Jade Dungeon

反射

Class类

取得Class类

每个类都有的运用getClass()方法。可以在实例上调用:

String str = "abc";
Class c1 = str.getClass();

取得超类Class.getSuperclass()

Button b = new Button();
Class c1 = b.getClass();
Class c2 = c1.getSuperclass();

静态方法Class.forName()

Class c1 = Class.forName("java.lang.String");
Class c2 = Class.forName("java.awt.Button");
Class c3 = Class.forName("java.util.LinkedList$Entry");
Class c4 = Class.forName("I");
Class c5 = Class.forName("[I");

.class语法:

Class c1 = String.class;
Class c2 = java.awt.Button.class;
Class c3 = Main.InnerClass.class;
Class c4 = int.class;
Class c5 = int[].class;

运用primitive wrapper classesTYPE语法:

Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Character.TYPE;
Class c4 = Short.TYPE;
Class c5 = Integer.TYPE;
Class c6 = Long.TYPE;
Class c7 = Float.TYPE;
Class c8 = Double.TYPE;
Class c9 = Void.TYPE;

基本类型

  • 基本类型的class和其对应包装类的class是不同的,所以在获得Method指定参数的时候 ,需要精确指定参数的类型,即setInt(int x)无法使用 getMethod("setInt",Integer.class)获得。
  • 基本类型的class无法通过Class.forName方法获得,可以通过类型名.class或者 对应包装类的静态字段TYPE获得。若要动态获得基本类型的class,可以考虑把class 存进一个Map中进行读取。
  • 基本类型class的泛型参数使用对应的包装类进行指定。例如: Class<Integer> clazz = int.class;
private static final Map<String, Class<?>> primitiveClazz; // 基本类型的class  
  
private static final String INTEGER = "Integer";  
private static final String BYTE = "Byte";  
private static final String CHARACTOR = "Charactor";  
private static final String SHORT = "Short";  
private static final String LONG = "Long";  
private static final String FLOAT = "Float";  
private static final String DOUBLE = "Double";  
private static final String BOOLEAN = "Boolean";  
  
static  {  
    primitiveClazz = new HashMap<String, Class<?>>();  
    primitiveClazz.put(INTEGER, int.class);  
    primitiveClazz.put(BYTE, byte.class);  
    primitiveClazz.put(CHARACTOR, char.class);  
    primitiveClazz.put(SHORT, short.class);  
    primitiveClazz.put(LONG, long.class);  
    primitiveClazz.put(FLOAT, float.class);  
    primitiveClazz.put(DOUBLE, double.class);  
    primitiveClazz.put(BOOLEAN, boolean.class);  
}  

取得类信息

类的内部模块 说明 API 返回类型
package 类隶属哪个包 getPackage() Package
import 类导入哪些类 无直接对应之API。 可间接获取。 void
modifier 类的方法与字段 int getModifiers() int
Modifier.toString(int) String
Modifier.isInterface(int) bool
类名或接口名 class/interface 名称getName() String
参数类型 参数化类型的名称 getTypeParameters() TypeVariable <Class>[]
基础粝 base class(只可能一个) getSuperClass() Class
已实现接口 实现有哪些interfaces getInterfaces() Class[]
内部类 内部classes getDeclaredClasses() Class[]
外部类 内部类一定会有外部类 getDeclaringClass() Class

构造函数

从Class类中取得构造函数

通过指定参数类型返回确定的构造函数:

Constructor getConstructor(Class[] params) 

Constructor getDeclaredConstructor(Class[] params) 

获取所有的构造函数:

Constructor[] getConstructors()

Constructor[] getDeclaredConstructors()

创建对象

调用默认无参构造函数

Class cls = Class.forName("className");
inst =  cls.newInstance();

在java1.9版本中,newInstance()已经被弃用,取而代之的是

class.getDeclaredConstructor().newInstance()

class.newInstance()会直接调用该类的无参构造函数进行实例化

getDeclaredConstructor()方法会根据他的参数对该类的构造函数进行搜索并返回对应的构造函数,没有参数就返回该类的无参构造函数,然后再通过newInstance进行实例化。

来个实例:

public class Test {
    public Test() {
        System.out.println("HelloTest");
    }
    public static void main(String[] args) throws Exception {
        C c = C.class.getDeclaredConstructor(int.class).newInstance(5);    
    }
}

class C {
    public C() {}
    private C(int i) {
    	System.out.println("HelloC" + i);
    }
    
}

class.getDeclaredConstructor().newInstance()方法会传播由空构造函数引发的任何异常, 包括已检查的异常。老方法绕过了编译时异常检查,编译器不会检查到。

使用构造函数

通过前面得到构造函数类Constructor<T>,成员方法:

T newInstance(Object... args)

其中args为对应的参数。

成员函数

从Class类中取得成员函数

和获取构造函数的方法类似,获取成员函数的方法有以下一些:

Method getMethod(String name, Class[] params)

Method[] getMethods()

Method getDeclaredMethod(String name, Class[] params) 

Method[] getDeclaredMethods() 

其中需要注意,String name参数,需要写入方法名。关于访问权限和确定性的问题,和 构造函数基本一致。

调用方法

Method类的成员方法:

public Object invoke(Object receiver, Object... args)

第二个参数args明显是参数列表。

第一个参数reveiver就是成员函数所调用的对象。如果是静态方法,可以为空。

receiver的存在是有历史原因的:在非面向对象语言中,没有obj.func()的。以C语言 实现Java来说,相当于用一个参数来表明现在调用的是哪一个对象的成员方法。

所以obj.func()其实是有隐含参数的,那就是object对象的指针,method原型的第一个 参数其实是this指针,于是原型为method(void* this)

成员属性

通过Class取得成员属性

获取成员变量的方法与上面两种方法类似,具体如下:

Field getField(String name)

Field[] getFields()

Field getDeclaredField(String name)

Field[] getDeclaredFields()

其中,String name参数,需要写入变量名。关于访问权限和确定性的问题,与前面两例 基本一致。

操作成员属性

public Object get(Object object)

public void set(Object object, Object value)

object参数需要传入的对象,原理类似于成员方法需要指明对象一样。如果是静态属性, 同样可以为null。

其他

  • Java反射中对数组做过单独的优化处理,具体可查看java.lang.reflect.Array类;
  • 还有关于泛型的支持,可查看java.lang.reflect.ParameterizedType及相关资料。