kagxin / blog

个人博客:技术、随笔、生活
https://github.com/kagxin/blog/issues
7 stars 0 forks source link

Java反射使用 #44

Open kagxin opened 4 years ago

kagxin commented 4 years ago

Class 是java的一个特殊类

什么是反射

在java中,class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。注意:这里的Class类型是一个名叫Class的class。通过Class实例获取class信息的方法称为反射(Reflection)。

获取class关联的Class类对象的3种方法

代码示例

代码目录结果结构

image

获取class关联的Class类对象的3种方法示例

import Persion.Persion;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {

        Persion xiaoming = new Persion("xiaoming", 25);
        Class cls1 = Class.forName("Persion.Persion");  //通过class的完整类名
        Class cls2 = Persion.class;                     //通过class的静态变量
        Class cls3 = xiaoming.getClass();               //通过class对象获取的

        System.out.println(cls1 == cls2); //ture
        System.out.println(cls1 == cls3); //ture 三种方式获取的是同一个对象
    }
}

通过Class 对象操作对象字段

import Persion.Persion;

import java.lang.reflect.Field;

public class Main1 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Persion xiaoming = new Persion("xiaoming", 25);
        Class cls = xiaoming.getClass();               //通过class对象获取的
        /*
         * 获取 field的方法
         * */
        Field name = cls.getField("name");  // 获取指定name的public field
        System.out.println(name.getName());

        name.set(xiaoming, "xiaoming2"); // 使用feild设置name属性的值
        Object nameStr = name.get(xiaoming);  // 使用feild获取,name值
        System.out.println(nameStr);

        System.out.println("==================");
        Field[] fields = cls.getFields();  // 获取所有的public field
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("==================");

        Field age = cls.getDeclaredField("age");  // 获取指定name的field,public protected private都可获取,获取是有方法screct
        System.out.println(age.getName());
        age.setAccessible(true);     // 私有属性,通过该方法设置忽略权限
        age.set(xiaoming, 26);       //
        Object val = age.get(xiaoming);
        System.out.println(val);
        System.out.println("==================");

        Field[] declaredFields = cls.getDeclaredFields();  // 获取指定所有的field,public protected private都可获取
        for (Field field : declaredFields
        ) {
            System.out.println(field.getName());
        }
        System.out.println("==================");

    }
}

通过Class 对象操作对象字段

import Persion.Persion;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main2 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Persion xiaogang = new Persion("xiaogang", 24);
        Class cls = xiaogang.getClass();

        Method[] methods = cls.getDeclaredMethods();  // 获取所有方法
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        System.out.println("=========");

        Method secret = cls.getDeclaredMethod("secret"); // 获取private方法
        secret.setAccessible(true);
        Object m = secret.invoke(xiaogang);          // 调用secret
        System.out.println(m);
    }
}

获取构造方法

ref: https://docs.oracle.com/javase/8/docs/api/index.html

反射应用示例

使用反射机制实现,在不改代码的情况下,执行配置文件中配置的方法。

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

public class Main3 {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        ClassLoader classLoader = Main3.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("conf.properties");
        properties.load(resourceAsStream);

        String className = properties.getProperty("className");  // 通过配置文件获取className
        String methodName = properties.getProperty("methodName"); //通过配置文件获取methodName
        Class cls = Class.forName(className);  //通过反射获取到Persion类关联的Class对象
        System.out.println(cls.getName());

        Constructor dcon = cls.getDeclaredConstructor(String.class, int.class); // 通过制定的签名获取到构造函数
        Object xiaohong = dcon.newInstance("xiaohong", 22);  // 通过Persion关联的Class对象,new一个Persion对象
        Method ts = cls.getDeclaredMethod(methodName); // 获取到对应的Method
        ts.setAccessible(true);
        Object s = ts.invoke(xiaohong); //调用配置文件里的的方法
        System.out.println(s);

    }
}
kagxin commented 4 years ago

Persion.java

package Persion;

public class Persion {
    public String name;
    private int age;

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

    public String info() {
        return String.format("%s, age %d", this.age);
    }

    private String secret() {
        return "secret";
    }

    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;
    }

    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Student.java

package Persion;

public class Student extends Persion {
    private int score;

    public Student(String name, int age) {
        super(name, age);
    }

    public String info() {
        return String.format("%s, age %d", this.getName(), this.getAge());
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "score=" + score +
                '}';
    }
}

Main.java

import Persion.Persion;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {

        Persion xiaoming = new Persion("xiaoming", 25);
        Class cls1 = Class.forName("Persion.Persion");  //通过class的完整类名
        Class cls2 = Persion.class;                     //通过class的静态变量
        Class cls3 = xiaoming.getClass();               //通过class对象获取的

        System.out.println(cls1 == cls2); //ture
        System.out.println(cls1 == cls3); //ture 三种方式获取的是同一个对象
    }
}

Main1.java

import Persion.Persion;

import java.lang.reflect.Field;

public class Main1 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {

        Persion xiaoming = new Persion("xiaoming", 25);
        Class cls = xiaoming.getClass();               //通过class对象获取的
        /*
         * 获取 field的方法
         * */
        Field name = cls.getField("name");  // 获取指定name的public field
        System.out.println(name.getName());

        name.set(xiaoming, "xiaoming2"); // 使用feild设置name属性的值
        Object nameStr = name.get(xiaoming);  // 使用feild获取,name值
        System.out.println(nameStr);

        System.out.println("==================");
        Field[] fields = cls.getFields();  // 获取所有的public field
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("==================");

        Field age = cls.getDeclaredField("age");  // 获取指定name的field,public protected private都可获取,获取是有方法screct
        System.out.println(age.getName());
        age.setAccessible(true);     // 私有属性,通过该方法设置忽略权限
        age.set(xiaoming, 26);       //
        Object val = age.get(xiaoming);
        System.out.println(val);
        System.out.println("==================");

        Field[] declaredFields = cls.getDeclaredFields();  // 获取指定所有的field,public protected private都可获取
        for (Field field : declaredFields
        ) {
            System.out.println(field.getName());
        }
        System.out.println("==================");

    }
}

Main2.java

import Persion.Persion;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main2 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Persion xiaogang = new Persion("xiaogang", 24);
        Class cls = xiaogang.getClass();

        Method[] methods = cls.getDeclaredMethods();  // 获取所有方法
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        System.out.println("=========");

        Method secret = cls.getDeclaredMethod("secret"); // 获取private方法
        secret.setAccessible(true);
        Object m = secret.invoke(xiaogang);          // 调用secret
        System.out.println(m);
    }

}

Main3.java

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

public class Main3 {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        ClassLoader classLoader = Main3.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("conf.properties");
        properties.load(resourceAsStream);

        String className = properties.getProperty("className");  // 通过配置文件获取className
        String methodName = properties.getProperty("methodName"); //通过配置文件获取methodName
        Class cls = Class.forName(className);  //通过反射获取到Persion类关联的Class对象
        System.out.println(cls.getName());

        Constructor dcon = cls.getDeclaredConstructor(String.class, int.class); // 通过制定的签名获取到构造函数
        Object xiaohong = dcon.newInstance("xiaohong", 22);  // 通过Persion关联的Class对象,new一个Persion对象
        Method ts = cls.getDeclaredMethod(methodName); // 获取到对应的Method
        ts.setAccessible(true);
        Object s = ts.invoke(xiaohong); //调用配置文件里的的方法
        System.out.println(s);
    }
}

conf.properties

className=Persion.Persion
methodName=toString