JAVA中的反射机制

血红的双手。 提交于 2020-02-26 12:02:17

JAVA中的反射机制

反射机制-获取类对象

什么是类对象?

  • 所有的类,都有一个类对象,这个类对象用于提供类本身的信息。比如有多少构造方法,有多少属性,有哪些普通方法。

如何获取类对象

  • 获取类对象有3种方式

    • Class.forName
    • 类名.class
    • new 类名.getClass()
  • 在JVM中,一种类只会有一个类对象存在,所以以上三种方式所获取的类对象,都是一样的。

  • 准确的来讲,是一个ClassLoader下,一种类只有一个类对象存在

  • 代码实现:

package reflection;

/**
 * @author xsl20
 */
public class GetInstanceForClass {
    public static void main(String[] args){
        String className = "reflection.Hero";
        try{
            Class pClass1 = Class.forName(className);
            Class pClass2 = Hero.class;
            Class pClass3 = new Hero("garren",12,1010).getClass();
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}
  • 当以上三种方法获取类对象时,都会导致静态属性被初始化,而其他属性不会,而且这种初始化只会执行一次。
public class Hero{
    static String copyright;
    static {
        System.out.println("copyright被初始化!");
    }
}
  • 在Hero类添加了上面的静态属性之后,再次执行上面的获取类对象的代码,将会发现,Hero类的静态属性copyright执行了仅一次。

反射机制-创建对象

  • 反射机制创建对象和正常的使用new来创建对象不同,反射机制会先拿到类对象,然后通过类对象获取构造器对象,再通过构造器对象来创建一个对象。

创建一个对象

  • 通过java的反射机制来创建一个对象
  • 代码实现:
package reflection;
import java.lang.reflect.Constructor;
import charactor.Hero;
public class TestReflection {
  
    public static void main(String[] args) {
        //传统的使用new的方式创建对象
        Hero h1 =new Hero();
        h1.name = "teemo";
        System.out.println(h1);
          
        try {
            //使用反射的方式创建对象
            String className = "charactor.Hero";
            //类对象
            Class pClass=Class.forName(className);
            //构造器
            Constructor c= pClass.getConstructor();
            //通过构造器实例化
            Hero h2= (Hero) c.newInstance();
            h2.name="gareen";
            System.out.println(h2);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

通过配置文件创建获取文件

  • 从配置文件hero.config中获取其中的保存的类的全名称,可以是character.APHero或者character.ADHero,根据类名来实现对象的实例化。
  • 代码实现:
package reflection;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;

public class CodeGetHero {
    public static void main(String[] args){
        getHero();
    }
    public static Hero getHero(){
        File file = new File("D:/javaWorkspace/Hero.config");
        String className = "";
        try(FileReader fileReader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(fileReader)){
            className = bufferedReader.readLine();
        }catch (IOException e){
            e.printStackTrace();
        }
        System.out.println(className);
        Hero hero = null;
        try {
            Class pClass = Class.forName(className);
            Constructor constructor = pClass.getConstructor();
            hero = (Hero)constructor.newInstance();
            hero.name = "garen";
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(hero);
        return hero;
    }
}

反射机制- 访问属性

通过反射机制来访问和修改对象的属性

  • 为了访问属性,需要将Hero类的属性name设置为public,这样才能顺利的完成访问。
  • 如果需要访问private的属性,必须使用setAccessible(true)才能进行访问和修改。
  • 代码实现:
public class TestReflection{
    public static void main(String[] args){
        //新建一个对象
        Hero hero = new Hero();
        //设置对象的字段
        hero.name = "tse";
        try{
            //获取对象的字段
            Field field = hero.getClass().getDeclaredField("name");
            //设置对象的字段
            field.set(hero,"newTse");
            System.out.println(hero);
        }catch(NoSuchFieldException e){
            e.printStackTrace();
        }catch(IllegalAccessException e1){
            e1.printStackTrace();
        }
    }
}
  • 通过类对象来获取对象的字段可以使用getField(fieldName)或者使用getDeclaredField(FieldName)来实现,这两个方法有一些不同之处:

    • getField()方法只能获取public的字段,包括从父类继承来的字段。
    • getDeclaredField()方法能够该对象的所有字段,但是不包含继承来的。能够获取private的字段,但是并不能访问该值,除非使用setAccessible(true)
  • 代码实现:

Field field = hero.getClass().getDeclaredField("num");
field.setAccessible(true);
field.set(hero,111111);

反射机制- 调用方法

  • 通过java的反射特性,调用一个方法。

调用方法

  • 通过反射来调用Hero类的getNamesetName方法。
  • 代码实现:
public static void useGetAndSet(String name){
    Hero hero = new Hero();
    hero.name = "garen";
    hero.num = 110;
    try{
        //利用反射机制获取hero的方法getNum
        Method method = hero.getClass().getDeclaredMethod("getNum");
        //调用getNum方法得到Num
        int num = (int)method.invoke(hero,null);
        //打印结果为110
        System.out.println(num);
        
    }
}

反射机制- 有什么用处

  • java的反射特性非常强大,但是在基础阶段并不知道反射有什么用处
  • 简单来讲,当有两个业务类需要进行方法测试时,如果不使用反射,就只能通过修改代码来实现两个不同类的测试工作,但是如果使用反射,只需要从config文件中加载类和方法名来测试就可以。当需要更换测试类的时候,就只需要修改config文件而不需要更改代码。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!