Java-反射机制reflect

反射机制是在程序运行时获取任何一个类的字节码的所有信息,包括修饰符、构造方法、字段、方法实现接口等信息,并且可以在程序运行时根据字节码信息创建类的实例对象,改变该对象的字段内容和调用任意一个方法。
获取一个已知的类的内部信息可以通过以下三个类获取:

  1. Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。

  2. Field类:提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

  3. Method类:提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。

Constructor类、Field类、Method类都是由JVM虚拟机在程序运行时候创建。要获得这些对象,需先获得对应的类对象。
Person类:

package com.reflect;

public class Person {
    private String userName;
    private int age;
    public double money;

    public Person(){

    }
    private Person(String name){
        this.userName = name;
    }

    public Person(String name,int age){
        this.userName = name;
        this.age = age;
    }

    public String getName() {
        return userName;
    }

    public void setName(String name) {
        this.userName = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }



    public void show(){
        System.out.println("show...");
    }

    public void show(String msg){
        System.out.println("show..."+msg);
    }

    @Override
    public String toString() {
        return "Person [name=" + userName + ", age=" + age + "]";
    }

}

以下通过反射的方式获得Person类的实例对象:

例1:通过反射创建Person对象。

public class ClassTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Person p1 = new Person();
        Person p2 = new Person();
        // 可以獲取到內存中這份class,Class表示内存中的那份字节码文件
        Class clazz1 = p1.getClass();
        Class clazz2 = p2.getClass();
        System.out.println(clazz1 == clazz2);//true
        //
        System.out.println(clazz1 == Person.class);//
        //
        Class clazz3 = Class.forName("com.reflect.Person");
        System.out.println(clazz1 == clazz3);//new关键字方法创建和反射方法创建两者比较
    }
}

输出结果:

true
true
true

true说明这三种方法获得的Person实例对象是一样的。

例2:获得Constructor类对象,进而创建Person的实例对象。

public class ConstructorTest {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.reflect.Person");
        Constructor con = clazz.getConstructor();

        Person person = (Person) con.newInstance();
        person.setName("张三");
        person.setAge(25);
        System.out.println(person.toString());
        System.out.println("------------");
        Constructor[] cs = clazz.getDeclaredConstructors();//获得所有类型的构造方法
        for(Constructor c : cs){
            System.out.println(c);
        }
        System.out.println("------------");
        Constructor[] cs2 = clazz.getConstructors();//获得public类型构造方法
        for(Constructor c : cs2){
            System.out.println(c);
        }
        System.out.println("------------");//获得指定的参数的构造方法,如果有定义无参构造方法,会同时返回
        Constructor cs3 = clazz.getConstructor(String.class,int.class);
        System.out.println(cs3);
    }
}
Person [name=张三, age=25]
------------
public com.reflect.Person()
public com.reflect.Person(java.lang.String,int)
private com.reflect.Person(java.lang.String)
------------
public com.reflect.Person()
public com.reflect.Person(java.lang.String,int)
------------
public com.reflect.Person(java.lang.String,int)

通过Constructor类创建对应的对象只能通过newInstance方法获得

例3:获得Field类,修改Person实例对象的属性值。

public class FieldTest {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.reflect.Person");
        Field age = clazz.getDeclaredField("age");
        age.setAccessible(true);//private修饰的属性必须设为true表示反射的对象在使用时应该取消 Java 语言访问检查
        Person p = new Person();
        System.out.println("before:"+p.getAge());//0

        age.set(p, 10);
        System.out.println("after:"+p.getAge());//10
        Field userName = clazz.getDeclaredField("userName");
        userName.setAccessible(true);
        userName.set(p, "张三");
        System.out.println("name="+p.getName());

        System.out.println(p.toString());
        //拿所有的属性
        System.out.println("--------");
        Field[] fs = clazz.getDeclaredFields();
        for(Field f : fs){
            System.out.println(f);
        }
        //拿到public类型的属性
        System.out.println("--------");
        Field[] fields = clazz.getFields();
        for(Field f:fields){
            System.out.println(f);
        }

    }
}

输出结果:

before:0
after:10
name=张三
Person [name=张三, age=10]
--------
private java.lang.String com.reflect.Person.userName
private int com.reflect.Person.age
public double com.reflect.Person.money
--------
public double com.reflect.Person.money

例4:获得Method类,调用Person实例对象的方法。

public class MethodTest {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        /*p.show();
        p.show("11");*/

        Class clazz = Class.forName("com.reflect.Person");
        Method method1 = clazz.getMethod("show");
        method1.invoke(p);

        Method method2 = clazz.getMethod("show", String.class);
        method2.invoke(p, "1513");
    }
}

输出结果:

show...
show...1513

例5:利用反射读取配置文件调用对应方法
配置文件config.txt:

className=com.reflect.Person
method=show
public class Test {
    public static void main(String[] args) throws Exception {
        //IO流技术读取配置文件,获取对应类名和方法名
        /*BufferedReader reader = new BufferedReader(new FileReader("config.txt"));
        String line1 = reader.readLine();//className=com.reflect.Other
        String className = line1.substring(line1.indexOf("=")+1);
        String line2 = reader.readLine();
        String method = line2.substring(line2.indexOf("=")+1);

        System.out.println(className);
        System.out.println(method);
        reader.close();*/
        Properties pro = new Properties();
        pro.load(new FileInputStream("config.txt"));

        String className = pro.getProperty("className");
        String method = pro.getProperty("method");
        //反射技术动态调用对应方法
        Class clazz = Class.forName(className);
        Method m = clazz.getDeclaredMethod(method);
        m.invoke(clazz.newInstance());
    }
}

输出结果:

show...

你可能感兴趣的:(Java,对象,实例,class)