07 反射 01获取class的三种方法

1、获取Class的三种方法

/*
        * 1、反射机制
        *   通过Java语言中反射机制可以操作字节码文件(可以读和修改字节码文件)
        *   通过反射机制可以操作代码片段(class文件)
        * 2、反射机制的相关类在哪个包下:java.lang.reflect.*
        * 3、反射机制相关的类有哪些?
        *   java.lang.Class 代表整个字节码
        *   java.lang.reflect.Method 代表字节码中方法字节码
        *   java.lang.reflect.Construct 代表字节码中的构造方法字节码
        *   java.lang.reflect.Field   代表字节码中的属性字节码,代表类中的成员变量
        *
        *
        * */

        /*
        * 要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Close实例?
        * 三种方式:
        *   第一种:Class c = Class.forName("完整类名带包名");
        *   第二种:Class c = 对象.geClass()
        *   第三种:java语言中任何一种类型,包括基本数据类型,它都有class属性,Class c = "任何类型“.class
        * Class.forName()
        * 1、静态方法
        * 2、方法的参数是一个字符串
        * 3、字符串需要的是一个完整的类名
        * 4、完整类名必须带有包名,java.lang包不能省略
        *
        * */
        Class c1 = null;  //代表String.Class类型
        Class c2 = null;
        Class c3 = null;
        try {
            c1 = Class.forName("java.lang.String");
            c2 = Class.forName("java.lang.Integer");  //代表Integer类型
           
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


        //java中任何一个对象都有一个方法:getClass()
        String  s = "abc";
        Class x = s.getClass();  //x代表的String.class字节码文件,x代表String类型
        System.out.println(c1 == x);   //==比较的是字节码的内存地址,字节码文件装载到JVM的时候,值装载一份
        
        //java语言中任何一种类型,包括基本数据类型,它都有class属性
        Class  z = String.class;  //代表String类型
        Class f = Date.class;   //代表Date类型
        Class e = double.class;   //代表double类型
        Class r = int.class;  //代表int类型
        

2、通过反射实例化对象

 //普通创建
        User user = new User();
        System.out.println(user);

        try {
            //重点:通过反射机制,获取Class,通过Class来实例化对象
            Class c = Class.forName("User");
            //会调用USer的无参构造方法,完成User的创建;
            //重点是:newInstance调用的是无参构造,必须保证无参构造是存在的
            Object obj = c.newInstance();  
            System.out.println(obj);   //User@4554617c
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

3、反射机制的灵活性

*
* 获取Class,能干什么?
* 操作字节码文件
*  java 代码写一遍,再不改变java源代码的基础之上,可以做到不同对象的实例化
* 非常之灵活,符合OCP原则,对修改关闭,对扩展开放
*
* 后期要歇息高级框架,而工作中需要使用高级框架,而高级框架都是使用反射机制,有利于学习框架底层的东西
* */
  //这种就写死了,只能创建一个User类型的对象
        User user = new User();

        //一下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改后,可以创建出不同的实例对象
        try {
            //通过IO流读取classinfo.properties文件
            FileReader fr = new FileReader("src/classinfo.properties");
            //创建属性类对象
            Properties pro = new Properties();
            //加载
            pro.load(fr);

            //通过key获取value
            String className = pro.getProperty("className");

            //通过反射机制实例化对象
            Class c1 = Class.forName(className);
            Object obj = c1.newInstance();
            System.out.println(obj);
            //关闭流
            fr.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

4、Class.forName()发生了什么

/*
* 研究一下:Class.forName()发生了什么
* 重点:只希望一个类的静态代码块执行,其他一律不执行
*   你可以使用:Class.forName("完整类名")
*   这个方法的执行会导致类加载,类加载时,静态代码块执行
* 
* 提示:
*   后面JDBC技术的时候我们还需要
* */

public class ReflectTest01 {
    public static void main(String[] args) {
        //静态代码块在类加载时加载,并且只执行一次
        try {
            Class.forName("MyClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


    }
}
class MyClass{
    //静态代码块在类加载时执行,并且只执行一次
    static{
        System.out.println("静态代码块执行了");
    }
}

5、获取路径的绝对路径

  //这种路径的缺点就是:移植性差,在idea中默认的路径是project的根
        // 这个代码假设离开了idea,换到其他的位置,可能当前路径就不是project的根了,这个路径就无效了
        // FileReader reader = new FileReader("classinfo.properties");
        //接下来说一种通用的路径表示方法,这种编写是通用的是
        //注意:试用一下通用方式的前提是:这个文件必须在类路径下,什么是类路径下,方式在src下都是类路径 src类的根路径
        /*
        * Thread.currentThread():当前线程
        * getContextClassLoader():是线程对象的方法,可以获取当前线程的类加载器
        * getResource:这是类加载器对象的方法,当前线程的类加载器默认从类的根目录获取资源
        * 可以拿到一个文件的绝对路径:/D:/java_base/out/production/chapter15/classinfo.properties
         *
        * */
        String path = Thread.currentThread().getContextClassLoader().getResource("classinfo.properties").getPath();
        System.out.println(path);

        //获取db.properties的绝对路径(从类的根路径下作为起点开始)
        String path2 = Thread.currentThread().getContextClassLoader().getResource("integer/db.properties").getPath();
        System.out.println(path2);

6、类加载器

  /*
      * java.util下提供一个资源绑定器,便于获取属性配置文件中的内容
      * 但是以这种方式的时候,属性配置文件xxx.properties必须放到类路径下
      *
      * */
        //资源管理器,只能绑定xxx.properties文件,并且这个文件必须在类路径下,在写文件名的时候,路径后面的扩展名不能写
     
        ResourceBundle bundle  = ResourceBundle.getBundle("classinfo");

        String className = bundle.getString("className");

 

posted @ 2022-01-28 18:14  zhustarstar  阅读(102)  评论(0编辑  收藏  举报