java 反射操作详解

前言

本文将用到 Student 类和 Address 类进行演示。

Student 类:

package com.hai.tang.model;

public class Student {
    public Integer id;
    public String name;
    public Integer score;
    public Address address;

    public Student(){}

    public Student(Integer id ,String name,Integer score){
        this.id=id;
        this.name=name;
        this.score=score;
    }

    public Student(String name,Integer id ){
        this.id=id;
        this.name=name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public  String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public String setAndGetName(int id, String name) {
        this.id = id;
        this.name = name;
        return name;
    }

    public Integer getScore() {
        return score;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "id:"+id+",name:"+name+",score:"+score+",address:"+address;
    }

    public String calculation(String name,Integer score ){
        return name+"成绩是:"+score;
    }
}

Address 类:

package com.hai.tang.model;

public class Address {
    public String type;
    public String value;

    public Address(String type, String value) {
        this.type = type;
        this.value = value;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "type:" + type + ",value:" + value;
    }
}

一、获取反射类

1.使用 Class.forName 方式获取反射类

        Class studentClass = Class.forName("com.hai.tang.model.Student");
        System.out.println(studentClass); //class com.hai.tang.model.Student

2.使用 类名.class 方式获取反射类

        Class studentClass = Student.class;
        System.out.println(studentClass);//class com.hai.tang.model.Student

3.通过 对象.getClass() 方式获取反射类

        Student student = new Student();
        Class studentClass = student.getClass(); 
        System.out.println(studentClass);//class com.hai.tang.model.Student

二、反射获取对象的所有构造方法及参数个数、类型

        Class<Student> studentClass = Student.class;
        //获取 Student 里所有的构造方法
        Constructor[] constructors = studentClass.getConstructors();
        for (Constructor constructor : constructors) {
            //打印该构造方法
            System.out.println(constructor);
            //获取该构造方法的形参
            Class[] params = constructor.getParameterTypes();
            //获取该构造方法有几个参数
            int paramsCount = params.length;
            System.out.println(paramsCount);
            for (int i = 0; i < params.length; i++) {
                //打印该形参
                System.out.println(params[i]);
            }
            //调用有3个参数的构造方法进行反射创建对象
            if (paramsCount == 3) {
                try {
                    Student student = (Student) constructor.newInstance(1, "jack", 89);
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
            System.out.println();
        }

输出:

public com.hai.tang.model.Student(java.lang.String,java.lang.Integer)
2
class java.lang.String
class java.lang.Integer

public com.hai.tang.model.Student(java.lang.Integer,java.lang.String,java.lang.Integer)
3
class java.lang.Integer
class java.lang.String
class java.lang.Integer

public com.hai.tang.model.Student()
0

二、利用反射创建对象

1.调用 newInstance()无参构造方法创建对象

        Class<Student> studentClass = Student.class;
        try {
            //Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;
            Student student = studentClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

或者 使用getDeclaredConstructor :

        Class<Student> studentClass = Student.class;        
		try {
            //或使用getDeclaredConstructor()调用默认构造方法
            Constructor<Student> con = studentClass.getDeclaredConstructor();
            Student student = con.newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }

2.调用有参的构造方法创建对象

        Class<Student> studentClass = Student.class;
        try {
            Constructor<Student> con = studentClass.getDeclaredConstructor(Integer.class, String.class, Integer.class);
            Student student = con.newInstance(1,"jack", 89);
            System.out.println(student.getName());
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }

三、反射获取类成员变量名称

1.获取所有成员变量的全部信息

        Class clas = Student.class;
        Field[] fields = clas.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i]);
        }

输出:

public java.lang.Integer com.hai.tang.model.Student.id
public java.lang.String com.hai.tang.model.Student.name
public java.lang.Integer com.hai.tang.model.Student.score
public com.hai.tang.model.Address com.hai.tang.model.Student.address

2.只获取所有成员变量的名称

        Class clas = Student.class;
        Field[] fields = clas.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            String fieldName = fields[i].getName();
            System.out.println(fieldName);
        }

输出:

id
name
score
address

3.获取某一指定字段全部信息

        Class clas = Student.class;
        Field field = clas.getField("name"); //获取"name"
		//输出 public java.lang.String com.hai.tang.model.Student.name
        System.out.println(field); 

4.只获取某一指定成员变量的名称

        Class clas = Student.class;
        Field field = clas.getField("name"); //获取"name"
        String name = field.getName();
        System.out.println(name); //输出name

5.getFields()与getDeclaredFields()的区别

  • getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
  • getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是 不包括父类的声明字段

四、获取成员变量的值

1.获取公有的成员变量的值

        try {
            //创建对象
            Student student = new Student(1,"李梅",89);
            //通过反射获取属性 name 成员变量对应的值
            Class clas = Student.class;
            Field field = clas.getField("name");
            //如果获取的成员变量是私有的 使用get获取会报 IllegalAccessException 错误
            Object property = field.get(student);
            System.out.println(property.toString());//输出:李梅
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

2.获取私有的成员变量的值

加入 name 是 private 修饰的私有成员变量

        try {
            //创建对象
            Student student = new Student(1,"李梅",89);
            //反射获取
            Field privateField = Student.class.getDeclaredField("name");
            privateField.setAccessible(true);
            String name = (String) privateField.get(student);
            System.out.println(name);//输出:李梅
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

五、修改成员变量的值

        try {
            Student student = new Student(1,"李梅",89);
            //没有修改时:李梅
            System.out.println("没有修改时:" + student.getName());
            Class clas = Student.class;
            Field field = clas.getDeclaredField("name");
            // 若name成员变量是private修饰的,需要将可见范围设为true才可以访问私有类型变量
            //field.setAccessible(true); 
            field.set(student, "张三"); // 将name的值设置为张三
            //修改后:张三
            System.out.println("修改后:" + student.getName()); 
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

六、反射获取类的所有方法

1.使用getMethods获取所有方法(包含从父类和Object继承的方法)

        Class clas = Student.class;
        Method[] methods = clas.getMethods();
        Arrays.stream(methods).forEach(System.out::println);

输出:

public java.lang.String com.hai.tang.model.Student.toString()
public com.hai.tang.model.Address com.hai.tang.model.Student.getAddress()
public java.lang.String com.hai.tang.model.Student.getName()
public void com.hai.tang.model.Student.setName(java.lang.String)
public void com.hai.tang.model.Student.setAddress(com.hai.tang.model.Address)
public void com.hai.tang.model.Student.setId(java.lang.Integer)
public java.lang.String com.hai.tang.model.Student.setAndGetName(int,java.lang.String)
public java.lang.Integer com.hai.tang.model.Student.getScore()
public java.lang.String com.hai.tang.model.Student.calculation(java.lang.String,java.lang.Integer)
public void com.hai.tang.model.Student.setScore(java.lang.Integer)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

2.使用getDeclaredMethods获取其类自身声明的所有方法

        Class clas = Student.class;
        Method[] methods = clas.getDeclaredMethods();
        Arrays.stream(methods).forEach(System.out::println);

输出:

public java.lang.String com.hai.tang.model.Student.toString()
public com.hai.tang.model.Address com.hai.tang.model.Student.getAddress()
public java.lang.String com.hai.tang.model.Student.getName()
public void com.hai.tang.model.Student.setName(java.lang.String)
public void com.hai.tang.model.Student.setAddress(com.hai.tang.model.Address)
public java.lang.Integer com.hai.tang.model.Student.getScore()
public void com.hai.tang.model.Student.setScore(java.lang.Integer)
public java.lang.String com.hai.tang.model.Student.calculation(java.lang.String,java.lang.Integer)
public void com.hai.tang.model.Student.setId(java.lang.Integer)
public java.lang.String com.hai.tang.model.Student.setAndGetName(int,java.lang.String)

七、反射执行方法

1.调用某一方法(无参构造器)

        try {
            Class clas = Student.class;
            //要调用的方法名称及参数类型
            Method method = clas.getMethod("setAndGetName", int.class,String.class);
            //使用newInstance (无参构造器)创建对象,调用方法,传入参数"李梅",接收返回值为 obj (若方法无返回值则会返回null)
            Object obj = method.invoke(clas.newInstance(), 1,"李梅");
            //获取方法返回结果
            String name = (String) obj;
            System.out.println(name);//输出:李梅
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }

2.调用某一方法(有参构造器)

        try {
            Class clas = Student.class;
            //要调用的方法名称及参数类型
            Method method = clas.getMethod("setAndGetName", int.class,String.class);
            //使用newInstance (有参构造器)创建对象
            Constructor con = clas.getDeclaredConstructor(Integer.class, String.class, Integer.class);
            //调用方法,传入参数 2,"张三" ,并接收返回值
            Object obj = method.invoke(con.newInstance(1,"李梅", 89),2,"张三");
            //获取方法返回结果
            String name = (String) obj;
            System.out.println(name);//输出:张三
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }

3.调用private修饰的私有方法

假设 setAndGetName 方法是 private 修饰的,需要用 getDeclaredMethod 获取方法,并设置setAccessible为true

        try {
            Class clas = Student.class;
            //要调用的方法名称及参数类型
            Method method = clas.getDeclaredMethod("setAndGetName", int.class,String.class);
            method.setAccessible(true);
            //使用newInstance (有参构造器)创建对象
            Constructor con = clas.getDeclaredConstructor(Integer.class, String.class, Integer.class);
            //调用方法,传入参数 2,"张三" ,并接收返回值
            Object obj = method.invoke(con.newInstance(1,"李梅", 89),2,"张三");
            //获取方法返回结果
            String name = (String) obj;
            System.out.println(name);//输出:张三
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }

八、综合示例

1.利用反射判断 WebFrom 类中的成员变量的值是否有是 “token” 的

package com.hai.tang.model;

public class WebFrom {
    public static String FROM_XT = "xt";
    public static String FROM_WX= "wx";
    public static String FROM_DINGTALK = "dingtalk";
    public static String FROM_EASSSO= "eassso";
    public static String FROM_COMMON = "common";
    public static String FROM_TOKEN = "token";
    public static String FROM_WELINK = "welink";
    public static String FROM_SSOTYPE = "ssotype";
    public static String FROM_WORKFLOW = "workflow";
    public static String FROM_OTHERAPP = "otherapp";
    public static String FROM_IDAAS = "IDAAS";
}

实现代码:

import com.hai.tang.model.WebFrom;
import java.lang.reflect.Field;

public class MainServer {
    public static void main(String[] args) throws IllegalAccessException {
        boolean hasToken = false;
        Field[] fields = WebFrom.class.getFields();
        for (Field field : fields) {
            String name = field.getName();
            String webFromValue = (String) field.get(name);
            if ("token".equals(webFromValue)) {
                hasToken = true;
            }
        }
        System.out.println(hasToken);//输出 true
    }
}

2.获取 RedisKeys 类中所有成员变量里的 number、description、expireDate、type

package com.hai.tang.model;

public class RedisKeys {
    public static Key developerEids = new Key("$developer-eids","开发者企业号集合","set");

    public static Key qrUrlMD5 = new Key("$qr-url","二维码的url缓存","string",60*60);

    public static Key wxTicket = new Key("$key-wxTicket-eid","微信ticket ","string",7200);

    public static Key portalAppList = new Key("$applist-portal","展现在门户的应用列表","string",7200);

    public static Key appServiceIdMap = new Key("$app-serviceIdMap","记录应用映射的服务;安装时写入,卸载时删除;判断license使用","string");

    public static  Key loginCode = new Key("$login-code","登陆加密码","string",1000*60*60);

    public static Key cdnEids = new Key("$eid-has-config-cdn","配置过自定义cdn的企业eid","set");

    public static Key JobStatus = new Key("$job_status","任务锁","string",60*10);
}
package com.hai.tang.model;

public class Key {
    public String number;
    public String description;
    public int expireDate = -1;
    public String type;

    public Key(String number, String description, String type) {
        this(number, description, type, -1);
    }

    public Key(String number, String description, String type, int expireDate) {
        this.number = number;
        this.description = description;
        this.expireDate = expireDate;
        this.type = type;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getExpireDate() {
        return expireDate;
    }

    public void setExpireDate(int expireDate) {
        this.expireDate = expireDate;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

实现代码:

import com.hai.tang.model.Key;
import java.lang.reflect.Field;
import java.util.*;

public class MainServer {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException {
        Class redisKeysClass = Class.forName("com.hai.tang.model.RedisKeys");//要反射的包名
        Field[] fields = redisKeysClass.getDeclaredFields();
        List<Map<String,String>> list = new ArrayList<>();
        for (int i = 0; i < fields.length; i++) {
            Map<String, String> map = new HashMap<>();
            Object property = fields[i].get(redisKeysClass);
            Key key= (Key)property;
            map.put("number",key.getNumber());
            map.put("description",key.getDescription());
            map.put("type",key.getType());
            map.put("expireDate",String.valueOf(key.getExpireDate()));
            list.add(map);
        }
        System.out.println(list);
    }
}

输出:

[{number=$developer-eids, description=开发者企业号集合, expireDate=-1, type=set}, 
 {number=$qr-url, description=二维码的url缓存, expireDate=3600, type=string}, 
 {number=$key-wxTicket-eid, description=微信ticket , expireDate=7200, type=string}, 
 {number=$applist-portal, description=展现在门户的应用列表, expireDate=7200, type=string}, 
 {number=$app-serviceIdMap, description=记录应用映射的服务;安装时写入,卸载时删除;判断license使用, expireDate=-1, type=string}, 
 {number=$login-code, description=登陆加密码, expireDate=3600000, type=string}, 
 {number=$eid-has-config-cdn, description=配置过自定义cdn的企业eid, expireDate=-1, type=set},
 {number=$job_status, description=任务锁, expireDate=600, type=string}]

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java反射机制是指在运行时动态地获取一个类的信息,并可以操作类的属性、方法和构造器等。Java反射机制可以使程序员在运行时动态地调用类的方法和属性,扩展类的功能,并可以实现注解、工厂模式以及框架开发等。 Java反射机制的原理如下:首先,Java编译器将Java源代码编译为字节码文件,字节码文件中包含着类的信息,这些信息包括类的名称、方法、属性和构造器等等。接着,Java虚拟机将字节码文件加载到内存中,然后通过类加载器将类加载到内存中形成一个类对象,这个类对象可以操作字节码文件中的信息。 使用Java反射机制的过程如下:首先获取类对象,通过类对象来获取类的构造器、属性、方法等信息,然后调用构造器来创建对象,通过属性获取和设置类的成员属性,通过方法调用类的方法等。 Java反射机制的优点是可以在运行时动态地得到类的信息,使得程序员在程序运行时能够对类进行更加灵活的操作,并可以使得程序更加通用化,同时也存在着一定的性能问题,因为Java反射机制需要Java虚拟机进行一定的额外处理,所以在程序运行时需要进行额外的时间和资源消耗。 总之,Java反射机制是Java语言的一项重要特性,在Java开发中广泛应用,在代码编写、框架开发以及API开发中具有重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值