zoukankan      html  css  js  c++  java
  • 【Java】Reflection 反射机制 01概述

    Reflection 反射机制

    反射允许程序在执行期间借助ReflectionAPI获取任何类的内部信息,直接操作任意对象的内部属性和方法

    加载完类之后,堆内存的方法区产生了一个Class 类类型的对象

    要注意!一个类只能有它对应的唯一的一个类类型实例

    这个对象封装了类的完整的结构信息,可以通过这个类对象看到类的结构

    动态语言和静态语言之分:

    动态语言

    在运行时可以改变结构的语言,新的函数、对象、代码、可以在运行时加入

    已有的函数可以被删除或者修改、,运行时代码可以根据一定条件改变结构

    主要语言: Object-C、C#、JavaScript、PHP、Python、Eriang

    静态语言

    运行时不可以改变代码的编程语言即是静态语言:Java、C、C++

    虽然Java是静态语言,但是反射机制可以让Java看起来是动态的!!!

    反射机制提供的功能:

    - 判断对象所属类

    - 运行时创建类的实例

    - 判断一个类所有的成员变量和方法

    - 获取泛型信息

    - 调用任何实例的成员变量和方法

    - 运行时处理注解

    - 动态代理!!!

    API

    - java.lang.Class 类类型类

    - java.lang.reflect.Method 方法类

    - java.lang.reflect.Field 字段类

    - java.lang.reflect.Construtor 构造器类

    我们声明一个自定义类

    public class Person {
        private String name;
        private int age;
        private boolean gender;
    
        public Person() {
        }
    
        public Person(String name, int age, boolean gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public boolean isGender() {
            return gender;
        }
    
        public void setGender(boolean gender) {
            this.gender = gender;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    '}';
        }
    }

    通过反射实现对类的访问和实例的操作

    public class ReflectTest {
    
        @Test
        public void reflect() throws Exception {
            // class属性可返回这个类的类对象
            Class<Person> personClass = Person.class;
    
            // 获取这个类的构造器类的对象,这里获取的是全参构造器
            Constructor<Person> personClassConstructor = personClass.getConstructor(String.class, int.class, boolean.class);
    
            // 调用构造器,创建Person对象
            Person person = personClassConstructor.newInstance("杰哥", 28, true);
    
            // 调用Person对象的toString();
            System.out.println(person.toString());
    
            // 通过反射,调用对象指定的属性,方法
            Field age = personClass.getDeclaredField("age");
            
            // 解开访问权限 要在访问前设置,否则无意义
            age.setAccessible(true);
    
            // 通过类的字段类实例,调用参数实例age字段,修改值
            // 发现异常报错 private无法访问
            // Class cn.dai.Reflection.ReflectTest can not access a member of class cn.dai.Reflection.Person with modifiers "private"
            age.set(person,10);
            System.out.println(person);
        }
    }

    例如方法,构造器,这些基本都是获取对应的封装类,得到封装类的实例,再调用方法即可,

    如果是private修饰的访问权限,使用前先对封装实例设置可访问,再执行调用

    类的加载过程:

    - 字节码经过java.exe之后,会根据源码编写的内容生成一个或者多个字节码文件

    - java.exe会根据某个字节码文件进行解释运行 == 字节码加载进内存

    - 上面的这一步被称为类的加载

    - 加载到内存的类,称为运行时类,作为Class类类的一个实例存在

    - 反之,Class的对象就是一个在JVM种运行的字节码类

    四种获取Class实例的方式:

    public class GetClassStyle {
    
        @Test
        public void getClass4Way() throws Exception {
            // 第一种  类.class
            Class<Person> personClass1 = Person.class;
            System.out.println(personClass1);
    
            // 第二种  类的实例.getClass();
            Person person = new Person();
            Class<? extends Person> personClass2 = person.getClass();
            System.out.println(personClass2);
    
            // 第三种 Class.forName(类的完整限定名)
            Class<?> personClass3 = Class.forName("cn.dai.Reflection.Person");
            System.out.println(personClass3);
    
            // 第四种 当前类.class.getClassLoader().loadClass(类的完全限定名");
            Class<?> personClass4 = GetClassStyle.class.getClassLoader().loadClass("cn.dai.Reflection.Person");
            
            // 所有调用的方法出来的实例都是同一个对象
        }
    }

    使用ClassLoader加载配置文件

    public class Loader {
    
        @Test
        public void loader() throws Exception {
            Properties properties = new Properties();
            // 流对象读取只能读取在当前源码工程的目录下 如果要读取,路径要写成"src\\jdbc.properties"
            FileInputStream inputStream = new FileInputStream("jdbc.properties");
            properties.load(inputStream);
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String password = properties.getProperty("password");
            System.out.println(driver);
            System.out.println(url);
            System.out.println(username);
            System.out.println(password);
            inputStream.close();
        }
    
        @Test
        public void loader2() throws Exception {
            // 创建配置实例
            Properties properties = new Properties();
            // 类加载器读取 文件的位置默认是在当前Module或者项目的src包下
            InputStream inputStream = Loader.class.getClassLoader().getResourceAsStream("jdbc.properties");
            // 加载
            properties.load(inputStream);
    
            // 读取信息
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String password = properties.getProperty("password");
    
            System.out.println(driver);
            System.out.println(url);
            System.out.println(username);
            System.out.println(password);
            
            inputStream.close();
        }
    
        @Test
        public void loader3() throws Exception {
            // 创建配置实例
            Properties properties = new Properties();
            // 返回URL的编码 %20  类加载器读取 文件的位置默认是在当前Module或者项目的src包下
            String path = Loader.class.getClassLoader().getResource("jdbc.properties").getFile();
            // 需要解码
            String decode = URLDecoder.decode(path, "UTF-8");
            // 创建流对象
            InputStream inputStream = new FileInputStream(decode);
            // 加载配置
            properties.load(inputStream);
    
            // 读取信息
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String password = properties.getProperty("password");
    
            System.out.println(driver);
            System.out.println(url);
            System.out.println(username);
            System.out.println(password);
            
            inputStream.close();
        }
    }

     创建运行时类的对象

        @Test
        public void getInstanceByReflect() throws Exception {
            Class<Person> personClass = Person.class;
    
            // 直接用类的类实例创建对象 在JDK9+ 以后不推荐使用此方法创建实例了
            // .newInstance(); 内部调用运行时的空参构造器,没有空参构造,调用异常
            // 运行时类必须提供空参构造器,访问权限不得低于默认
            
            // javaBean 要求提供一个空参构造器的原因:
            // 通过这个反射调用构造器创建Bean的实例
            // 子类继承运行时类时,调用super()保证父类也有此构造器
            
            Person person = personClass.newInstance();
            System.out.println(person);
        }

    反射的动态性,动态生成实例

        @Test
        public void dynamic() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            for (int i = 0; i < 100; i++) {
                int random = new Random().nextInt(3);
                String classPath = null;
                switch (random){
                    case 0:
                        classPath = "java.util.Date";
                        break;
                    case 1:
                        classPath = "java.lang.Object";
                        break;
                    case 2:
                        classPath = "cn.dai.Reflection.Person";
                }
    
                Class<?> name = Class.forName(classPath);
                Object instance = name.newInstance();
                System.out.println(instance);
            }
        }
  • 相关阅读:
    ARM(ARM处理器)
    Android系统
    2014-9-17二班----11 web project
    2014-9-17二班----10 web project
    append() 、push() 和pop()的区别
    python hash
    虚拟机卡掉
    虚拟化
    heroinfo_set.all 函数
    encode()和decode()两个函数
  • 原文地址:https://www.cnblogs.com/mindzone/p/12757474.html
Copyright © 2011-2022 走看看