注解与反射

84 阅读5分钟

注解

注解分为三类

  • 内置注解 @Override @Deprecated @SuppressWarnings
  • 元注解 @Target @Documented @Retention @Inherited 等等
  • 自定义注解

元注解

@Target

表示在什么地方使用该注解

  • ElementType.METHOD 作用于方法上
  • ElementType.TYPE 作用于class上
  • ElementType.FILED 作用于字段上
  • ...

@Retention

表示什么时候该注解会有效

  • RetentionPolicy.SOURCE (源码)
  • RetentionPolicy.CLASS (编译阶段)
  • RetentionPolicy.RUNTIME (运行时)
  • 注:RUNTIME > CLASS > SOURCE,选择了RUNTIME,那么CLASS、SOURCE都支持,一般情况下都是RUNTIME

@Documented @Inherited

  • @Documented 表示将该注解生成到Java Doc中
  • @Inherited 表示子类可以继承父类的注解

自定义注解

定义一个简单的注解

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface SimpleAnnotation {
}

定义一个复杂的注解

情况1: 当只有一个参数时,需要把参数名定义为value,这样在使用该注解时可以直接写参数值

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface OneParamAnnotation {
    String value();
}

@OneParamAnnotation("Kieran")
public class Test {
}

情况2:多个参数,可以设置默认值

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface HardAnnotation {
    String name() default "";
    int age() default 0;
    int id() default -1; // -1表示该参数不存在
    String[] colors() default {"white","blue"};
}

@HardAnnotation(name = "kieran", id = "75", colors = {"red","green","yellow"})
public class Test {
}

反射

  1. 一个类在内存中只有一个类的class对象
  2. 一个类被加载后,类的整个结构都会被封装在class对象中
  3. 在java中类是获取的,不是创建的
  4. 获得class的几种方式
  • A a = new A(); Class<?> c1 = a.getClass();
  • Class<?> c2 = Class.forName("com.xxxxxx.reflection.demo.A);
  • Class<?> c3 = A.class;
  • Class<Integer> c4 = Integer.TYPE;
Person person = new Student();
System.err.println(person.name);
System.err.println("-----");

// 方式一:通过对象获取
Class<? extends Person> c1 = person.getClass();
System.err.println(c1);
System.err.println(c1.hashCode());
System.err.println("-----");

// 方式二: forName获取
Class<?> c2 = Class.forName("com.shinefriends.juc.reflection.Student");
System.err.println(c2);
System.err.println(c2.hashCode());
System.err.println("-----");

// 方式三:通过类名.class获取
Class<Student> c3 = Student.class;
System.err.println(c3);
System.err.println(c3.hashCode());
System.err.println("-----");

// 方式四:基本内置类型的包装类都有一个TYPE属性
Class<Integer> c4 = Integer.TYPE;
System.err.println(c4);
System.err.println(c4.hashCode());
System.err.println("-----");

// 获取父类类型
Class<?> s1 = c1.getSuperclass();
System.err.println(s1);
System.err.println(s1.hashCode());
System.err.println("-----");

Class<?> s2 = c2.getSuperclass();
System.err.println(s2);
System.err.println(s2.hashCode());
System.err.println("-----");

Class<? super Student> s3 = c3.getSuperclass();
System.err.println(s3);
System.err.println(s3.hashCode());
System.err.println("-----");

// superClass与new Class()不一样
Person p = new Person();
System.err.println(p);
System.err.println(p.hashCode());
System.err.println("-----");

5. 所有类型的class

  • Class c1 = Object.class; // 类
  • Class c2 = Serializable.class; // 接口
  • Class c3 = ElementType.class; // 枚举
  • Class c4 = Integer.class; // 基本数据类型
  • Class c5 = String[].class; // 一维数组
  • Class c6 = int[][].class; // 二维数组
  • Class c7 = void.class; // void
  • Class c8 = override.class; // 注解
  • Class c9 = Class.class; // class
  1. 只要类型相同和维度相同,就是同一个class
int[] i1 = new int[10];
int[] i2 = new int[100];

i1.getClass().hashCode() 等于 i2.getClass().hashCode();

7. 测试类什么时候会被加载(类的加载分为主动和被动)

/**
 * 测试类什么时候会初始化
 */
public class Demo5 {
    static {
        System.err.println("main类被加载");
    }

    public static void main(String[] args) throws ClassNotFoundException {
        // 1.主动引用
//        Son son = new Son();

        // 1.主动引用 - 反射也会产生主动引用
//        Class son = Class.forName("com.shinefriends.juc.reflection.Son");


        // 2.被动引用 - 不会发生类的初始化 调用父类的静态变量
//        System.err.println(Son.b);

        // 2.被动引用 - 初始化数组也不会发生类的初始化 - 此处也不会加载父类,只是给空间命名了,并不会加载一个类
//        Son[] son = new Son[5];

        // 2.被动引用 - 常量,也不会发生类的初始化
        System.err.println(Son.M);
    }
}

class Father {
    static int b = 2;
    static {
        System.err.println("父类被加载");
    }
}

class Son extends Father {
    static {
        System.err.println("子类被加载");
        index = 300;
    }

    static int index = 100;

    static final int M = 1;
}

类加载器

  1. 由父类到子类的三个类加载器
  • 引导类加载器(根加载器) rt.jar
  • 扩展类加载器 ext
  • 系统类加载器
  1. 获取三个类加载器
  • ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
  • ClassLoader extClassLoader = systemClassLoader.getParent();
  • ClassLoader rootClassLoader = extClassLoader.getParent();
  • 根加载器说明:由于根加载器是由c/c++编写的,因此获取不到,输出为null
  • 系统加载器说:输出时AppClassLoader和SystemClassLoader是同一个东西
  1. 如何获取系统类加载可以加载的路径
  • System.getProperty("java.class.path");

双亲委派机制

  1. 比如自己定义了一个 java.lang.String,系统会保证安全性,先到系统类加载器中寻找类String,找不到再到扩展类加载器寻找类String,找不到最后到引导类加载器寻找leiString。如果找到了,则会使用找到的类。
  2. 1.避免了类的重复加载 2.保护了程序的安全性,防止核心API被修改

动态创建对象,通过反射,设置属性

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

/**
 * 动态创建对象,通过反射
 */
public class Demo8 {
    public static void main(String[] args) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class c1 = Class.forName("com.shinefriends.juc.reflection.User");

        // 创建个对象,本质是调用了一个无参构造器
        User u1 = (User) c1.newInstance();
        System.err.println(u1);

        // 通过构造器,创建一个对象
        User u2 = (User) c1.getDeclaredConstructor(String.class, int.class, int.class).newInstance("pyc", 10, 50);
        System.err.println(u2);

        // 通过反射获取方法,invoke激活
        Method method = c1.getDeclaredMethod("setName", String.class);
        method.invoke(u2, "kieran");
        System.err.println(u2);

        // 通过反射操作属性,不能直接操作私有属性
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true); // 因为是name是private修饰的,因此需要把操作权限打开
        name.set(u2, "基兰");
        System.err.println(u2);
    }
}

获取类中的各种信息

public class Demo {
    psvm {
       Class c = Class.forName("com.xxx.User");
       
       // 获取类的名字
       c.getName(); // com.xxx.User
       c.getSimpleName(); // User
      
       // 获取类的字段,只能获取到public
       Field[] fields = c.getFields();
       
       // 获取类的所有字段,包括private
       Field[] fields = c.getDeclaredFields();
       
       // 获取类的方法,本类及父类的所有public方法
       Method[] methods = c.getMethods();
 
       // 获取类的所有方法,包括private
       Method[] methods = c.getDeclaredMethods();
     
       // 获取类的指定方法
       Method method = c.getMethod("getName", null);
       Method method = c.getMethod("setName", String.class);
       
       // 获取类的默认无参构造器
       Constructor constructor = c.getConstructor();
       
       // 获取类的全部公有构造器
       Constructor[] constructors = c.getConstructors();
       
       // 获取类的全部构造器,包含私有
       Constructor[] constructors = c.getDeclaredConstructors();
       
       // 获取类的指定构造器
       Constructor constructor = c.getConstructor(String.class, int.class, int.class);
    
    }
}

获取泛型

public class Demo10 {

    public void test1(Map<String, User> map, List<User> list) {
        System.err.println("test1");
    }

    public Map<String, User> test2() {
        System.err.println("test2");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method test1 = Demo10.class.getMethod("test1", Map.class, List.class);

        Type[] genericParameterTypes = test1.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.err.println("#" + genericParameterType);
            if (genericParameterType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.err.println("##" + actualTypeArgument);
                }
            }
        }

        Method test2 = Demo10.class.getMethod("test2", null);
        Class returnType = test2.getReturnType();
        System.err.println(returnType);

        Type genericReturnType = test2.getGenericReturnType();
        System.err.println(genericReturnType);
        if (genericReturnType instanceof ParameterizedType) {
            for (Type actualTypeArgument : ((ParameterizedType) genericReturnType).getActualTypeArguments()) {
                System.err.println("#" + actualTypeArgument);
            }

        }
    }
}

获取注解

public class Demo11 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.shinefriends.juc.reflection.Air");
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.err.println(annotation);
        }

        AirAnno airAnno = (AirAnno) c1.getAnnotation(AirAnno.class);
        String value =airAnno.value();
        System.err.println(value);

        System.err.println("============");
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            Annotation[] fa = field.getAnnotations();
            for (Annotation annotation : fa) {
                System.err.println(annotation);
            }

            AirField airField = field.getAnnotation(AirField.class);
            System.err.println(airField.columnName() + " - " + airField.type() + " - " + airField.length());

        }
    }
}

@AirAnno(value = "sweet")
class Air {
    @AirField(columnName = "id", type = "integer", length = 10)
    private int id;

    @AirField(columnName = "age", type = "integer", length = 5)
    private int age;

    @AirField(columnName = "name", type = "varchar", length = 20)
    private String name;

    public Air() {

    }

    public Air(int id, int age, String 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 "Air{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + ''' +
                '}';
    }
}

@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface AirAnno {
    String value();
}

@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface AirField {
    String columnName();
    String type();
    int length();
}