JavaDay19-动态代理、反射、注解

一、动态代理

1.1 代理的基本概念

1、代理可以无侵入式的给对象增强其他的功能
2、代理里面是对象需要被代理的方法
3、对象和代理需要实现同一个接口,接口中是被代理的所有方法

//动态代理--测试类
public class Test {
    public static void main(String[] args) {
        Star star = new Star("鸡哥");
        StarProxy starProxy = ProxyUtil.CreatProxy(star);
        String s = starProxy.Sing("只因你太美");
        System.out.println(s);
    }
}
//被代理的对象
public class Star implements StarProxy{
    private String name;
    public Star() {
    }

    public Star(String name) {
        this.name = name;
    }
    //被代理的方法之一:唱歌
    @Override
    public String Sing(String name){
        System.out.println(this.name+"正在唱"+name+"...");
        return "谢谢";
    }
    //被代理的方法:跳舞
    @Override
    public void Dance(){
        System.out.println(this.name+"正在跳舞...");
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "Star{name = " + name + "}";
    }
}
//被代理的对象中的方法
public interface StarProxy {
    //被代理的方法之一:唱歌
    public abstract String Sing(String name);
    //被代理的方法:跳舞
    public abstract void Dance();

}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 类的作用:
 *        创建代理,代理star对象中的方法,方法放在了StarProxy这个接口中
 */
public class ProxyUtil {
    /**
     * 方法的作用:
     *      创建Star对象的代理
     * 形参:
     *      Star对象
     * 返回值:
     *      给明星创建的代理--Star对象的接口
     */
    public static StarProxy CreatProxy(Star star){

        /*
        java.long.reflect.Proxy类提供了为对象产生代理对象的方法:
        public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        参数一:指定类加载器,加载生成的代理类
        参数二:接口数组,需要代理的方法
        参数三:指定生成的代理要干什么事情
         */
        StarProxy starp = (StarProxy) java.lang.reflect.Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//使用当前字节码文件的类加载器,将代理对象加载到内存中
                new Class[]{StarProxy.class},//将所有需要代理的方法的字节码文件放到字节码文件数组中
                new InvocationHandler(){//代理需要做的事情
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /**
                         * 参数一:代理的对象
                         * 参数二:要运行的方法
                         * 参数三:调用要运行的方法时,要传递的实参
                         */
                        if ("Sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if("Dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");
                        }
                        return method.invoke(star,args);
                    }
                });
        return starp;
    }
}

1.2 实现动态代理的步骤总结:

1、创建JavaBean类,这个类就是需要被代理的对象,需要实现代理接口
2、创建代理接口,里面是需要被代理的方法
3、创建代理类,

  • 代理类中只定义了一个方法:createProxy(),
  • 此方法的参数是需要被代理的对象(即1中创建的JavaBean类)
  • 返回值是代理接口
    • createProxy()内部的主体逻辑是:
      • 调用Proxy.newProxyInstance()方法
      • 返回代理接口的对象

4、Proxy.newProxyInstance()方法的三个参数:

  • 参数一:类加载器--代理类的类加载器
  • 参数二:代理接口的字节码文件(数组)
  • 参数三:InvocationHandler接口的实现类对象
    • 需要重写接口的invoke方法,
    • 方法内有三个参数,不需要修改,但要知道什么意思,
      • 参数一:代理的对象,即创建的JavaBean类
      • 参数二:代理接口中的方法
      • 参数三:代理接口中的方法需要传递的参数
    • 方法体是代理类需要做的事,
    • 返回值是JavaBean对象中被代理的方法的返回值。(此例中是bigStar中Sing的返回值)。

Proxy.newProxyInstance()方法的返回值是代理接口的对象。

5、创建测试类:

  • 第一步:创建JavaBean对象
  • 第二步:创建代理--调用创建代理的方法
  • 第三步:通过代理调用JavaBean对象的方法

二、反射

2.1 概念

反射允许对成员变量、成员方法、构造方法的所有信息进行访问

2.2 如何通过反射获取上述信息

  • 获取
    • class对象--->成员变量Field、成员方法Method、构造方法Constructor
  • 解剖
    • 成员变量>>>修饰符、名字、类型>>>赋值/获取值
    • 成员方法>>>修饰符、名字、形参、抛出的异常、注解、方法体>>>获取返回值
    • 构造方法>>>修饰符、名字、形参>>>创建对象

2.3 获取class对象的三种方法

  • Class.forName()------源代码阶段:编写.java文件
  • 类名.class()------加载阶段:将.class文件加载到内存
  • 对象.getClass()------运行阶段:在内存中创建对象
//练习获取class对象的三种方法
public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        Student student = new Student();
        //第一种方式:Class.forName(全类名=包名+类名)
        //最常用
        Class class1 = Class.forName("reflectionDemo01.Student");
        System.out.println(class1);
        //第二种方式:类名.class
        //一般当做参数进行传递
        Class class2 = Student.class;
        System.out.println(class2);
        //第三种方式:对象名.class
        //当已经有了对象时才可以使用
        Class class3 = student.getClass();
        System.out.println(class3);
    }
}
public class Student {
    private String name;
    private int age;
    public Student() {
    }

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

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

2.4 通过获取的class对象获取构造方法

  • 获取public修饰的构造方法--getConstructors()
  • 获取所有构造方法--getDeclaredConstructors()
  • 获取某一个构造方法(参数一致即可)--getConstructor(String.class)、getDeclaredConstructor(int.class)
    通过class对象获取了构造方法以后,可以:
    • 获取构造方法的权限修饰符--getModifiers()
    • 获取构造方法的参数--getParameters()
    • 创建对象--newInstance()、setAccessible(true)

2.5 通过获取的class对象获取成员变量

  • 获取所有public修饰的成员变量--getFields()

  • 获取所有的成员变量--getDeclaredFields()

  • 获取单个成员变量--getField("name")、getDeclaredField("name")

    通过class对象获取了成员变量以后,可以:

    • 获取成员变量的权限修饰符--getModifiers()
    • 获取成员变量名--getName()
    • 获取成员变量的数据类型--getType()
    • 获取成员变量记录的值--get(对象)
    • 修改变量记录的值--set(对象,"需要修改的值")

2.6 通过获取的class对象获取成员方法

  • 获取所有public修饰的成员方法--getMethods()

  • 获取所有的成员方法--getDeclaredMethods()

  • 获取单个成员方法--getMethods("方法名",参数类型)、getDeclaredMethods("方法名",参数类型)

    通过class对象获取了成员方法以后,可以:

    • 获取成员方法的权限修饰符--getModifiers()
    • 获取成员方法的名字--getName()
    • 获取成员方法的参数--getParameters()
    • 获取成员方法抛出的异常--getExceptionTypes()
    • 运行获取出来的方法--invoke(对象,方法实参)
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
//通过获取的class对象获取构造方法
public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class stuClass = Class.forName("reflectionDemo02.Student");
        //获取所有public的构造
        Constructor[] cons = stuClass.getConstructors();
        System.out.println("所有public的构造方法:");
        for (Constructor con : cons) {
            System.out.println(con);
        }
        System.out.println("============================================================");
        //获取所有构造
        Constructor[] cons1 = stuClass.getDeclaredConstructors();
        System.out.println("所有的构造方法(包括private、protected):");
        for (Constructor constructor : cons1) {
            System.out.println(constructor);
        }
        System.out.println("============================================================");
        //获取某一个构造,参数类型要与构造一致
        Constructor consString = stuClass.getConstructor(String.class);
        System.out.println("参数为String name的构造方法:");
        System.out.println(consString);
        System.out.println("============================================================");
        //getDeclaredConstructor此方法获取的私有构造只能看 不能创建对象 必须setAccessible(true)
        Constructor consInt = stuClass.getDeclaredConstructor(int.class);
        System.out.println("参数为Int age的构造方法:");
        System.out.println(consInt);
        System.out.println("============================================================");
        //获取构造方法的权限修饰符
        int modifiers = consInt.getModifiers();
        System.out.println("参数为Int age的构造方法的权限修饰符编号:");
        System.out.println(modifiers);//返回权限修饰符对应的数字
        System.out.println("============================================================");
        //获取构造方法的参数
        Parameter[] parameters = consInt.getParameters();
        System.out.println("参数为Int age的构造方法的参数:");
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        System.out.println("============================================================");
        //通过获取的构造方法创建对象--构造方法权限为public
        Student stu1 = (Student) consString.newInstance("小刘");
        System.out.println("用public修饰的构造方法创建对象:");
        System.out.println(stu1);
        System.out.println("============================================================");
        //通过获取的构造方法创建对象--构造方法权限为private
        consInt.setAccessible(true);//临时取消私有权限  暴力反射
        Student stu2 = (Student) consInt.newInstance(18);
        System.out.println("用private修饰的构造方法创建对象:");
        System.out.println(stu2);
    }
}
import java.lang.reflect.Field;
//通过获取的class对象获取成员变量
public class Demo03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Class<?> stuClass = Class.forName("reflectionDemo02.Student");
        Field[] fields = stuClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        Field[] declaredFields = stuClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        Field name = stuClass.getDeclaredField("name");
        System.out.println(name);
        System.out.println(name.getModifiers());
        System.out.println(name.getName());//获取变量的名字
        System.out.println(name.getType());//获取变量的数据类型
        //获取变量中存储的值
        Student s = new Student("zhangsa", 28);
        name.setAccessible(true);
        System.out.println(name.get(s));//输出:zhangsa
        name.set(s,"lisi");//修改name中存储的值
        System.out.println(s);
    }
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
//通过获取的class对象获取成员方法
public class Demo04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?> clazz = Class.forName("reflectionDemo02.Student");
        Method[] methods = clazz.getMethods();//同时能够获得父类中所有的公共方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("========================================================");
        Method[] methods2 = clazz.getDeclaredMethods();//不能获取父类的,但能获取本类中私有的方法
        for (Method method : methods2) {
            System.out.println(method);
        }
        System.out.println("========================================================");
        Method eat = clazz.getDeclaredMethod("eat", String.class);
        System.out.println(eat.getName());
        System.out.println(eat.getModifiers());
        Parameter[] parameters = eat.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        for (Class<?> exceptionType : eat.getExceptionTypes()) {
            System.out.println(exceptionType);
        }
        Student s = new Student();
        eat.setAccessible(true);
        eat.invoke(s,"螺蛳粉");//参数一:对象;参数二:实参
    }
}
public class Student {
    private String name;
    private int age;
//无参构造
    public Student() {
    }
//name构造
    public Student(String name) {
        this.name = name;
    }
//age构造
    private Student(int age) {
        this.age = age;
    }
//所有参数的构造
    protected Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
//sleep()
    public void sleep(){
        System.out.println("Sleeping...");
    }
//eat()
    private void eat(String something){
        System.out.println("Eating"+something);
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

三、注解 Annotation

3.1 内置注解

1、@Override--用于修饰方法,表示一个方法重写父类方法
2、@Deprecated--用于修饰方法、属性、类,表示不鼓励使用这样的元素,因为它很危险或者存在更好的选择
3、@SuppressWarning--用于抑制编译时的警告信息,需要添加参数(all、unchecked等)

3.2 元注解 meta-annotation

用于对其他注解做说明
1、@Target--用于描述注解的适用范围
2、@Retention--描述注解的生命周期(SOURCE<CLASS<RUNTIME)
3、@Document--说明该注解将被包含在javadoc中
4、@Inherited--说明该注解可以被子类继承

3.3 自定义注解

1、定义方式:@interface
2、书写方式

@Target({ElementType.METHOD})//表示该注解可以用在方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{
    String name() default "";//value是变量,不写的话默认是0
}

3、使用方式:

@MyAnnotation(name="wan")
posted @ 2023-04-17 18:13  小园初来乍到  阅读(35)  评论(0)    收藏  举报