-
什么是反射
> 反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型的对象。(程序集包含模块,而模块包含类型,类型又包含成员。)
对于JAVA,反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 -
反射的作用
1、反射提高了程序的灵活性和扩展性。
2、降低耦合性,提高自适应能力。
3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
- java的Class类
众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。
Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。如果您想借由“修改Java标准库源码”来观察Class 对象的实际生成时机(例如在Class的constructor内添加一个println()),这样是行不通的!因为Class并没有public constructor。
与Java反射相关的类如下:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
以下为Class源码片段:
public final class Class<T> implements Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
private Class() {}
public String toString() {
return ( isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
- Class对象的三种获取方式:
先创建一个demo类
public class ClassDemo {
public int i = 0;
protected Object o = new Object();
private float f = 1.0f;
String str = "hello";
ClassDemo(){
}
private ClassDemo(String s){
str = s;
}
public float getF() {
return f;
}
protected void setF(float f) {
this.f = f;
}
public void print(){
System.out.println("print "+str);
}
private void printS(String s){
System.out.println("print "+s);
}
}
然后获取其Class对象
@Test
public void test1() throws ClassNotFoundException {
Class c1 = Class.forName("com.aliencat.ClassDemo");//1
Class c2 = ClassDemo.class;//2
ClassDemo demo = new ClassDemo();
Class c3 = demo.getClass();//3
//还有一种特殊方式 运用primitive wrapper classes的TYPE 语法
Class c4 = Integer.TYPE;
}
- Class对象的功能
创建实例
@Test
public void test2() throws IllegalAccessException, InstantiationException {
Class<ClassDemo> c2 = ClassDemo.class;
ClassDemo classDemo = c2.newInstance();
}
获取对象属性
@Test
public void test3() throws NoSuchFieldException, IllegalAccessException {
ClassDemo classDemo = new ClassDemo();
Class c2 = classDemo.getClass();
//获取所有属性
Field[] declaredFields = c2.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field.toString());
System.out.println("变量名-->" + field.getName() + " 访问修饰符-->" + field.getModifiers() + " 属性类型-->" + field.getType());
}
System.out.println("-----------------------");
//通过下面这个方法可以获取指定变量名的public属性
Field field = c2.getField("i");
System.out.println(field.toGenericString());
//得到对象的此属性值
System.out.println("i原来的值:" + field.get(classDemo));
//修改此对象的此属性值
field.set(classDemo, 2);
System.out.println("i修改后的值:" + field.get(classDemo));
Field field2 = c2.getDeclaredField("f");
/*如果不调用setAccessible(true)则会抛出下列异常
* java.lang.IllegalAccessException: Class com.aliencat.testclass.ClassTest can not access a member of class com.aliencat.testclass.ClassDemo with modifiers "private"
*/
field2.setAccessible(true);
System.out.println("获取私有属性f:" + field2.toGenericString());
System.out.println("f原来的值:" + field2.get(classDemo));
//修改此对象的此属性值
field2.set(classDemo, 2);
System.out.println("f修改后的值:" + field2.get(classDemo));
}
结果如下:
获取对象方法:
@Test
public void test4() throws InvocationTargetException, IllegalAccessException {
ClassDemo classDemo = new ClassDemo();
Class c2 = classDemo.getClass();
Method[] methods = c2.getDeclaredMethods();
for(Method method : methods){
//0代表default,1代表public,2代表private,4代表protected
System.out.println("访问权限:"+method.getModifiers()+" 返回类型:"+method.getReturnType()+" 方法名:"+method.getName());
if(method.getModifiers()==2) {
//因为printS()为private,所以需要加入下面这句获取访问权限
method.setAccessible(true);
//invoke方法可以执行这个方法的动作
method.invoke(classDemo, "这是反射的打印结果");
}
}
}
结果如下:
- 当然还可以用Class的getDeclaredConstructors()方法获取所以构造方法以及通过getDeclaredAnnotations()获取注解等等,这里我就不再累述。
- Class类提供了大量的实例方法来获取该Class对象所对应的详细信息,其中每个方法都包含多个重载版本,因此我只是做简单的介绍,详细请参考JDK文档。