Java 反射、注解

79 阅读4分钟

反射

什么是反射
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法、构造函数
对于任意一个对象,都能够调用它的任意一个方法和属性;
这个动态获取的信息以及动态调用对象的方法的功能成为Java语言的反射机制。

反射有什么用
反射 当一个字节码加载到内存的时候,jvm会对字节码进行解析,然后会创建与i个Class对象把所有的信息存储到Class对象中,我们就可以对对象设置或者调用方法和属性。
在运行时构造任意一个类的对象
在运行时调用任意一个对象的方法(属性)
在运行时获取任意一个类所具有的成员变量和方法。

Class类
Class类是Java语言中定义一个特定类的实现,一个类的定义包含成员变量,成员方法,还有这个类实现的接口,以及这个类的父类。
Class类的对象用于表示当前运行的Java应用程序中的类和接口。

获取Class对象的三种方式

  1、通过类名获取            类名.class        该方法无法加载类
Class<Demo1> clazz = Demo1.class;
2、通过对象获取        对象名.getClass()  该方式获取的反射类是未知的泛型类,不能指定对应泛型
Demo1 demo1 = new Demo1();
Class<?> clazz = demo1.getClass();
```java
//3、通过全类名获取  Class.forName(全类名) 该方法可以加载类,就是可以加载静态内容(重点!!!!!)  
Class<?> clazz = Class.forName("com.xxx.fanshe.Demo1");
public class Demo1 implements Serializable {
    private String name;
    private int age;
    public void eat(){
        System.out.println("吃了");
    }
    public void waiting(){
        System.out.println("等待");
    }

    public Demo1(String name){}
    public Demo1(){}


    @Override
    public String toString() {
        return "Demo1{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    static {
        System.out.println("静态代码块");
    }
    {
        System.out.println("构造代码");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        //反射
//        1、通过类名获取            类名.class        该方法无法加载类
//        Class<Demo1> clazz = Demo1.class;
//        2、通过对象获取        对象名.getClass()  该方式获取的反射类是未知的泛型类,不能指定对应泛型
//        Demo1 demo1 = new Demo1();
//        Class<?> clazz = demo1.getClass();
        //3、通过全类名获取  Class.forName(全类名) 该方法可以加载类,就是可以加载静态内容(重点!!!!!)
        try {
            Class<?> clazz = Class.forName("com.xxx.fanshe.Demo1");
            //取得所有属性,包括私有属性
            Field[] fields = clazz.getDeclaredFields();
            //clazz.getFields() 会受到访问修饰符的影响
            for (Field field: fields) {
                System.out.println(field);
            }
            
            //通过属性名获取属性
            Field age = clazz.getDeclaredField("age");
            System.out.println(age);
            
            //获取父类   获取父类的属性、方法
            Class<?> superclass = clazz.getSuperclass();
            System.out.println(superclass);

            //获取接口
            Class<?>[] interfaces = clazz.getInterfaces();
            for (Class class1: interfaces) {
                System.out.println(class1);
            }

            //获取方法
            Method[] ms = clazz.getDeclaredMethods();
            for (Method method: ms) {
                System.out.println(method);
            }

            //获取单个方法
            Method eat = clazz.getDeclaredMethod("eat");
            System.out.println(eat);
            
            
            //获取构造方法
            Constructor<?>[] aa = clazz.getDeclaredConstructors();
            for (Constructor constructor: aa) {
                System.out.println(constructor);
            }

            //通过特定的参数类型获取对应的构造方法
            Constructor<?> ca = clazz.getDeclaredConstructor(String.class);
            System.out.println(ca);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        try {
            Demo1 demo1 = new Demo1();
            Class d2= demo1.getClass();
            Field age = d2.getDeclaredField("age");
            age.setAccessible(true);
            age.set(demo1,11);
            String s = age.get(demo1).toString();
            System.out.println(s);
            System.out.println(demo1);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }

}

public class A implements Serializable {
    private String name;
    private int age;
    private void eat(){
        System.out.println("吃了");
    }
    public void waiting(){
        System.out.println("等待");
    }

    public A(String name){}
    private A(){}


    @Override
    public String toString() {
        return "Demo1{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    static {
        System.out.println("静态代码块");
    }
    {
        System.out.println("构造代码");
    }
}
public class TestA {
    public static void main(String[] args) {
        try {
            Class<A> zla = A.class;
            Constructor<A> structor = zla.getDeclaredConstructor();
            //再次设置无视修饰符
            structor.setAccessible(true);
            //调用该反射出来的构造方法,实例化  newInstance 调用实例化步骤
            A b = structor.newInstance();
            System.out.println(b);

            Method eat = zla.getDeclaredMethod("eat");
            eat.setAccessible(true);
            //invoke通过实体类,调用该实体类的方法
            eat.invoke(b);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

注解

注释是对源代码作介绍或说明的文字 注解的定义:Java文件叫做Annotation(元数据),用@interface表示,即一种描述数据的数据元注解(系统自带的注解):@interface上面按选哟注解上一些东西,包括@Retention、@Target、@Document、@inherited四种

注解的保留策略: image.png

注解的作用目标:

image.png @inherited注解--在注解类里面加入
注解可以被继承--实体类子类没有该注解,父类有注解,那么子类也会拥有该注解

//创建了一个注解

@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
//注解会在class字节码文件中存在,在运行时可以通过反射获取到。
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    //value是注解的特殊属性,使用个注解的时候,默认不填名称直接赋值,默认的赋值是value
    //注解的属性     default表示该属性的默认值,就是别的类使用这个属性的时候,不声明默认就是该值。
    String value() default "你";
}
@MyAnnotation("hello")
public class Demo1 {
    @MyAnnotation("lalala")
    private String name;

    @MyAnnotation
    private void eat(){
        System.out.println("hh");
    }
    public static void main(String[] args) {

        try {
            Class<Demo1> clz = Demo1.class;
            //获取类的注解
            MyAnnotation c = clz.getDeclaredAnnotation(MyAnnotation.class);
            System.out.println(c.value());

            //获取属性上的注解
            Field fiel = clz.getDeclaredField("name");
            MyAnnotation c2 = fiel.getDeclaredAnnotation(MyAnnotation.class);
            System.out.println(c2.value());

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return super.toString();
    }
}