千锋逆战班,学习了反射

学习Java的第52天,
明天的自己会感谢今天拼命的自己
今天学习了反射的类加载,类加载器,类反射机制,工厂模式,反射机制操作构造器,成员变量,成员函数,反射机制跳过泛型的限制,反射机制配置文件,静待代理设计模式

类加载

  • 概念:在class文件加载到jvm中时,会对应创建一个Class对象;分为三个步骤:加载、连接、初始化
  • 加载时机
    1.Class.forName(“com.mysql.jdbc.Driver”) : 将Driver类加载到jvm中的方法区
    2.初始化Fahter类的子类Son类:Father类也会加载,Son类会使用到Father类中的成员变量,Father类中成员变量就需要进行初始化,就需要将Father加载到内存,子类要调用父类的构造方法。

类加载器

  • 概念
    将class文件加载进内存,并生成对应的Class对象
  • 分类
    • 根类加载器
      • 加载java中的核心类,主要加载F:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar中的类
    • 扩展类加载器
      • 加载java中的扩展类,主要加载F:\Program Files\Java\jdk1.8.0_202\jre\lib\ext所有jar包中的类
    • 系统类加载器
      • 加载开发人员编写的自定义类、以及一些第三方的jar包中类

类的反射机制

  • 概念
    通过类的Class对象,动态去调用类中的属性和方法
  • 获取Class对象方式
    • 全类名=包名.类名
      • Class.forName(“全类名”)
    • 编译期
      • 类名.class
    • 运行时
      • 对象名.getClass()

反射结合工厂模式

  • 工厂模式的最大作用是创建类的对象,从而让模块和模块之间的耦合度也叫关联性降低,这样代码的拓展方便,
  • 反射在里面就是按照配置文件的内的类全限定名来创建哪一个类的对象

反射操作构造器

 //获取User类对应的Class对象
        Class<?> acl = Class.forName("com.qf.bean.User");
        //通过获取的Class对象获取无参构造方法
        Constructor<?> cl = acl.getConstructor();
        //通过无参构造方法创建对象
        Object o1 = cl.newInstance();
        System.out.println(o1);

        System.out.println("-------------------------------------");
        //获取User类对应的有参构造方法对象
        Constructor<?> constructor = acl.getConstructor(Integer.class, String.class, String.class);
        //使用有参创建User对象
        Object o2 = constructor.newInstance(2, "ww", "888");
        System.out.println(o2);

        //获取私有构造方法
        Constructor<?> declaredConstructor = acl.getDeclaredConstructor(String.class, String.class);
        //暴力反射
        declaredConstructor.setAccessible(true);
        Object o3 = declaredConstructor.newInstance("大大大", "555");
        System.out.println(o3);

反射操作成员变量

  //获取User类的Class对象
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        //操作public修饰的成员变量
        Field idField = userClass.getField("id");
        //设置该成员变量值
        //obj:需要设置的对象
        //value:需要设置的值
        //给user对象的id属性设置值为2
        idField.set(user,2);
        System.out.println(user);
        //获取该成员变量值
        Object idValues = idField.get(user);
        System.out.println(idValues);

        //操作非public修饰的成员变量
        Field username = userClass.getDeclaredField("username");
        //暴力反射
        username.setAccessible(true);
        username.set(user,"花花");

        System.out.println(user);

        Object o = username.get(user);
        System.out.println(o);

反射操作成员方法

//获取User的Class对象
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        //获取public成员方法
        Method setId = userClass.getMethod("setId", Integer.class);
        //使用方法对象
        //obj:哪个对象在执行该方法
        //args:方法执行时所需的参数值
        Object invoke = setId.invoke(user, 3);
        System.out.println(user);

        //获取非public成员方法
        Method setUsername = userClass.getDeclaredMethod("show");
        //暴力反射
        setUsername.setAccessible(true);
        Object value = setUsername.invoke(user);
        System.out.println(value);
        System.out.println(user);
    

反射越过泛型检查

 List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list);

        //泛型只在编译期有效!!!
        //反射越过泛型检查
        //反射可以在程序运行时,动态地调用List中的add方法去添加元素

        Class<? extends List> aClass = list.getClass();
        Method add = aClass.getMethod("add", Object.class);
        Object hello = add.invoke(list, "hello");
        System.out.println(list);

反射通用方法案例

  • 需求

      给指定对象的指定字段设置指定值
    
Class<?> aClass = obj.getClass();
        Object o1 = aClass.newInstance();
        //方法名规范:如果只有一个单词,所有的字母全都小写。如果有多个单词,从第二个单词开始,首字母大写!!!
        //变量名规范: 如果只有一个单词,所有的字母全都小写。如果有多个单词,从第二个单词开始,首字母大写!!!
        //username setUsername
        //根据属性名称获取对应的set方法名称
        //String methodName = "set" + "U" + "sername";
        String str = "set" + s.substring(0, 1).toUpperCase() + s.substring(1);
        Field declaredField = aClass.getDeclaredField(s);
        //获取字段(属性)的数据类型
        Class<?> type = declaredField.getType();
        //获取set方法对象
        Method method = aClass.getMethod(str, type);
        //执行set方法
        method.invoke(obj,o);

反射结合配置文件

  • 需求

  • 编写bean.properties,配置对象的唯一标识及对象的全类名,根据这段配置创建一个对象

bean01=com.qf.bean.User
bean02=com.qf.bean.Banana
 //需求:编写bean.properties,配置对象的唯一标识及对象的全类名,根据这段配置创建一个对象
        Properties properties = new Properties();
        //将bean.properties中的数据存储到resourceAsStream中
        InputStream resourceAsStream = Demo11.class.getResourceAsStream("/bean.properties");
        //将bean.properties中的数据绑定到了Properties中!
        properties.load(resourceAsStream);
        //根据全类名,创建Class对象
        Class<?> bean01 = Class.forName(properties.getProperty("bean01"));
        //根据Class对象创建对象
        Object o = bean01.newInstance();
        System.out.println(o);


        Class<?> bean02 = Class.forName(properties.getProperty("bean02"));
        Object o1 = bean02.newInstance();
        System.out.println(o1);

静态代理设计模式

  • 概念
    • 增强被代理类的功能
  • 步骤
    • 自定义类实现和被代理类相同的接口
    • 在代理类中声明被代理类的对象
    • 在代理类的方法中使用被代理类调用方法
  • 代码实现
//1,自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
public class UserDaoImplProxy implements UserDao{

    //2,在代理类中声明被代理类的引用
    private UserDao userDao ;
    public UserDaoImplProxy(){
        userDao = new UserDaoImpl();
    }
    @Override
    public void addUser() {
        //3,在代理类的方法中使用被代理类调用方法
        System.out.println("权限校验");
        userDao.addUser();
        System.out.println("日志记录");
    }

    @Override
    public void deleteUser() {
        userDao.deleteUser();
    }
    @Override
    public void updateUser() {
        userDao.updateUser();
    }
    @Override
    public void selectUser() {
        userDao.selectUser();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章