Java中的反射
目录
一、认识反射
1、反射的概念
2、反射的作用
3、反射相关的类
二、反射的使用
1、Class类
2、调用类中的私有构造方法
3、使用类中的私有成员变量
4、调用类中的私有成员方法
三、反射的优点和缺点
1、优点
2、缺点
一、认识反射
1、反射的概念
Java的反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法;对于任意一个对象,都能够调用它的任何方法和属性。这种动态获取类的信息以及动态调用方法的功能称为Java语言的反射(reflection)机制。
2、反射的作用
Java程序中一些对象在运行时会出现两种类型:运行时类型和编译时类型,例如一个向上转型的代码:Bird bird = new Animal();其中,bird在编译时类型为Bird,运行时类型为Animal,通过反射机制就能在程序运行时发现该对象和类的真实信息。
3、反射相关的类
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量/字段 |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
二、反射的使用
1、Class类
在反射之前,我们需要先拿到当前需要反射的类的Class对象,然后通过Class对象调用相关的方法,来达到反射的目的。
获得Class对象的三种方式:
(1)使用Class.forName方法("类的全路径名");
(2)使用需要反射的类名调用class方法;
(3)使用需要反射的类的对象调用getClass方法
但是通过三种方式获取的Class对象都是相同的,也就是说,一个类只有一个对应的Class对象:
Class类中常用获得类相关的方法 | |
---|---|
方法 | 作用 |
getClassLoader() | 获得类的加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 |
forName(String classRoad) | 根据类的路径返回类的Class对象(该方法是静态成员方法) |
newInstacne() | 创建类的实例 |
getName() | 获得类的完整路径名 |
2、调用类中的私有构造方法
获得类中构造器相关的方法(返回值为Constructor类型相关)
方法 | 作用 |
getConstructor(Class...<?>parameterTypes) | 获得该类中与参数类型匹配的公有的构造方法 |
getConstructors() | 获得该类中所有公有的构造方法 |
getDeclaredConstructor(Class...<?>parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类中所有构造方法 |
示例:
创建一个Student类:
public class Student {
public String name;//公共的成员变量
private int id = 1;//私有的成员变量
public Student(){
System.out.println("公共的构造方法");
}
private Student(int id){
this.id = id;
System.out.println("私有的构造方法");
}
public void func(){
System.out.println("公共的成员方法");
}
private void func2(String s){
System.out.println(s);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
在同一个包中的Test类中通过Student类私有的构造方法创建一个Student对象:
public class Test {
public static void reflectPrivateConstructor(){
try {
//获得Class对象
Class<?> c1 = Class.forName("reflect.Student");
//调用getDeclaredField(String name)方法
Constructor<?> constructor = c1.getDeclaredConstructor(int.class);
//调用setAccessible(boolean)后可修改访问权限
constructor.setAccessible(true);
//通过Constructor对象创建Student对象
Student student = (Student) constructor.newInstance(100);
//输出创建好的Student对象
System.out.println(student);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws ClassNotFoundException {
reflectPrivateConstructor();
}
}
代码运行结果:
3、使用类中的私有成员变量
获得类中字段相关的方法(返回值为Field类型相关)
方法 | 作用 |
getField(String name) | 获得该类中某个公有的字段 |
getFields() | 获得该类中所有公有的字段 |
getDeclaredField(String name) | 获得该类中某个字段 |
getDeclaredFields() | 获得该类中所有字段 |
示例:
反射Student类中的私有成员变量
public class Test {
public static void reflectPrivateField(){
try {
//获得Class对象
Class<?> c1 = Class.forName("reflect.Student");
//getDeclaredField(String name)方法
Field field = c1.getDeclaredField("id");
//调用setAccessible(boolean)后可修改访问权限
field.setAccessible(true);
//通过Class类反射一个Student对象
Student student = (Student) c1.newInstance();
//修改指定Student对象的静态成员变量:id = 500
field.set(student,500);
//输出Student对象
System.out.println(student);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
reflectPrivateField();
}
}
代码运行结果:
4、调用类中的私有成员方法
获得类中方法相关的方法(返回值为Method类型相关)
方法 | 作用 |
getMethod(String name,Class...<?>parameterTypes) | 获得该类中某个公有的方法 |
getMethods() | 获得该类中所有公有的方法 |
getDeclaredMethod(String name,Class...<?>parameterTypes) | 获得该类中某个方法 |
getDeclaredMethods() | 获得该类中所有方法 |
示例:
反射Student类中的私有成员方法
public class Test {
public static void reflectPrivateMethod(){
try {
//获得Class对象
Class<?> c1 = Class.forName("reflect.Student");
//调用getDeclaredMethod(String name,Class...<?>parameterTypes)方法
Method method = c1.getDeclaredMethod("func2",String.class);
//获取私有的属性或方法一般都要调用setAccessible(boolean)方法
method.setAccessible(true);
//通过Class类反射一个Student对象
Student student = (Student) c1.newInstance();
//Method对象调用invoke方法
//让指定的Student对象调用指定的私有方法并传参
method.invoke(student,"通过反射机制调用Student类的私有方法");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
reflectPrivateMethod();
}
}
代码运行结果:
三、反射的优点和缺点
1、优点
(1)对于任意一个类,都能够获得这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
(2)增加程序的灵活性和扩展性,降低耦合性。
2、缺点
(1)使用反射会导致程序效率降低(为了获得一个类的对象,调用了Class类中的多个方法);
(2)反射机制绕过了源代码,可能会带来维护问题。