Java-反射-注解-代理

144 阅读4分钟

一. 反射 Reflection

java是静态语言,但可以利用反射机制获得类似动态语言的特性

加载完类之后,在堆内存的方法区中就产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。

1.获取Class类的实例

a.若已知具体的类,通过类的class属性获取,(安全可靠,性能最高)

Class clazz = User.class;

b.已知某个类的实例,调用该实例的getClass()方法

Class clazz = user.getClass();

c.已知类的全类名,且该类在类路径下,通过Class的静态方法forName获取

Class c1 = Class.forName("com.wu.tong.reflection.User");

d.内置基本数据类型可以直接通过类名.Type

e.还可以利用ClassLoader

public class ReflectionDemo01 {

    /*
    * 反射 -> 将类的各个部分封装成其他对象
    * */
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, IOException {
        //三种获取类的方式
        //同一个字节码文件(.class)在一次程序运行过程中,只被加载一次,三种方式获取的class对象都是同一个
        Class c1azz = Class.forName("com.wu.tong.reflection.User");
        System.out.println(c1azz);
        Class  clazz01 = User.class;
        System.out.println(clazz01);
        User user = new User();
        Class clazz02 = user.getClass();
        System.out.println(clazz02);
        System.out.println(clazz02.getSuperclass());
        System.out.println("====================");
        Class userClass = User.class;
        //获取public成员变量
        Field[] fields = userClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //获取所有成员变量
        Field[] decFields = userClass.getDeclaredFields();
        for (Field field : decFields) {
            System.out.println(field);
        }
        //属性的获取和设值
        System.out.println("================");
        Field name = userClass.getDeclaredField("name");
        name.setAccessible(true);
        User user1 = new User();
        Object o = name.get(user1);
        System.out.println(o);
        System.out.println("=====================");
        Class cls = User.class;
        //构造函数
        Constructor constructor = cls.getConstructor(String.class, int.class, int.class);
        Object o1 = constructor.newInstance("zc",10010,21);
        System.out.println(o1);
        //Object o2 = constructor.newInstance();
        //System.out.println(o2);
        System.out.println(cls.newInstance());

        //获取方法
        User user3 = new User();
        Method setName = cls.getMethod("setName", String.class);
        Object invoke = setName.invoke(user3, "123");
        System.out.println(user3);

        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName());
        }
        //
        Properties prop = new Properties();
        ClassLoader classLoader = ReflectionDemo01.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        prop.load(is);
    }
}

class User{
    private String name;
    private int id;
    private int age;

    public User() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        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;
    }

    private String testDef(String str){
        return str+"abc";
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}
public class ReflectionDemo03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Class clazz = Class.forName("com.wu.tong.reflection.User");
        System.out.println(clazz.getSimpleName());

        //获取类属性
        //clazz.getFields() public属性
        Field[] fields = clazz.getDeclaredFields();//全部属性
        for (Field field : fields) {
            System.out.println(field);
        }

        Field name = clazz.getDeclaredField("name");
        System.out.println(name);


        System.out.println("+________________________");
        Method[] methods = clazz.getMethods();//获取本类和父类的全部public方法
        Method[] declaredMethods = clazz.getDeclaredMethods();//获取本类的所有方法
        for (Method method : declaredMethods) {
            System.out.println(method);
        }

        System.out.println("------------------");
        Method getName = clazz.getMethod("getName", null);
        Method setName = clazz.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        System.out.println("--------------");

        User user = (User) clazz.newInstance();
        setName.invoke(user,"abc");
        System.out.println(user.getName());

        Method testDef = clazz.getDeclaredMethod("testDef", String.class);
        testDef.setAccessible(true);
        Object invoke = testDef.invoke(user, "123");
        System.out.println(invoke);


    }
}

2. 获取类的完整结构

Field,Method,Constuctor都有setAccessiable()方法,启动和禁用访问安全检查的开关

3.获取泛型的信息

  获取注解

二.注解 Annotation

Annotation就是代码里的特殊标记,可以在编译、类加载、运行时被其他程序(编译器)读取,并执行相应的处理。

1.JDK内置基本注解

2.元注解:对现有注解进行解释说明的注解

@Retention - 指定修饰Annotation的是生命周期(SOURCE<CLASS<RUNTIME 只有声明为RUNTIME生命周期的注解才能通过反射操作)

@Target - 用于描述注解的使用范围

@Documented - 说明该注解将被包含在javadoc中

@Inhirited - 说明子类可以继承父类中的该注解

3.自定义注解

@Target({ElementType.TYPE,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnnotation02{

//注解的参数:参数+参数名()

String name() default "";

String[] schools() default {"西大","北大","南大"};

}

@MyAnnotation02(name = "lala")

public void test01(){

}

@Target({ElementType.TYPE,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnnotation03{

String value();

}

--如果只有一个参数,建议用value,可以省略key值

@MyAnnotation03("大大")

public void test02(){

}

三.动态代理 (基于反射)

1.代理

为其他对象提供一种代理已控制对这个对象的访问。(功能增强,控制访问)

2.静态代理

缺点:当目标类增加,代理类需要成倍的增加。当借口功能修改,影响过多的实现类。

3.动态代理

程序使用过程中,使用JDK的反射机制 ,创建代理类对象,并动态指定要代理的目标类

jdk动态代理(InvocationHander Method Proxy)

InvocationHandler接口,invoke方法,表示代理对象要执行的功能代码

Method:表示目标类中的方法

Proxy类:创建代理的对象

Cglib(Code Generation Library 原理是继承,通过继承目标类,创建它的子类,在子类中重写父类的同名方法,实现功能的修改)