ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java — 反射

2022-05-10 15:31:55  阅读:168  来源: 互联网

标签:lang 反射 Java String public Student java class


目录

一、反射简介

程序在运行中也可以获取类的变量和方法信息,并通过获取到的信息来创建对象。程序不必再编译期就完成确定,在运行期仍然可以扩展。

示例:学生类

public class Student {
    // 成员变量:公共、受保护、默认、私有各一个
    public String name;
    protected String pwd;
    String sex;
    private int age;

    // 构造方法:公共两个,受保护、默认、私有各一个
    public Student() {
    }

    protected Student(String name) {
        this.name = name;
    }

    Student(String name, String pwd) {
        this.name = name;
        this.pwd = pwd;
    }

    private Student(String name, String pwd, String sex) {
        this.name = name;
        this.pwd = pwd;
        this.sex = sex;
    }

    public Student(String name, String pwd, String sex, int age) {
        this.name = name;
        this.pwd = pwd;
        this.sex = sex;
        this.age = age;
    }

    // 成员方法:公共、受保护、默认、私有各一个
    public void method1() {
        System.out.println("public成员方法:method1");
    }

    protected void method2() {
        System.out.println("protected成员方法:method2");
    }

    void method3() {
        System.out.println("default成员方法:method3");
    }

    private void method4() {
        System.out.println("private成员方法:method4");
    }

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

二、Class 类

类名:Class<T>

包名:java.lang.Class<T>

Class 类和 Class 文件的关系:java.lang.Class 类用于表示一个类的字节码(.class)文件

通过反射获取对象的方式有以下三种:

方式 描述
类名.class 当该类被加载成 .class 文件时,此时该类变成了 .class,再获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段
对象.getClass() 通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
Class.forName("全限定类名") 通过 Class 类中的静态方法 forName 直接获取到该类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件

测试:

public class Test_01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 类名.class
        Class<Student> s1 = Student.class;

        // 对象.getClass()
        Student student = new Student();
        Class<? extends Student> s2 = student.getClass();

        // Class.forName("包名.类名")
        Class<?> s3 = Class.forName("A_11_reflect.Student");

        System.out.println(s1 + "\n" + s2 + "\n" + s3);
        System.out.println(s1 == s2 && s1 == s3 && s2 == s3);
    }
}

运行:

class A_11_reflect.Student
class A_11_reflect.Student
class A_11_reflect.Student
true

三、构造方法

3.1、获取构造方法

修饰符和类型 方法 秒速
Constructor<?>[] getConstructors() 返回该类所有的公共构造方法
Constructor getConstructor(Class<?>... parameterTypes) 返回该类指定的公共构造方法
Constructor<?>[] getDeclaredConstructors() 返回该类所有的构造方法
Constructor getDeclaredConstructor(Class<?>... parameterTypes) 返回该类指定的构造方法

测试:

public class Test_02 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<Student> s = Student.class;

        // 获取该类所有的公共构造方法
        Constructor<?>[] constructors = s.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("constructor = " + constructor);
        }
        System.out.println("--------");

        // 获取该类指定的公共构造方法
        Constructor<Student> c1 = s.getConstructor();
        Constructor<Student> c2 = s.getConstructor(String.class, String.class, String.class, int.class);
        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        System.out.println("--------");

        // 获取该类所有的构造方法
        Constructor<?>[] declaredConstructors = s.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("declaredConstructor = " + declaredConstructor);
        }
        System.out.println("--------");

        // 获取该类指定的构造方法
        Constructor<Student> c3 = s.getDeclaredConstructor();
        Constructor<Student> c4 = s.getDeclaredConstructor(String.class);
        Constructor<Student> c5 = s.getDeclaredConstructor(String.class, String.class);
        Constructor<Student> c6 = s.getDeclaredConstructor(String.class, String.class, String.class);
        Constructor<Student> c7 = s.getDeclaredConstructor(String.class, String.class, String.class, int.class);
        System.out.println("c3 = " + c3 + "\nc4 = " + c4 + "\nc5 = " + c5 + "\nc6 = " + c6 + "\nc7 = " + c7);
    }
}

运行:

constructor = public A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String,int)
constructor = public A_11_reflect.Student()
--------
c1 = public A_11_reflect.Student()
c2 = public A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String,int)
--------
declaredConstructor = public A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String,int)
declaredConstructor = private A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String)
declaredConstructor = A_11_reflect.Student(java.lang.String,java.lang.String)
declaredConstructor = protected A_11_reflect.Student(java.lang.String)
declaredConstructor = public A_11_reflect.Student()
--------
c3 = public A_11_reflect.Student()
c4 = protected A_11_reflect.Student(java.lang.String)
c5 = A_11_reflect.Student(java.lang.String,java.lang.String)
c6 = private A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String)
c7 = public A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String,int)

3.2、调用构造方法

类名:Constructor<T>

包名:java.lang.reflect.Constructor<T>

修饰符和类型 构造方法 描述
T newInstance(Object... initargs) 根据指定的构造方法创建对象
void setAccessible(boolean flag) 值设为 true,取消访问检查(访问私有属性时会被检查)

测试:

public class Test_03 {
    public static void main(String[] args) throws Exception {
        Class<Student> s = Student.class;

        // 调用公共的无参构造方法创建对象
        Constructor<Student> c0 = s.getConstructor();
        Student student0 = c0.newInstance();
        System.out.println("student0 = " + student0);

        // 调用公共的有参构造方法创建对象
        Constructor<Student> c1 = s.getConstructor(String.class, String.class, String.class, int.class);
        Student student1 = c1.newInstance("张三", "123", "男", 23);
        System.out.println("student1 = " + student1);

        // 调用受保护的有参构造方法创建对象
        Constructor<Student> c2 = s.getDeclaredConstructor(String.class);
        Student student2 = c2.newInstance("李四");
        System.out.println("student2 = " + student2);

        // 调用默认的有参构造方法创建对象
        Constructor<Student> c3 = s.getDeclaredConstructor(String.class, String.class);
        Student student3 = c3.newInstance("王五", "123");
        System.out.println("student3 = " + student3);

        // 调用私有的有参造方法创建对象
        Constructor<Student> c4 = s.getDeclaredConstructor(String.class, String.class, String.class);
        c4.setAccessible(true); // 取消访问检查
        Student student4 = c4.newInstance("赵六", "123", "男");
        System.out.println("student4 = " + student4);
    }
}

运行:

student0 = Student{name='null', pwd='null', sex=null, age=0}
student1 = Student{name='张三', pwd='123', sex=男, age=23}
student2 = Student{name='李四', pwd='null', sex=null, age=0}
student3 = Student{name='王五', pwd='123', sex=null, age=0}
student4 = Student{name='赵六', pwd='123', sex=男, age=0}

四、成员变量

4.1、获取成员变量

修饰符和类型 成员方法 描述
Field[] getFields() 返回该类所有的公共成员变量
Field getField(String name) 返回该类指定的公共成员变量
Field[] getDeclaredFields() 返回该类所有的成员变量
Field getDeclaredField(String name) 返回该类指定的成员变量

测试:

public class Test_04 {
    public static void main(String[] args) throws NoSuchFieldException {
        Class<Student> s = Student.class;

        // 获取该类所有的公共成员变量
        Field[] fields = s.getFields();
        for (Field field : fields) {
            System.out.println("field = " + field);
        }
        System.out.println("--------");

        // 获取该类指定的公共成员变量
        Field name1 = s.getField("name");
        System.out.println("name1 = " + name1);
        System.out.println("--------");

        // 获取该类所有的成员变量
        Field[] declaredFields = s.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("declaredField = " + declaredField);
        }
        System.out.println("--------");

        // 获取该类指定的成员变量
        Field name = s.getDeclaredField("name");
        Field pwd = s.getDeclaredField("pwd");
        Field sex = s.getDeclaredField("sex");
        Field age = s.getDeclaredField("age");
        System.out.println("name = " + name + "\npwd = " + pwd + "\nsex = " + sex + "\nage = " + age);
    }
}

运行:

field = public java.lang.String A_11_reflect.Student.name
--------
name1 = public java.lang.String A_11_reflect.Student.name
--------
declaredField = public java.lang.String A_11_reflect.Student.name
declaredField = protected java.lang.String A_11_reflect.Student.pwd
declaredField = java.lang.String A_11_reflect.Student.sex
declaredField = private int A_11_reflect.Student.age
--------
name = public java.lang.String A_11_reflect.Student.name
pwd = protected java.lang.String A_11_reflect.Student.pwd
sex = java.lang.String A_11_reflect.Student.sex
age = private int A_11_reflect.Student.age

4.2、调用成员变量

类名:Field

包名:java.lang.reflect.Field

修饰符和类型 成员方法 描述
Object set(Object obj, Object value) 将 value 赋值给 obj 对象的成员变量
Object get(Object obj) 返回 obj 对象的成员变量值

测试:

public class Test_05 {
    public static void main(String[] args) throws Exception {
        Class<Student> s = Student.class;
        // 先获取所有成员变量
        Field name = s.getDeclaredField("name");
        Field pwd = s.getDeclaredField("pwd");
        Field sex = s.getDeclaredField("sex");
        Field age = s.getDeclaredField("age");
        // 调用无参构造方法
        Constructor<Student> c = s.getConstructor();
        // 实例化
        Student student = c.newInstance();
        // 成员变量赋值
        name.set(student, "张三");
        pwd.set(student, "123");
        sex.set(student, "男");
        age.setAccessible(true); // 私有成员需取消访问检查
        age.set(student, 23);
        System.out.println("student = " + student);
        System.out.println("--------");
        // 获取成员变量值
        System.out.println(name.get(student));
        System.out.println(pwd.get(student));
        System.out.println(sex.get(student));
        System.out.println(age.get(student));
    }
}

运行:

student = Student{name='张三', pwd='123', sex=男, age=23}
--------
张三
123
男
23

五、成员方法

5.1、获取成员方法

修饰符和类型 成员方法 描述
Method[] getMethods() 返回该类所有的公共成员方法(包括继承的)
Method getMethod(String name, Class<?>... parameterTypes) 返回该类指定的公共成员方法
Method[] getDeclaredMethods() 返回该类所有的成员方法(不包括继承的)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回该类指定的成员方法

测试:

public class Test_06 {
    public static void main(String[] args) throws Exception {
        Class<Student> s = Student.class;

        // 获取该类所有的公共成员方法(包括继承的)
        Method[] methods = s.getMethods();
        for (Method method : methods) {
            System.out.println("method = " + method);
        }
        System.out.println("--------");

        // 获取该类指定的公共成员方法
        Method method = s.getMethod("method1");
        System.out.println("method1 = " + method);
        System.out.println("--------");


        // 获取该类所有的成员方法(不包括继承的)
        Method[] declaredMethods = s.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("declaredMethod = " + declaredMethod);
        }
        System.out.println("--------");

        // 获取该类指定的成员方法
        Method method1 = s.getDeclaredMethod("method1");
        Method method2 = s.getDeclaredMethod("method2");
        Method method3 = s.getDeclaredMethod("method3");
        Method method4 = s.getDeclaredMethod("method4");
        System.out.println("method1 = " + method1 + "\nmethod2 = " + method2 + "\nmethod3 = " + method3 + "\nmethod4 = " + method4);
    }
}

运行:

method = public java.lang.String A_11_reflect.Student.toString()
method = public void A_11_reflect.Student.method1()
method = public final void java.lang.Object.wait() throws java.lang.InterruptedException
method = public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
method = public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
method = public boolean java.lang.Object.equals(java.lang.Object)
method = public native int java.lang.Object.hashCode()
method = public final native java.lang.Class java.lang.Object.getClass()
method = public final native void java.lang.Object.notify()
method = public final native void java.lang.Object.notifyAll()
--------
method1 = public void A_11_reflect.Student.method1()
--------
declaredMethod = public java.lang.String A_11_reflect.Student.toString()
declaredMethod = public void A_11_reflect.Student.method1()
declaredMethod = protected void A_11_reflect.Student.method2()
declaredMethod = void A_11_reflect.Student.method3()
declaredMethod = private void A_11_reflect.Student.method4()
--------
method1 = public void A_11_reflect.Student.method1()
method2 = protected void A_11_reflect.Student.method2()
method3 = void A_11_reflect.Student.method3()
method4 = private void A_11_reflect.Student.method4()

5.2、调用成员方法

类名:Method

包名:java.lang.reflect.Method

修饰符和类型 成员方法 描述
Object invoke(Object obj, Object... args) obj:调用方法的对象,args:方法的参数

测试:

public class Test_07 {
    public static void main(String[] args) throws Exception {
        Class<Student> s = Student.class;
        // 获取类的无参构造方法
        Constructor<Student> constructor = s.getConstructor();
        // 实例化
        Student student = constructor.newInstance();
        // 调用方法
        Method[] declaredMethods = s.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            declaredMethod.setAccessible(true); // 取消私有成员方法访问检查
            declaredMethod.invoke(student);
        }
    }
}

运行:

protected成员方法:method2
default成员方法:method3
private成员方法:method4
public成员方法:method1

六、反射示例

6.1、示例1

需求:往 ArrayList<Integer> 集合中添加字符串数据。

示例:

// 越过泛型检查
public class Test_08 {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        System.out.println("arrayList = " + arrayList);
        Class<? extends ArrayList> arrayListClass = arrayList.getClass();
        Method add = arrayListClass.getMethod("add", Object.class);
        add.invoke(arrayList, "张三");
        add.invoke(arrayList, "李四");
        add.invoke(arrayList, "王五");
        System.out.println("arrayList = " + arrayList);
    }
}

运行:

arrayList = [1, 2, 3]
arrayList = [1, 2, 3, 张三, 李四, 王五]

6.2、示例2

需求:通过 properties.txt 配置文件运行类中的方法。

示例:

className=A_11_reflect/demo/Student
methodName=study
parameter=张三
public class Student {
    public void study(String name) {
        System.out.println(name + "同学爱学习!");
    }
}
public class Teacher {
    public void study(String name) {
        System.out.println(name + "老师爱学习!");
    }
}

测试:

public class Test_01 {
    public static void main(String[] args) throws Exception {
        // 加载数据
        Properties p = new Properties();
        // 读取配置
        FileReader fr = new FileReader(".\\properties.txt");
        p.load(fr);
        fr.close();

        // 获取类名
        String className = p.getProperty("className");
        // 获取方法名
        String methodName = p.getProperty("methodName");
        // 获取参数
        String parameter = p.getProperty("parameter");

        // 反射获取类的实例
        Class<?> clazz = Class.forName(className);
        // 获取类的构造方法
        Constructor<?> con = clazz.getConstructor();
        // 类实例化
        Object o = con.newInstance();
        // 获取方法对象,指定参数类型
        Method m = clazz.getMethod(methodName, String.class);
        // o对象调用m方法传入parameter参数
        m.invoke(o, parameter);
        System.out.println("o = " + o);
    }
}

运行:

张三同学爱学习!

标签:lang,反射,Java,String,public,Student,java,class
来源: https://www.cnblogs.com/bybeiya/p/16251826.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有