2022-08-10 day27 第一小组 王鸣赫

注解和反射

反射

反射的概念

什么是反射
反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

每个类都有一个自身的 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。

反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。

Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用 private 方法);
在运行时调用任意一个对象的方法

反射的优点

可扩展性:应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
类浏览器和可视化开发环境:一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
调试器和测试工具:调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。

反射的缺点

性能开销:反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

反射构造对象

点击查看代码
package cn.dioxide.cn;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class arraylist_t {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得一个class类对象  
        Class c1 = Class.forName("cn.dioxide.cn.User");
        User user = (User) c1.newInstance(); //调用类的无参构造器  
        System.out.println(user);

        //通过构造器创建对象  
        Constructor con = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User) con.newInstance("李四", 001, 18);
        System.out.println(user2);

        //通过反射调用普通方法  
        User user3 = (User) c1.newInstance();
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user3, "张三"); //invoke方法激活:("方法名", "对象值")  
        System.out.println(user3.getName());

        //通过反射操作属性  
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true); //绕过private保护  
        name.set(user4, "王五");
        System.out.println(user4.getName());
    }
}

反射与注解

点击查看代码
package cn.dioxide.cn;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class arraylist_t {
    //普通构造器	  19ms
    public static void demo1() {
        User u1 = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            u1.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cost time: " + (endTime - startTime) + "ms");
    }
    //反射构造器	  2183ms
    public static void demo2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User u1 = new User();
        Class c1 = u1.getClass();
        Method getname = c1.getDeclaredMethod("getName", null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getname.invoke(u1, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cost time: " + (endTime - startTime) + "ms");
    }
    //反射构造器 权限越级	1138ms
    public static void demo3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User u1 = new User();
        Class c1 = u1.getClass();
        Method getname = c1.getDeclaredMethod("getName", null);
        getname.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getname.invoke(u1, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cost time: " + (endTime - startTime) + "ms");
    }
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        demo1();
        demo2();
        demo3();
    }
}

反射操作泛型

ava采用泛型擦除的机制来引入泛型,Java中的泛型静静是给编译器javac使用的,确保数据的安全性和免去强制转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除;
为了通过反射操作这些类型,Java新增了ParameterizedType, GenericArrayType, TypeVariable 和 WildcardType 几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型;
ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型;
TypeVariable:是各种类型变量的公共父接口;
WildcardType:代表一种通配符类型表达式;

点击查看代码
package cn.dioxide.cn;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class arraylist_t {
    //反射解析泛型  
    public static void demo1(Map < String, User > map, List < User > list) {
        System.out.println("test01");
        return;
    }
    public Map < String, User > demo2() {
        System.out.println("test02");
        return null;
    }
    public static void main(String[] args) throws NoSuchMethodException {
        Method method = arraylist_t.class.getMethod("demo1", Map.class, List.class);
        //参数化类型  
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType: genericParameterTypes) {
            System.out.println("#" + genericParameterType);
            if (genericParameterType instanceof ParameterizedType) {
                //获得参数类型  
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument: actualTypeArguments) {
                    System.out.println("demo1 " + actualTypeArgument);
                }
            }
        }
        method = arraylist_t.class.getMethod("demo2", null);
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            //判断参数类型  
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument: actualTypeArguments) {
                System.out.println("demo2 " + actualTypeArgument);
            }
        }
    }
}

反射操作注解

点击查看代码
package cn.dioxide.cn;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class arraylist_t {
    //反射操作注解  
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("cn.dioxide.cn.student");
        //通过反射获得注解类  
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation: annotations) {
            System.out.println(annotation);
        }
        //获得注解的value值  
        Dioxide dioxide = (Dioxide) c1.getAnnotation(Dioxide.class);
        String value = dioxide.value();
        System.out.println(value);
        //获得类指定的注解  
        Field f = c1.getDeclaredField("name");
        FieldDioxide annotation = f.getAnnotation(FieldDioxide.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}

@Dioxide(value = "db_student")
class student {
    @FieldDioxide(columnName = "db_id", type = "int", length = 10)
    private int id;
    @FieldDioxide(columnName = "db_age", type = "int", length = 10)
    private int age;
    @FieldDioxide(columnName = "db_name", type = "varchar", length = 10)
    private String name;

    public student() {}

    public student(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "student{" +
            "id=" + id +
            ", age=" + age +
            ", name='" + name + '\'' +
            '}';
    }
}
//类名注解  
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Dioxide {
    String value();
}
//属性注解  
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldDioxide {
    String columnName();
    String type();
    int length();
}

注解Annotation

什么是注解

Annotation是从JDK5.0开始引入的新技术。

Annotation的作用:

不是程序本身,可以对程序作出解释。(这一点和注释(comment)没有什么区别)
可以被其他程序(比如:编译器等)读取。
Annotation的格式:

注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:@SuppressWarnings(value=“unchecked”)。
Annotation在哪里使用:

可以附加在package,class,method,filed等上面,相当于给他们添加了额外的辅助信息,
我们可以通过反射机制编程实现对这些元数据的访问。

内置注解

@Override:定义在java.lang.Override中,此注解只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明。

@Deprecated:定义在java.lang.Deprecated中,此注解可以用于修饰方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为他很危险或者是存在更好的选择。

@SuppressWarning:定义在java.lang.SuppressWarning中,用来抑制编译时的警告信息。

他与前两个注解有所不同,你需要添加一些参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了。

@SuppressWarning(”all“)镇压全部
@SuppressWarning(”unchecked“)镇压危险
@SuppressWarning(value={”unchecked“,”deprecation“})还可以同时镇压多种
点击查看代码
//什么是注解
@SuppressWarnings("all")
public class Test01 extends Object {
   //Override 重写的注解
   @Override
   public String toString() {
      return super.toString();
   }

   //Deprecated  不推荐使用或者存在更好的方法,但是此方法也可以使用
   @Deprecated
   public static void test() {
      System.out.println("注解");
   }

   @SuppressWarnings("all")//使此方法中不出警报信息
   public static void test1() {
   }

   public static void main(String[] args) {
      //不建议使用,并不是不能使用
      test();
   }
}

元注解

元注解的作用就是负责注解其他注解,java定义了四个标准的meat-annotation类型,他们被用来提供对其他annotation类型做说明。
这些类型和它们所支持的类在java.lang. annotation中可以找到。

(@Target、@Retention、@Document、@Inherited)
@Target :用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
@Document:说明该注解将被包含在javaDoc中 文档中
@Inherited:说明子类可以继承父类中的该注解
点击查看代码
//元注解
   @MyAnnotation
public class Test02 {

   public void test(){
      
   }

}

//Target表示我们的注解需要使用到什么地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})

//表示我们的注解在什么地方还有效
//runtime>class>source
//runtime>class>source
//runtime运行时有效
//class 编译成class文件使有效
//source 在源码是有效
@Retention(value = RetentionPolicy.RUNTIME)

//表示是否将我们的注解生成到javadoc中 文档中
@Documented

//子类可以继承父类的注解
@Inherited
@interface MyAnnotation{

}

自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
分析:
@interface用来声明一个注解,格式:public @interface 注解名 {定义内容}
其中的每一个方法实际上是声明了一个配置参数。
方法的名称就是参数的名称。
返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)。、
可以通过default来声明参数的默认值
如果只有一个参数成员,一般参数名为value
注解元素必须要有值,我们定义注解元素时, 经常使用空字符串,0作为默认值

点击查看代码
//自定义注解
public class Test03 {
   //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
   @MyAnnotation2(name = "zz",schools = {"北京","菜鸟"})
   public void test(){}
   @MyAnnotation3("小明")//当参数名为value的时候可以直接写参数,
   public void test2(){}
}
//可以作用在类上和方法上
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
   //注解的参数:参数类型 + 参数名 +()
   String name() default "";//设置参数,也可以定义一个默认值用default
   int age() default 0;
   int id() default -1;//如果默认值为-1,代表不存在,indexof,如果找不到就返回-1
   String[] schools() default {"清华","北大"} ;
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
   String value();  //一个注解中只有一个参数的时候推荐使用value作为参数名
}

posted @ 2022-08-11 19:56  404notfond  阅读(15)  评论(0)    收藏  举报