反射
java反射机制:
-
反射是一种动态机制,允许java程序运行期间再确定对象的实例化,方法的调用,属性的操作等。
-
反射可以提高代码的灵活性,但是会有更多的性能开销和较低的运行效率。因此不能过度依赖反射
Class类
- 称为类的类对象
- JVM中每个被加载的类都有且只有一个Class的实例与之对应,通过获取一个类的类对象我们可以得知
这个类的一切信息,比如类名,有哪些方法,属性,构造器等,并且可以动态的操作它们。
反射的第一步就是获取类对象,而获取一个类的类对象有三种方式
- 类名.class
Class cls = String.class;
Class cls = int.class
常用方法:
// 测试String
Class cls = String.class;
String name = cls.getName(); // 获取类对象的名称
System.out.println(name); // java.lang.String
// 通过类对象获取所有的方法(返回Method[])
Method[] methods = cls.getMethods();
for(Method method : methods) {
System.out.println(method.getName());
}
- Class.forName(String className)
Class cls = Class.forName(“java.lang.String”); // java.lang是包名,String是类名
示例:
Class cls = Class.forName(“raflect.Person”); // 自己定义的类,raflect是包名
// 获取当前类自己定义的所有方法(不含有继承的)
Method[] methods = cls.getDeclaredMethods(); // 自己定义的类用getDeclaredMethods()方法
3.类加载器ClassLoader
第二步:实例化
- 反射实例化:要求必须有无参构造器
示例:
// 1.获取类对象
Class cls = Class.forName("raflect.Person");
// 2.实例化(此种方式实例化要求必须有无参构造器)(这里不能用Person去接收的)
Object obj = cls.newInstance();
System.out.println(obj);
第三步:利用反射机制调用方法(有参数/无参数)(反射可以调用外部私有方法,不推荐这么做)
示例:
// 1.获取类对象
Class cls = Class.forName("raflect.Person");
// 2.实例化
Object o = cls.newInstance();
// 3.1调用方法(无参数)
Method method = cls.getMethod("sayHi");
method.invoke(o); // 把o这个对象传过去
// 3.2调用有参构造方法
Method m1 = cls.getMethod("sayHi",String.class);
m1.invoke(o, "张三");
Method m2 = cls.getMethod("sayHi", String.class,int.class);
m2.invoke(o, "李四",22);
// 利用反射在类的外部调用其私有方法
Method m3 = cls.getDeclaredMethod("dosome");
m3.setAccessible(true); // 强制访问(不推荐这么做)
m3.invoke(o);
示例:
reflect
包下的A
类
package reflect;
public class A {
public void f1() {
System.out.println("A.f1()");
}
public String f2() {
System.out.println("A.f2()");
return "Hello f2";
}
public String bala(String msg, int qty) {
System.out.println("A.bala()");
return "bala" + msg + " " + qty;
}
}
reflect
包下的B
类
package reflect;
public class B {
public void f1() {
System.out.println("B's f1()");
}
public void testF2() {
System.out.println("B's testF2()");
}
public void hello() {
System.out.println("B's hello()");
}
}
reflect
包下的ReflectTest
类
package reflect;
import java.lang.reflect.Method;
import java.util.Scanner;
public class ReflectTest {
public static void main(String[] args) throws Exception {
// 通过控制台读取类名
Scanner scanner = new Scanner(System.in);
String className = scanner.nextLine();
System.out.println("className:" + className);
// 加载类
Class clazz = Class.forName(className);
// 实例化
Object obj = clazz.newInstance();
System.out.println("obj:" + obj);
/*
* 获得该类的所有方法。
* Method用来描述一个方法(包括方法名、参数类型、返回类型,加在方法前的注解等等)
*/
Method[] methods = clazz.getDeclaredMethods();
// 遍历所有方法
for (Method mh : methods) {
/*
* 我们把要调用的方法称之为目标方法。
* 目标不带参: mh.invoke(obj)
* 目标方法带参:mh.invoke(obj,params),params是一个对象数组,里面存放有实际参数值。
*/
// 先获得目标方法的参数类型信息
Class[] types = mh.getParameterTypes();
// rv是目标方法的返回值。
Object rv = null;
if (types.length == 0) {
// 目标方法不带参
rv = mh.invoke(obj);
} else {
// params用于存放实际参数值
Object[] params = new Object[types.length];
// 依据目标方法的参数类型进行赋值
for (int i = 0; i < types.length; i++) {
if (types[i] == String.class) {
params[i] = "阿里巴巴";
}
if (types[i] == int.class) {
params[i] = 100;
}
}
// 调用目标方法(带参)
rv = mh.invoke(obj, params);
}
System.out.println("rv:" + rv);
}
}
}