JAVA反射机制是在运行状态中,动态获取的类的所有信息以及动态调用对象的方法(或属性),称为java语言的反射机制。
注意:反射是在运行的时候进行的,不是在编译的时候运行的。
反射的功能
Java反射机制主要提供了以下功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;生成动态代理。
API简介
在这里先看一下sun为我们提供了那些反射机制中的类:
— java.lang.Class; 代表一个类
— java.lang.reflect.Constructor; 代表类的构造方法
— java.lang.reflect.Field; 代表类的成员变量(成员变量也称为类的属性)
— java.lang.reflect.Method; 代表类的方法
— java.lang.reflect.Array; 提供了动态创建数组,以及访问数组的元素的静态方法
注意:java中无论生成某个类的多少对象, 这些对象都会对应于同一个Class对象。
方法介绍
方法关键字 | 含义 |
getDeclaredMethods() | 获取所有的方法 |
getReturnType() | 获得方法的放回类型 |
getParameterTypes() | 获得方法的传入参数类型 |
getDeclaredMethod("方法名",参数类型.class,……) | 获得特定的方法 |
构造方法关键字 | 含义 |
getDeclaredConstructors() | 获取所有的构造方法 |
getDeclaredConstructor(参数类型.class,……) | 获取特定的构造方法 |
父类和父接口 | 含义 |
getSuperclass() | 获取某类的父类 |
getInterfaces() | 获取某类实现的接口 |
获取Class的三种方式
1)使用Class类的forName(String className)静态方法。改方法需要传入字符串参数,改字符串参数的值是某个类的全限定类名(必须添加完整的包名)。
Class.forName("java.lang.String");
2)调用某个类的class属性来获取该类对应的class对象,如
String.class
3)调用某个对象的getClass方法。
String s = "aa"; Class<?> clazz = s.getClass();
生成对象
1)通过不带参数的构造方法生成对象有两种方法
a)先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:
newInstance()方法可以返回一个实例,但是构造方法要是没有参数列表的,它相当于调用某个类的不带参数的构造方法,但是如果在初始化对象的时候要传参数,就要使用Constructor
Class<?> classType = String.class;
Object obj = classType.newInstance();
b)先获得Class对象,然后通过该对象获得相应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:
Class<?> classType = object.getClass();
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
2)若想通过类的带参数的构造方法生成对象,只能使用下面一种方式
Class<?> classType = object.getClass();
Constructor cons = classType.getConstructor(new Class[]{String.class,int.class});
Object obj = cons.newInstance(new Object[]{"hello",3});
//以上的两行代码等价于下面一行
//Object obj2 = classType.newInstance();
反射访问私有(private)的方法
private 限制的方法没有办法在另外的类中使用,但可以使用反射进行使用。而getMethod()方法只能获取public的方法。如果要使用private的方法就要使用 getDeclaredMethod()方法。
1、获取privete方法
public class PrivateTest {
private String sayHello(String name){
return "hello" + name;
}
}
public class Test{
public static void main(String[] args) throws Exception{
PrivateTest obj = new PrivateTest();
Class<?> classType = obj.getClass();
Method method = classType.getDeclaredMethod("sayHello", new Class[]{String.class});
method.setAccessible(true); //压制java的访问控制检查
String str = (String)method.invoke(obj, new Object[]{"aaa"});
}
}
2、改变private的属性
public class PrivateTest2 {
private String name = "张三";
public String getName(){
return name;
}
}
public class Test{
public static void main(String[] args) throws Exception{
PrivateTest2 obj = new PrivateTest2();
Class<?> classType = obj.getClass();
Field field = classType.getDeclaredField("name");
field.setAccessible(true);
field.set(obj, "李四");
System.out.println(obj.getName());
}
}
反射机制的优点与缺点
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
- 静态编译:在编译时确定类型,绑定对象,即通过。
- 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
优点——可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中。
比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
缺点——对性能有影响。
使用反射基本上是一种解释操作,这类操作总是慢于只直接执行相同的操作。