注解和反射

1、注解

注解(Annotation)

  • 作用
    • 可以对程序作出解释(和注释(comment)相同)
    • 可以被其他程序读取(编译器等)
  • 格式:@注释名,还可以添加一些参数值
    • eg:@SuppressWarnings(value="unchecked")
  • 使用范围:package、class、method、field等,可以通过反射机制编程实现对这些元数据的访问

1.1、内置注解

  • @Override:重写注解
  • @Deprecated:不鼓励使用的属性、类(通常是危险的或者有更好的选择)
  • @SuppressWarnings:抑制编译时的警告信息(需要添加一个参数才能正常使用)
    • @SuppressWarnings("all")
    • @SuppressWarnings("unchecked")
    • @SuppressWarnings(value={"unchecked","deprecation})

1.2、元注解

负责注解其他注解

  • java的4个标准元注解(meta-annotation)
    • @Target:描述注解的使用范围
    • @Retention:表示需要在什么级别保存注解信息,用于描述注解的生命周期(SOURCE(源码时有效)<CLASS(class文件有效)<RUNTIME(运行时有效)(一般定义为RUNTIME))
    • @Documented:该直接将被包含到javadoc中(生成文档注释)
    • @Inherited:子类可以继承父类中的注解

1.3、自定义注解

@interface 注解名{定义内容}

每个方法实际上是声明了一个配置参数

方法的名称就是参数的名称

返回值类型就是参数的类型(返回值只能是基本类型Class、String、enum)

可以通过default来声明参数的默认值,没有默认值使用时必须给注解赋值

如果只有一个参数成员,一般参数名为value

注解元素必须要有值

public class Demo01 {
    @Annotation(age=18)
    public void text(){

    }
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation{
    String name() default "";
    int age();
}

2、反射

2.1、反射对象

Class类

一个类在内存中只有一个Class对象

一个类被加载后,类的整个结构都会被封装在Class对象中

获得Class对象

Person person = new Person();
//通过对象获得
Class c1 = person.getClass();
//forname获得,需要抛出异常
Class c2 = Class.forName("路径名");
//通过类名获得
Class c3 = Person.class;
//基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;

2.2、类的初始化

  • 类的主动引用(一定会发生类的初始化)

    • main方法
    • new一个类
    • 静态成员和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 初始化类时父类没有被初始化则先初始化父类
  • 类的被动引用(不会发生类的初始化)

    • 访问静态域时,只有真正声明这个域的类才会初始化(通过子类引用父类的静态变量不会导致子类初始化)
    • 通过数组定义类的引用,不会触发此类的初始化
    • 引用常量不会触发此类的初始化

2.3、类加载器

public static void main(String[] args) throws ClassNotFoundException {
        //获得系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
    
        //获得系统类加载器的父类加载器(拓展类加载器)
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
    
        //获得拓展类加载器的父类加载器(根加载器,无法直接获取)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
    
        //获得指定类是由那个加载器加载的
        ClassLoader classLoader = Class.forName("路径").getClassLoader();
        System.out.println(classLoader);
    
        //获得类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
}

2.4、类的结构

public static void main(String[] args) throws ClassNotFoundException {
        Class<?> aClass = Class.forName("路径");
    
        //获得类名
        System.out.println(aClass.getName());//类名+包名
        System.out.println(aClass.getSimpleName());//类名
    
        //获得类的属性
        Field[] fields = aClass.getFields();//只能获得public属性
        for (Field field : fields) {
            System.out.println(field);
        }
        Field[] declaredFields = aClass.getDeclaredFields();//能获得所有属性
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    
        //获得类的方法
        Method[] methods = aClass.getMethods();//本类及父类所有的public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        Method[] declaredMethods = aClass.getDeclaredMethods();//本类的所有方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    
        //获得构造器
        Constructor<?>[] constructors = aClass.getConstructors();//本类及父类所有的public构造器
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();//本类的构造器
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
}

【通过反射来创建对象】

public class Demo04 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得class对象
        Class<?> aClass = Class.forName("com.mixian.opp.Demo03");
        
        //创建对象
        Object o = aClass.newInstance();
        System.out.println(o);
        
        //通过构造器创建对象
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class);
        Object mixian = declaredConstructor.newInstance("mixian");
        System.out.println(mixian);
        
        //通过反射调用方法
        Method setName = aClass.getDeclaredMethod("setName", String.class);
        setName.invoke(o,"mixian");//激活
        
        //通过反射操作属性
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);//私有属性不能直接操作,需要关闭程序的安全监测
        name.set(o,"mixian");
    }
}

【通过反射获得注解】

public class Demo06 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.mixian.opp.Student");
        //通过反射获得注解
        AnnotatedType[] annotatedInterfaces = aClass.getAnnotatedInterfaces();
        for (AnnotatedType annotatedInterface : annotatedInterfaces) {
            System.out.println(annotatedInterface);
        }
        //获得类value的值
        xian annotation = aClass.getAnnotation(xian.class);
        String value = annotation.value();
        System.out.println(value);
        //获得类指定的注解
        Field age = aClass.getDeclaredField("age");
        xian annotation1 = age.getAnnotation(xian.class);
        System.out.println(annotation1.value());
    }
}
@xian("xian")
class Student{
    @xian("xian")
    private String name;
    @xian("xian")
    private int age;
}
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface xian{
    String value();
}

posted @ 2022-08-23 17:02  深巷の猫  阅读(49)  评论(0)    收藏  举报