首页 > 编程语言 >Java反射机制

Java反射机制

时间:2022-11-24 20:46:33浏览次数:42  
标签:反射 Java System clazz Person println 机制 Class out

反射特征:动态性
编译时候确定不了哪个类的对象
比如:后台已经在运行了,但还没有收到前端的请求,这时候,后台收到请求时,使用的是反射机制调用对象
反射机制与面向对象的矛盾:
不矛盾,如何看待:反射可以调用私有方法/属性,封装规定了不能用,

反射来调用私有私有构造器, 私有属性以及方法

使用大的Class类对象clazz来调用三种方法来实现。

关于Java.lang.Class

1、javac.exe 生成字节码文件(.class),
2.接着使用java.exe命令对某个字节码文件进行解释运行,相当于将文件所对应的类加载到内存中,即为类的加载过程加载到内存中的类就称作运行时类,此运行时类本身作为Class类的一个对象。通过类的.class化做一个对象。类本身也是一个对象,是Class类的对象。万物皆对象。
换句话说,Class类的实例就对应着一个运行时类

加载到内存中的运行时类,会缓存一定时间,在此时间内,可以通过不同的方式获取,而不是创建一个对象。而且都是同一个对象,可以看作是单例的

Class类的实例的方式

//方式一:调用运行时类的属性.class,编译时会发现写死了
        Class clazz1 = Person.class;
        System.out.println(clazz1);
        //方式二:调用运行时类的对象的getClass()方法
        Person person = new Person();
        Class clazz2 = person.getClass();
        //返回的是这个对象的运行时类
        System.out.println(clazz2);

        //方式三:通过Class的静态方法:forName(全类名:String classpath)
        //好处:编译时候不会确定,运行时才会确定这个类存不存在
        Class<?> clazz3 = Class.forName("com.nuaa.reflect.Person");
        System.out.println(clazz3);
        System.out.println(clazz1 == clazz2);
        System.out.println(clazz3 == clazz2);

        //方式四:使用ClassLoader类加载器的方式,通过loadClass函数来加载得到Person类
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class<?> clazz4 = classLoader.loadClass("com.nuaa.reflect.Person");
        System.out.println(clazz1 == clazz4);

运行和结果:
class com.nuaa.reflect.Person
class com.nuaa.reflect.Person
class com.nuaa.reflect.Person
true
true

Class类的实例可以是哪些:

class
Class
接口
数组(只要数组的类型和维度是一样的,就是同一个Class对象)
基本数据类型
注解

类的加载器

将.class文件字节码内容加载到内存空间中,并将这些静态数据转换成方法区运行时数据结构,然后在堆中生成一个代表这个类的java,lang.Class对象,作为方法区中类数据的入口。缓存中会维持一段时间,是对象就会被jvm垃圾收集机制处理。

自顶向下:
引导类加载器:用来装载Java核心类库,无法直接获取
扩展类加载器:负责将jar包装入到工作库。
系统类加载器:用来将指定全类名加载到内存。

//对于自定义的类,使用的是系统类加载器进行加载
        ClassLoader classLoader1 = ReflectionTest.class.getClassLoader();
        System.out.println(classLoader1);
        //调用系统类加载器的getParent()方法可以获取扩展类加载器
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);
        //调用扩展类加载器的getParent()获取不到引导类加载器,获取不到引导类加载器的。
        //引导类加载器是主要负责加载Java的核心类库,无法加载自定义的类
        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println(classLoader3);
        
        sun.miscLauncher$AppClassLoader@18b4aac2
        sun.miscLauncher$ExtClassLoader@85ede7b
        null

两种方式读取配置文件

两种方式都离不开对流的操作,但是流之前的操作可以不一样,对配置文件的默认识别位置也不一样,web工程下将配置文件放在src下进行管理。

Properties properties = new Properties();
        //方式一:读取配置文件,此时文件默认在当前module下,要是需要寻找src目录下的文件,
        // 需要使用地址:src\\jdbc.properties
        FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
        properties.load(fileInputStream);
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        System.out.println("user=" + user + ",password=" + password);
        
        //方式二:使用ClassLoader,配置文件默认识别为当前module的src下
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        //以流的方式获取资源,jdbc.properties本身就是一个资源包,
        // 以下只需要填上文件路径即可。
        InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");
        properties.load(fileInputStream);
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        System.out.println("user=" + user + ",password=" + password);

通过反射造对象

Class clazz = Class.forName("com.nuaa.reflect.Person");
        //newInstance()方法创建运行时类的对象,内部调用运行时类的空参构造器,
        //否则就会报错,找不到默认构造器。一般权限为public---》例如javabean
        Object o = clazz.newInstance();
        System.out.println(o);

反射的动态性

public void test1(){
        for (int i = 0; i < 100; i++) {
            int num = new Random().nextInt(3);
            String classPath = "";
            switch (num){
                case 0:
                    classPath = "java.util.Date";
                    break;
                case 1:
                    classPath = "java.lang.Object";
                    break;
                case 2:
                    classPath = "com.nuaa.reflect";
                    break;
            }
            Object instance = null;
            try {
                instance = getInstance(classPath);
                System.out.println(instance);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }
    public Object getInstance(String classPath) throws Exception {
        Class<?> aClass = Class.forName(classPath);
        return aClass.newInstance();
    }


    编译时不能确定具体的类,等到运行的时候能够确定

反射获取类的所有结构

 Class<?> clazz = Class.forName("com.nuaa.reflect.Person");
        //只能获取所有声明为public权限的属性。包含父类中声明的public属性
        Field[] fields = clazz.getFields();
        for (Object o: fields
             ) {
            System.out.println(o);
        }
        //获取当前运行时类所有声明的属性。(不包含父类中声明的属性)
        Field[] declaredFields = clazz.getDeclaredFields();
//只能获取所有声明为public权限的方法。包含父类中声明的public方法
        Method[] methods = clazz.getMethods();
        for (Method method:methods
             ) {
            System.out.println(method);
        }
        //获取当前运行时类所有声明的方法。(不包含父类中声明的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        //获取方法声声明的注解,了解注解的功能。
        for (Method method:declaredMethods
             ) {
            Annotation annotation = method.getAnnotation();
            System.out.println(annotation);
        }
        //获取接口,异常信息等

获取指定结构

通过反射获取到的只能是一个空壳,还需要给它赋值,找对象
属性:

Class<?> clazz = Class.forName("com.nuaa.reflect.Person");
        Person o = (Person) clazz.newInstance();
        //获取指定属性,但是只能获取运行时类中的pulic属性
        Field name = clazz.getField("age");
        name.set(o, 11);
        System.out.println(o.toString());

        结果:
        java.lang.NoSuchFieldException: age


Class<?> clazz = Class.forName("com.nuaa.reflect.Person");
        Person o = (Person) clazz.newInstance();
        //获取指定属性,但是只能获取运行时类中的pulic属性
        Field name = clazz.getDeclaredField("name");
        name.set(o, "张三");
        System.out.println(o.toString());

        结果2:java.lang.IllegalAccessException
        拿到了但是毕竟是私有的


改进:
Class<?> clazz = Class.forName("com.nuaa.reflect.Person");
        Person o = (Person) clazz.newInstance();
        //获取指定属性,但是只能获取运行时类中的pulic属性
        Field name = clazz.getDeclaredField("name");
        //保证当前属性是可以访问的,然后才能获取和操作
        name.setAccessible(true);
        name.set(o, "张三");
        System.out.println(o.toString());


获取特定方法

Class<?> clazz = Class.forName("com.nuaa.reflect.Person");
        Person o = (Person) clazz.newInstance();
        //函数名以及参数的名

        Method show = clazz.getDeclaredMethod("show", String.class);
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        //1,如果方法非public,要设置访问许可!!
        //2.invoke()方法的返回值就是对应类中调用的方法的返回值,没有返回值就是null
        show.setAccessible(true);
        Object o1 = show.invoke(o, "哈哈哈");
        //invoke()要求第一个参数是对象,.class就是一个类又是一个对象,第二个参数可省。
        Object invoke = showDesc.invoke(Person.class);
        
        System.out.println(o1);
        System.out.println(invoke);

标签:反射,Java,System,clazz,Person,println,机制,Class,out
From: https://www.cnblogs.com/napotre/p/16921948.html

相关文章