深入剖析Java的反射机制
一、反射机制的具体概念表述:
关于反射:在计算机领域,反射指的是一种能够自我描述以及自我控制的应用。
引用维基百科的解释:
在计算机学中,反射(英语:reflection)是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
要注意术语“反射”和“内省”(type introspection)的关系。内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。
反射机制简介:主要是指,程序可以访问、检测和修改它本身状态活性位的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
二、Java反射机制的用途:
1,反编译:.class–>.java
2,通过反射机制访问java对象的属性,方法,构造方法等;
1).判断任意一个对象所属的类;
2).构造任意一个类的对象;
3).判断任意一个类所具有的成员变量和方法;
4).调用任意一个对象的方法;
5).生成动态代理。
3, 基本运用:
3.1 获取Class对象:
1)使用Class类的forName静态方法;
2)直接获取一个对象的class;
3)调用某个对象的getClass()方法。
3.2 判断是否为某个类的实例:
——关键字instanceof
——方法isInstance():是一个native方法(一个java调用非java代码的接口)
private native boolean isInstance(Object obj);
3.3 创建实例:
1)使用Class对象的newInstance()方法进行创建:
Class<?> c = String.class;
Object str = c.newInstance();
Class c3 = user.getClass();
Object obj = c3.newInstance();
2) 通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);
3.4获取方法:
1)getDeclaredMethods() 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。返回的是一个Method类型的数组。
方法声明:
public Method[] getDeclaredMethods() throws SecurityException
使用案例:
Class c1 = Class.forName("com.jyk.Entity.User");
Method[] methods = c1.getDeclaredMethods();
for (Method m: methods
) {
System.out.println(m);
}
2)getMethods方法返回某个类的所有公用方法(public),包括其继承类的公用方法。(可以获取到父类的方法)
方法声明:
public Method[] getMethods() throws SecurityException
使用案例:
Method[] methods1 = c1.getDeclaredMethods();
for (Method m:methods1
) {
System.out.println(m);
}
3)getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应的Class对象。
方法声明:
public Method getMethod(String name, Class<?>... parameterTypes)
使用案例:
Method method2 = c1.getMethod("setUserAge", String.class);
System.out.println(method2);
3.5 获取类的构造器信息getConstructor()——根据反射获得的类构造器信息创建实例newInstance():
Constructor[] methods2 = c1.getConstructors();
for (Constructor c:methods2
) {
System.out.println(c);
}
public T newInstance(Object... initargs)
3.6 获取类的成员变量(字段)信息:
主要方法:
getFiled():访问共有的成员变量
getDeclaredFiled():所有已声明的成员变量,但不能得到其父类的成员变量。
Field[] f = c.getDeclaredFields();
StringBuffer s = new StringBuffer();
s.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + "{\n");
for (Field ff : f) {
s.append("\t");
s.append(Modifier.toString(ff.getModifiers()) + " ");
s.append(ff.getType().getSimpleName() + " ");
s.append(ff.getName() + ";\n");
}
s.append("\n}");
System.out.println(s);
3.7 调用方法:
使用invoke()方法来调用从类中获得的方法:
invoke()方法原型:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
使用实例:
public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}
3.8利用反射创建数组:
原理说明:以获取到的类为参数创建一个Array类对象,向该对象中添加新元素。
public static void testArray() throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");
Object array = Array.newInstance(cls,25);
//往数组里添加内容
Array.set(array,0,"hello");
Array.set(array,1,"Java");
Array.set(array,2,"fuck");
Array.set(array,3,"Scala");
Array.set(array,4,"Clojure");
//获取某一项的内容
System.out.println(Array.get(array,3));
}
Array类原型:java.lang.reflect.Array类
public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}
三、反射机制主要涉及的类和方法:
四、主要方法:
主要涉及的方法基本上已经在上文介绍过。
五、反射机制的优缺点:
优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
(2)与Java动态编译相结合,可以实现无比强大的功能
缺点:
(1)使用反射会额外消耗一定的系统资源,性能较低 ,如果不需要动态地创建对象,那么就不需要使用反射。
(2)使用反射会忽略权限检查,破坏了封装性,相对来说不安全