美文网首页Java
一文了解JAVA反射(超详尽!)

一文了解JAVA反射(超详尽!)

作者: 4d11ff5df74e | 来源:发表于2020-04-19 22:21 被阅读0次

    反射是框架设计的灵魂,只有学好了反射,才能设计出好的框架。

    一.反射的概述

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能就是Java语言的反射机制.简单来说,就是反射可以帮助我们在动态运行的时候,对于任意一个类,可以获得其所有方法,所有的变量(是所有的!包括私有!)

    反射的作用

    获取某些类的一些变量,调用某些类的私有方法.(举个例子,例如在Android开发中我们可以用来开启WiFi热点,调用WifiManager中的setWifiApEnabled()方法)

    增加代码的灵活性.(很多主流框架都使用了反射技术,像ssm框架都采用两种技术xml做配置文件+反射技术)

    而我们要想使用反射,就要对反射的常用对象有个基本了解

    Class:Class类的实例表示正在运行的Java应用程序中的类和接口
    Constructor:关于类的单个构造方法的信息以及对它的访问权限
    Field:Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限.
    Method:Method 提供关于类或接口上单独某个方法的信息

    反射在内存中的样子大概长这样

    image

    这是一个简单的Animal类,这个Animal.java文件,想要被执行的话,首先会被编译成Animal.class文件.而Animal.class想要被执行的话,就会被类加载器加载到JVM中执行,JVM就会将它加载到内存,而加载之后,我们的字节码文件Animal.class在内存中也会有一个对象的表示,别忘了Java语言有句话咋说的,“万事万物,皆为对象”.而.class文件在内存中的对象就是Class对象,所以说获得了Class,才能获得它的构造方法,属性以及方法,相对应的 构造方法在 内存中 对应的是Constructor对象, 属性 对应的就是 Field,而方法呢 对应的就是Method,但是 不管我们想要获得构造方法,属性 还是 方法, 前提都是我们先获得Class对象

    二.Class类

    Java中java.lang.Class类用于表示一个类的字节码(.class)文件

    如何得到某个class文件对应的Class对象?

    ①已知类和对象的情况下

    类名.class

    对象.getClass() — Object 类提供

    ②未知类和对象的情况下

    Class.forName(“包名.类名”)

    Class类代表某个类的字节码,并提供了加载字节码的方法:forName(“包名.类名”),forName方法用于加载类字节码到内存中,并封装成一个Class对象.

    package JavaReflectTest;
    public class Animal {
        public String name;
        private int id;
        public Animal(){
            System.out.println("我是无参构造方法");
        }
        public Animal(int id,String name){
            this.setId(id);
            this.setName(name);
            System.out.println("我是有参构造方法");
        }
        public void eat(){
            System.out.println("我是公有方法");
        }
        private void drink(){
            System.out.println("我是私有方法");
        }
        private void play(String name,String sex){
            System.out.println("我是私有带参方法");
        }
        @Override
        public String toString() {
            return "Animal{" +
                    "name='" + name + '\'' +
                    ", id=" + id +
                    '}';
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
    }
    
    public class ClassTest {
        /**
         * 获得Class对象
         * 1.通过类名.class
         * 2.对象.getClass()
         * 3.Class.forName();
         */
        public void demo1() throws ClassNotFoundException {
            //1.通过类名.class的方式
            Class class1 = Animal.class;
            //2.通过对象.getClass()的方式
            Animal animal = new Animal();
            Class class2 = animal.getClass();
            //3.Class类forName();获得(推荐)
            Class class3 = Class.forName("JavaReflectTest.Animal");
        }
        public static void main(String[] args){
    
        }
    }
    

    这三种获得Class对象的方法,推荐使用第三种方法,因为我们通常做反射的时候,都是在不知道类的实例的时候进行操作的,注意第三种方法通过Class.forName();来获得Class对象的时候,会抛出一个ClassNotFoundException 没有发现类的异常,如果我们Class.forName(“路径”); 路径写错了或者没有找到这个类的时候,就会抛出这个异常,当然这个异常处理,你可以选择try…catch处理也可以先向上抛,我这里为了方便,就直接向上抛了

    三.Constructor类

    Constructor类的实例对象代表类的一个构造方法

    ①得到某个类所有的构造方法

    Constructor [] constructors = Class.forName(“java.lang.String”).getConstructors();

    ②得到指定的构造方法并调用

    Constructor constructor = Class.forName(“java.lang.String”).getConstructors(String.class);

    String str = (String)constructor.newInstance(“abc”);

    ③Class类的newInstance()方法用来调用类的默认构造方法

    String obj = (String)Class.forName(“java.lang.String”).newInstance();

    package JavaReflectTest;
    
    import java.lang.reflect.Constructor;
    
    public class ConstructorTest {
        /**
         *获得无参构造方法
         */
        public void demo1() throws Exception {
            //获得类的字节码文件对应的对象:
            Class class1 = Class.forName("JavaReflectTest.Animal");
            Constructor c = class1.getConstructor();
            Animal animal = (Animal)c.newInstance();//相当于 Animal animal = new Animal();
        }
    
        /**
         *获得有参构造方法
         */
        public void demo2() throws Exception{
            Class class1 = Class.forName("JavaReflectTest.Animal");
            Constructor c = class1.getConstructor(int.class,String.class);
            Animal animal = (Animal)c.newInstance(2,"猴子");//相当于 Animal animal = new Animal(2,"猴子");
            System.out.println(animal.toString());
        }
        public static void main(String[] args) throws Exception {
            ConstructorTest c = new ConstructorTest();
            c.demo1();
            System.out.println("------------");
            c.demo2();
        }
    }
    

    运行结果

    image

    四.Field类

    Field类代表某个类中的一个成员变量,并提供动态的访问权限

    ①Field对象的获得

    Field[] fields = c.getFields();//取得所有public属性(包括父类继承)

    Field[] fields = c.getDeclaredFields();//取得所有声明的属性

    ②得到指定的成员变量

    Field name = c.getField(“name”);

    Field name = c.getDeclaredField(“name”);

    ③设置Filed变量是否可以访问

    field.setAccessible(boolean);

    ④Field变量值的读取,设置

    field.get(obj);

    filed.set(obj,value);

    package JavaReflectTest;
    
    import java.lang.reflect.Field;
    
    public class FieldTest {
        //测试共有属性
        public void demo1() throws Exception{
            //获得Class
            Class class1 = Class.forName("JavaReflectTest.Animal");
            //获得属性:
            Field field = class1.getField("name");
            //操作属性:
            Animal animal = (Animal)class1.getConstructor().newInstance();
            field.set(animal,"老虎");// animal.name = "老虎";
            //获取值
            Object obj = field.get(animal);
            System.out.println(obj);
            System.out.println(animal);//这样会自动调用toString()方法
        }
        //测试私有方法
        public void demo2() throws Exception{
            //获得Class
            Class class1 = Class.forName("JavaReflectTest.Animal");
            //获得私有属性:
            Field field = class1.getDeclaredField("id");
            //操作属性:
            Animal animal = (Animal)class1.getConstructor().newInstance();
            //私有属性,需要设置一个可访问的权限
            field.setAccessible(true);
            field.set(animal,1);
            //获取值:
            Object obj = field.get(animal);
            System.out.println(obj);
            System.out.println(animal);
        }
        public static void main(String[] args) throws Exception {
            FieldTest fieldTest = new FieldTest();
            fieldTest.demo1();
            System.out.println("----------------");
            fieldTest.demo2();
        }
    }
    

    效果图

    image

    五.Method类

    Method类代表某个类中的一个成员方法

    ①Method对象的获得

    1.获得所有方法

    getDeclaredMethods()

    getMethods()

    2.获得指定的方法

    getDeclaredMethod(String name,Class<?>…parameterTypes)

    getMethod(String name,Class<?>…parameterTypes)

    ②通过反射执行方法

    invoke(Object obj,Object…args)

    package JavaReflectTest;
    
    import java.lang.reflect.Method;
    
    public class MethodTest {
        //测试公有方法
        public void demo1() throws Exception{
            //获取Class对象
            Class class1 = Class.forName("JavaReflectTest.Animal");
            //实例化
            Animal animal = (Animal)class1.getConstructor().newInstance();
            //获得公有方法
            Method method = class1.getMethod("eat");
            //执行该方法
            method.invoke(animal);// 相当于animal.eat();
        }
        //测试私有方法
        public void demo2() throws Exception{
            //获取Class对象
            Class class1 = Class.forName("JavaReflectTest.Animal");
            //实例化
            Animal animal = (Animal)class1.getConstructor().newInstance();
            //获得私有方法
            Method method = class1.getDeclaredMethod("drink");
            //设置私有的访问权限
            method.setAccessible(true);
            //执行该方法
            method.invoke(animal);//相当于animal.drink();
        }
        public void demo3() throws Exception{
            //获取Class对象
            Class class1 = Class.forName("JavaReflectTest.Animal");
            //实例化
            Animal animal = (Animal)class1.getConstructor().newInstance();
            //获得私有带参的方法
            Method method = class1.getDeclaredMethod("play", int.class, String.class);
            //设置私有的访问权限
            method.setAccessible(true);
            //执行该方法
            Object obj = method.invoke(animal,2,"孔雀"); // 这是有返回值的情况 如果没有返回值可以直接写method.invoke(animal,2,"孔雀");
            System.out.println(obj);//打印返回的东西,没有就是null
        }
    
        //测试私有带参数的方法
        public static void main(String[] args) throws Exception{
            MethodTest methodTest = new MethodTest();
            methodTest.demo1();
            System.out.println("--------------------");
            methodTest.demo2();
            System.out.println("--------------------");
            methodTest.demo3();
    
        }
    
    }
    
    

    效果图

    image

    java反射就介绍到这里啦~

    image

    转载于:https://blog.csdn.net/qq_43527936/article/details/105571740

    相关文章

      网友评论

        本文标题:一文了解JAVA反射(超详尽!)

        本文链接:https://www.haomeiwen.com/subject/tulwbhtx.html