欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

< 笔记 > Java SE - 09 Java SE 反射

程序员文章站 2022-06-09 20:43:53
...

09 Java SE 反射

By Kevin Song

定义:反射机制是在运行状态中,对于任意一个(class文件),都能知道这个类的所有方法属性。对于任意一个对象都能调用它的任意一个方法属性

Tomcat例

  • Tomcat App提供 Servlet接口
  • MyServlet类实现Servlet接口
  • 编写MyServlet类配置文件
  • Tomcat直接读取配置文件来动态获取MyServlet类中的方法和属性
    • Tomcat通过Class类来获取MyServlet类字节码文件中的内容(想要对MyServlet文件进行内容获取,第一步要获取该类的字节码文件对象即可)
      • 获取Class类中的对象(字节码文件对象)
        • Tomcat通过Class类中的forName()方法获取MyServlet类字节码文件对象
      • 获取Class类中的构造方法
        • 通过newInstance()获取该类空构造方法对象
        • 通过getConstructor获取构造方法对象
          • 再通过构造方法对象newInstance();方法来创建非空参对象
      • 获取Class类中的字段
      • 获取Class类中的方法
class Person {
    name;
    age;
}

Person p1 = new Person(Leo, 20);
Person P2 = new Person(Kylo, 28);
//描述字节码文件的类
class Class {
    提供可以获取字节码文件的内容(字段,构造方法,一般方法)
}
class Demo {
    int a = 6;
    Demo() {}
    void show() {}
}
class Test {
    int b = 9;
    Test() {}
    void abc() {}
}

获取Class对象

三种方式
- 方式三:Object类中的getClass()方法
- 必须明确具体的类并且创建对象
- 方式二:任何数据类型都具备一个静态的属性.class来获取其对应的class对象
- 要明确类中的静态成员
- 方式三:通过给定的类的字符串名称就可以获取该类
- Class类中的forName()方法

public class ReflectDemo {
    public static void main(String[] args) {
        //方式一:Object类中的getClass()方法
        public static void getClassObject_1() {
            Person p = new Person();
            Class clazz = p.getClass();

            Person p1 = ne Person();
            Class clazz1 = p1.getClass();

            System.out.println(clazz==clazz1);//true
        }
        //方式二
        public static void getClassObject_2() {
            Class clazz = Person.class;
            Class clazz1 = Person.class;
            System.out.println(clazz==clazz1);//true
        }
        //方式三
        public static void getClassObject_3() throws ClassNotFoundException {
            String className ="Person";
            Class class = Class.forName(className);
            System.out.println(clazz);
        }
    }
}
public class Person {
    private int age;
    private String name;

    public Person(int age, String name) {
        super();
        this.age = age;
        this.name = name;
        System.out.println(personParam run"");
    }
    public Person() {
        super;
        System.out.println(person run"");
    }
    public void show() {
        System.out.println(name+"..."+age);
    }
    private void method() {
        System.out.println("method run");
    }
    public void paraMethod(String str, int num) {
        System.out.println("paramMethod run"+str+":"+num);
    }
    public static void staticMethod() {
        System.out.println("staticMethod run");
    }
}

获取Class中的构造方法

  • 早期创建对象
    • new的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内创建该字节码文件对象,然后创建该字节文件的对应Person对象
  • 反射创建对象
    • 只要知道类名,通过Class来创建该类字节码文件对象
      • 通过newInstance()获取该类空构造方法对象
      • 通过getConstructor获取构造方法对象
        • 再通过构造方法对象newInstance();方法来创建非空参对象
public class ReflectDemo2 {
    public static void main(String[] args) {
        createNewObject_1();
        createNewObject_2();
    }
    //空参数构造方法
    public static void createNewObject_1() {
        //以前
        Person p = new Person();
        //反射
        String name = "Person";
        Class clazz = Clazz.forName(name);//获取Person类字节码文件对象
        Object obj = clazz.newInstance();//产生Person类对象
    }
    //非空参数构造方法
    public static void createNewObject_2() {

        String name = "Person";
        Class clazz = Clazz.forName(name);//获取Person类字节码文件对象
        //获取指定构造函数的对象
        Constructor constructor = clazz.getConstructor(String.class, int.class);
        Object obj = constructor.newInstance("Kylo", 29);
    }
}

获取Class中的字段

public class ReflectDemo3 {
    public static void main(String[] args) {
        createNewObject_1();
        createNewObject_2();
    }
    //空参数构造方法
    public static void getFieldDemo() {
        Class clazz = Class.forName("Person");
        Field field = clazz.getField("age");//获取公有的
        field = clazz.getDeclaredField("age");//获取本类,包含私有
        //对私有字段的访问取消权限检查,强制访问
        field.setAccessible(true);
        Object obj = clazz.newInstance();
        field.set(obj,20);
        Object o = field.get(obj);
        System.out.println(o);

    }
}

获取Class中的方法

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        getMethodDemo_3();
    }
    //获取有参方法
    public static void getMethodDemo_3() throws Exception {
        Class clazz = Class.forName("cn.itcast.bean.Person");
        Method method = clazz.getMethod("paramMethod", String.class,int.class);
        Object obj = clazz.newInstance();
        method.invoke(obj, "小强",89);
    }
    //获取无参方法
    public static void getMethodDemo_2() throws Exception {
        Class clazz = Class.forName("cn.itcast.bean.Person");
        Method method = clazz.getMethod("show", null);//获取空参数一般方法。
        //Object obj = clazz.newInstance();
        Constructor constructor = clazz.getConstructor(String.class,int.class);
        Object obj = constructor.newInstance("小明",37);
        method.invoke(obj, null);
    }
    //获取指定Class中的所有公共方法
    public static void getMethodDemo() throws Exception {
        Class clazz = Class.forName("cn.itcast.bean.Person");
        Method[] methods  = clazz.getMethods();//获取的都是公有的方法。 
        methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包含私有。 
        for(Method method : methods){
            System.out.println(method);
        }
    }
}

反射练习

public class Mainboard {
    public void run() {
        System.out.println("main board run....");
    }
    public void usePCI(PCI p) {//PCI p = new SouncCard();
        if (p != null) {
            p.open();
            p.close();
        }
    }
}
public class SoundCard implements PCI {
    public void open(){
        System.out.println("sound open");
    }
    public void close(){
        System.out.println("sound close");
    }
}
public class NetCard implements PCI {
    @Override
    public void open() {
        System.out.println("net open");
    }
    @Override
    public void close() {
        System.out.println("net close");
    }
}
public interface PCI {
    public void open();
    public void close();
}
/*
 * 电脑运行。 
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        Mainboard mb = new Mainboard();
        mb.run();
        //每次添加一个设备都需要修改代码传递一个新创建的对象
        //mb.usePCI(new SoundCard());
        //能不能不修改代码就可以完成这个动作。
        //不用new来完成,而是只获取其class文件。在内部实现创建对象的动作。 
        File configFile = new File("pci.properties");

        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream(configFile);

        prop.load(fis);

        for(int x=0; x<prop.size(); x++){
            String pciName = prop.getProperty("pci"+(x+1));
            Class clazz = Class.forName(pciName);//用Class去加载这个pci子类。
            PCI p = (PCI)clazz.newInstance();

            mb.usePCI(p);
        }
        fis.close();
    }
}
pci.properties文件
pci1=cn.itcast.reflect.test.SoundCard
pci2=cn.itcast.reflect.test.NetCard