Java 通过反射获取方法与变量

0、反射技术

反射技术是Java生态中的重要内容,在Spring以及其他框架中得到了广泛的应用。

有了反射技术,我们可以在程序运行的过程中:

  • 构建任意一个类的对象,
  • 了解任意一个对象所属的类,
  • 获悉任意一个类中的所有成员变量和方法,
  • 调用任意一个类中的属性和方法。

1、获取方法

1.1、创建实体类

实体类中包含私有方法、公有方法、私有变量、公有变量。

public class Student {
private String name;
private Integer age;
public String className;
public Student() {
}
private Student(String name) {
this.name = name;
}
public Student(Integer age) {
this.age = age;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
private void getAge(){
System.out.println("这是一个私有方法");
}
public void getName(){
System.out.println("这是一个公有方法");
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setClassName(String className) {
this.className = className;
}
}

1.1、获取构造方法

1.1.1 获取类中的所有构造方法

首先需要通过上一篇文章中提到的方法,获取到 class对象,再通过 ​getDeclaredConstructors()​​ 获取到该类下所有构造方法。

import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
Constructor<?>[] constructors = student.getDeclaredConstructors();
for (Constructor constructor : constructors){
System.out.println(constructor);
}
}
}

输出的结果如下:

public com.reflect.Student(java.lang.String,java.lang.Integer)

public com.reflect.Student(java.lang.Integer)

private com.reflect.Student(java.lang.String)

public com.reflect.Student()

从输出的结果中,可以看到:实体类中四个构造方法都被获取到了,包括一个私有构造方法。及构造方法中的参数列表也能被取出来。

1.1.2 获取所有公有构造方法

不同于获取所有构造方法的反射方法,这里使用 ​​getConstructors()​​ 即可。

import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
Constructor<?>[] constructors = student.getConstructors();
for (Constructor constructor : constructors){
System.out.println(constructor);
}
}
}

输出如下:

public com.reflect.Student(java.lang.String,java.lang.Integer)

public com.reflect.Student(java.lang.Integer)

public com.reflect.Student()

没有获取到类中类型为 private 的构造方法,仅有 public 方法。

1.1.3 根据参数列表,获取对应的构造方法

如果我们想要根据参数列表,获取到特定的构造方法时,可以使用 ​​getDeclaredConstructor()​​ 方法,方法中指明构造方法需要的参数:

  • 所有参数,必须使用 class 对象;
  • 参数的顺序应和构造方法中的顺序一致;
  • 要获取无参构造方法,可以输入 null 作为参数,或为空;
  • 这种方式可能会产生方法找不到的异常,因此需要对异常进行捕获或抛出。
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
try {
Class<Student> student = Student.class;
//获取私有构造方法
Constructor<?> constructor = student.getDeclaredConstructor(String.class);
System.out.println(constructor);
//获取公有构造方法
Constructor<?> constructor2 = student.getDeclaredConstructor(String.class, Integer.class);
System.out.println(constructor2);
//获取无参构造方法
Constructor<?> constructor3 = student.getDeclaredConstructor(null);
System.out.println(constructor3);
}catch (Exception e){
e.printStackTrace();
}
}
}

输出结果为

private com.reflect.Student(java.lang.String)

public com.reflect.Student(java.lang.String,java.lang.Integer)

public com.reflect.Student()

  • 如果只想获取 public 类型的构造方法,可以使用 ​​getConstructor()​​​ 方法,当对应的构造方法为 private 时,会报异常 ​​java.lang.NoSuchMethodException​​;
  • 根据参数列表没有找到对应的方法,程序会报异常 ​​java.lang.NoSuchMethodException​​。

1.2、获取普通方法

1.2.1 获取所有普通方法

使用class对象的 ​​getDeclaredMethods()​​ ,可以获取当前类下所有普通方法(非构造方法)。

import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
//获取所有方法
Method[] declaredMethods = student.getDeclaredMethods();
for (Method method : declaredMethods){
System.out.println(method);
}
}
}

输出结果为

public void com.reflect.Student.getName()

public void com.reflect.Student.setName(java.lang.String)

private void com.reflect.Student.getAge()

public void com.reflect.Student.setAge(java.lang.Integer)

public void com.reflect.Student.setClassName(java.lang.String)

类型为 private 和 public 的方法,都被获取到了。

1.2.2 获取所有公有的普通方法

使用class对象的 ​​getMethods()​​ ,可以获取当前类及其所有父类下所有被 public 修饰的普通方法(非构造方法)。

import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
//获取所有方法
Method[] declaredMethods = student.getMethods();
for (Method method : declaredMethods){
System.out.println(method);
}
}
}

输出结果中,包含了 Student 类及默认父类 Object 类下所有由 public 修饰的方法。

public void com.reflect.Student.getName()

public void com.reflect.Student.setName(java.lang.String)

public void com.reflect.Student.setAge(java.lang.Integer)

public void com.reflect.Student.setClassName(java.lang.String)

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 java.lang.String java.lang.Object.toString()

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()

1.2.3 根据指定方法名及参数列表,获取指定方法

  • 如果要获取的方法为 public 时,使用 ​​getMethod()​​ 方法;
  • 如果想要获取私有方法时,需要使用 ​​getDeclaredMethod()​​ 方法。
  • 因为存在同名方法,需要在​​getMethod()​​方法中第一个参数指定要获取的方法名,后边为参数列表;
  • 无参方法时,参数列表可以没有,或使用 null 表示;
  • 因为可能存在方法找不到的情况,所以这里需要对异常进行处理或抛出;
  • 当使用​​getMethod()​​获取 private 修饰的方法时,也会抛出方法找不到的异常。
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
try {
//获取带参方法
Method method = student.getMethod("setAge", Integer.class);
System.out.println(method);
//获取无参方法
Method method2 = student.getMethod("getName", null);
System.out.println(method2);
//获取无参方法
Method method3 = student.getMethod("getName");
System.out.println(method3);
}catch (Exception e){
e.printStackTrace();
}
}
}

输出结果

public void com.reflect.Student.setAge(java.lang.Integer)

public void com.reflect.Student.getName()

public void com.reflect.Student.getName()

获取所有成员变量

import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
Field[] declaredFields = student.getDeclaredFields();
for (Field field: declaredFields){
System.out.println(field);
}
}
}

输出结果

private java.lang.String ​ ​com.reflect.Student.name​​

private java.lang.Integer com.reflect.Student.age

public java.lang.String com.reflect.Student.className

3、获取类的其他信息

3.1、获取类名

public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
System.out.println(student.getName());
}
}

获取类名其实有多种方式:

要么是通过类名获取,

或者通过对象获取,

或者指定类的全路径获取。

3.2、获取包名

可以拿到该类所在的包的全路径信息。

public class Test {
public static void main(String[] args) {
Class<HighSchoolStudent> student = HighSchoolStudent.class;
Package aPackage = student.getPackage();
System.out.println(aPackage);
}
}

3.3、获取父类

这种方式只能拿到该类的直接父类。

public class Test {
public static void main(String[] args) {
Class<HighSchoolStudent> student = HighSchoolStudent.class;
Class<? super HighSchoolStudent> superclass = student.getSuperclass();
System.out.println(superclass);
}
}

如果想要获取所有父类,可以在拿到父类后循环遍历,直到父类为 Object 为止。

public class Test {
public static void main(String[] args) {
Class<ArrayList> arrayListClass = ArrayList.class;
Class superclass = arrayListClass.getSuperclass();
System.out.println(superclass);
while (! "java.lang.Object".equals(superclass.getName())) {
superclass = superclass.getSuperclass();
System.out.println(superclass);
}
}
}

输出:

class java.util.AbstractList

class java.util.AbstractCollection

class java.lang.Object

3.4、获取实现的所有接口

该方法可以获取到该类实现的所有接口。

import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
Class<ArrayList> arrayListClass = ArrayList.class;
Class<?>[] interfaces = arrayListClass.getInterfaces();
for(Class clazz: interfaces){
System.out.println(clazz.getName());
}
}
}

输出如下:

java.util.List

java.util.RandomAccess

java.lang.Cloneable

java.io.Serializable

全部评论
根据参数列表,获取对应的构造方法这个遇见过
点赞 回复 分享
发布于 2023-03-29 15:00 四川

相关推荐

(黑话警告⚠️:hc=岗位数量,&nbsp;mt=导师,&nbsp;ld=直属领导,&nbsp;cr=代码审查)25年1月,我加入了字节某前端团队,并期望能在这里待到秋招并尝试转正。然而,就在上周,ld&nbsp;找我1v1,告诉我,我的能力和团队预期不太匹配,并和我劝退。晴天霹雳吗?肯定是有的。那一刻,脑子里嗡嗡作响,各种情绪翻涌。但冷静下来想想,这几个月,自己在能掌控的范围内,确实有不少地方做得不尽如人意。所以,我想把这段不算成功的经历复盘一下,希望能给同样在努力转正的你提个醒,避开我踩过的坑。一、ld&nbsp;的要求要注意刚进组时,ld就和我聊过转正的事。我当时发问:“咱们这儿有hc&nbsp;吗?”&nbsp;ld没直接回答,只是说:“看能力,能力到了...
牛客上的彭于晏:过来人告诉你,入职后要做的第一件事儿不是说主动找活儿做,你要先学会融入团队,摸清ld的性格,投其所好。然后才是展示你的能力,能力上可以说技术或者业务,以业务能力为主,技术能力为辅。优先保证自己对业务需求的开发保证质量效率,然后再谈技术的问题,不要你觉得啥啥啥不行就想着整体优化了(发现校招生最喜欢干这事儿),我工作快5年了发现搞这种的最后都没啥好的结果,产出没有还引入新的bug,校招或者实习的水平看到的问题别人看不到嘛?为什么别人不去搞?浪费时间还没收益的事儿不要去做,技术上的能力体现在对于一个新需求,在不符合现在业务发展的架构设计上,你能拿出好的技术方案同时能考虑到后续业务发展逐渐将技术架构引入合理的架构,这是一个漫长的过程而不是一次性的
点赞 评论 收藏
分享
05-26 09:07
已编辑
门头沟学院 Java
点赞 评论 收藏
分享
04-13 18:10
门头沟学院 Java
想熬夜的小飞象在秋招:被腾讯挂了后爸妈以为我失联了
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客企业服务