目录
Class类中的相关方法
反射的使用示例
获取Class对象
反射构造方法
反射属性
反射私有方法
反射的优点和缺点
本篇博客所有的代码已上传至gitee中:反射代码
反射
反射的定义
Java反射机制是在运行状态中,对于任意一个类,都能够知道知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,也可以修改部分类型的信息,这种动态获取信息以及动态调用对象的方法的功能称为Java的反射机制.
反射的应用
①当遇到某个类的成员变量、成员方法或属性是私有属性的时候,我们可以利用反射来获取所需的私有成员变量和方法;
②反射最重要的用途是开发各种通用框架.
反射相关的类
类名 | 作用 |
Class类 | 代表类的实体,在运行的Java程序中表示类和接口 |
Filed类 | 代表类的成员变量/成员属性 |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
Class类中的相关方法
Class类是反射机制的起源,代表类的实体,在运行的Java应用程序中表示类和接口
常用获得类的相关方法
方法 | 用途 |
getClassLoader() | 获得类的加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有的类和接口类的对象(包括私有的) |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getName() | 获得类的完整路径名字 |
常用获得类中属性的相关方法(以下方法返回值为Filed相关)
方法 | 用途 |
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
获得类中构造器相关的方法(以下方法返回值为Constructor相关)
获得类中方法相关的方法(以下返回值为Method相关)
方法 | 用途 |
getMethod(String name, Class...<?> parameterTypes) | 获得该类某个公有方法 |
getMethods() | 获得该类所有的公有方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) | 获得该类的某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
反射的使用示例
首先创建一个Student类,其中包含私有属性、公有属性、私有方法、公有方法,利用反射来获取其中的私有变量和方法.
public class Student {
//私有属性name
private String name = "bit";
//共有属性age
public int age = 18;
//不带参数的构造方法
public Student() {
System.out.println("Student()");
}
//带参数的私有构造方法
private Student(String name, int age) {
this.age = age;
this.name = name;
System.out.println("Student(String,int)");
}
//不带参数的私有方法
private void eat() {
System.out.println("I am eat");
}
public void sleep() {
System.out.println("I am sleeping");
}
//带参数的私有方法
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
获取Class对象
方法1:通过getClass来获取Class对象;
方法2:通过.class来获取
方法3:通过Class类的静态方法forName()来获取
具体获取方式如下述代码所示:
public static void main(String[] args) throws ClassNotFoundException {
//1、通过getClass获取Class对象
Student s1 = new Student();
Class<?> c1 = s1.getClass();
//2、利用.class获取
Class<?> c2 = Student.class;
//3、通过Class类的静态方法forName()来获取
Class<?> c3 = Class.forName("reflectdemo.Student");
System.out.println(c1.equals(c2));
System.out.println(c2.equals(c3));
System.out.println(c1.equals(c3));
//Class对象只有一个
}
注:无论利用什么方法来获取Class对象,Class对象都只有一个.通过下述输出可以说明,分别利用三种不同的方法获得Class对象c1、c2、c3,最终通过对比,c1与c2与c3都相等,因此说明Class对象只有一个.
反射构造方法
在反射私有构造方法之前需要获取对象、然后获取与该参数类型匹配的构造方法,获取之后对其授权,授权后就可以使用该私有的构造方法.
注:在整个反射过程中都需要进行捕获异常,原因是不确定是否有该类、该构造方法,因此需要对其进行异常处理
//反射私有的构造方法 屏蔽内容为获得公有的构造方法
public static void reflectPrivateConstruct() {
try {
//获取对象
Class<?> c1 = Class.forName("reflectdemo.Student");
//获得该类中与参数类型匹配的构造方法
Constructor<?> constructor =
c1.getDeclaredConstructor(String.class,int.class);
/*如果方法是 private修饰的,当你用反射去访问的时候
setAccessible(true)之后才能访问,相当于授权
*/
constructor.setAccessible(true);
Student student = (Student)constructor.newInstance("lyz",19);
System.out.println(student);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
测试结果
反射属性
在反射属性之前需要获取对象、然后获取相关的属性,获取之后对其授权,授权后就可以对其进行修改了.整个过程中需要对异常进行处理,原因与反射构造方法一样.
//反射所有的属性,以私有属性为例
public static void reflectPrivateFiled() {
try {
Class<?> c1 = Class.forName("reflectdemo.Student");
Student student = (Student)c1.newInstance();
Field field = c1.getDeclaredField("name");
field.setAccessible(true);
field.set(student,"张三");
System.out.println(student);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
测试结果
反射私有方法
//反射私有方法
public static void reflectPrivateMethod() {
try {
Class<?> c1 = Class.forName("reflectdemo.Student");
Student student = (Student)c1.newInstance();
//方法的名称 方法的参数
Method method = c1.getDeclaredMethod("function", String.class);
method.setAccessible(true);
method.invoke(student,"我是function的参数");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
测试结果
反射的优点和缺点
优点:
1.对于任意一个类,都能够获得这个类中的方法和属性;对于任意一个对象,都能够调用它的任意一个方法;
2.增加程序的灵活性和可扩展性;
3.反射在各种框架中的使用十分广泛.
缺点:
1.使用反射会可能导致效率变低;
2.反射绕过了源代码的技术,可能会带来维护问题.