Class与java.lang.refect类库一起对反射提供了支持,该类库包含Field、Method、Constructor类(都实现了Member接口)。这些类型的对象由JVM在运行时创建,表示未知类中的成员。可以用Constructor创建新对象,get()和set()读取修改字段,invoke方法调用方法。
构造器信息
- public Constructor<?>[] getDeclaredConstructors()
getDeclaredConstructors()是返回一个构造器数组
注意getDeclaredConstructors()和getConstructors()的区别,getDeclaredConstructors()可显示私有方法,getConstructors()只能显示公有方法。在后面的示例中也是,如此若想调用私有方法、构造器、域,都得加上Declared。
class cTest{
String str;
int i;
private cTest(){
}
private cTest(String str) {
this.str = str;
}
public cTest(int i) {
this.i = i;
}
public cTest(String str, int i) {
this.str = str;
this.i = i;
}
}
class Test{
public static void main(String[] args) {
Constructor[] ctors=cTest.class.getDeclaredConstructors();
for(Constructor ctor:ctors)
System.out.println(ctor);
}
}
//output:
//private cTest(java.lang.String)
//public cTest(int)
//public cTest(java.lang.String,int)
//private cTest()
调用公有构造器
- public Constructor getConstructor(Class<?>… parameterTypes)
- public T newInstance(Object … initargs)
getConstructor()得到构造器,以Class[]为参数,标识某个具体构造器,返回这个构造器
newIntance()利用得到的构造器创建实例,传入构造器对应的参数
Class[] parameters={String.class,int.class};
Constructor ctor=cTest.class.getConstructor(parameters);
ctor.newInstance("a string",1);
调用私有构造器
Class[] parameters={String.class};
Constructor ctor=cTest.class.getDeclaredConstructor(parameters);
ctor.setAccessible(true);
ctor.newInstance("a");
域信息
class fTest{
private final int a=1;
private int b=2;
public int c=3;
}
class Test{
public static void main(String[] args) throws Exception{
Field[] fields=fTest.class.getDeclaredFields();
for(Field field:fields)
System.out.println(field);
}
}
//output:
//private final int fTest.a
//private int fTest.b
//public int fTest.c
修改私有域
- public Field getDeclaredField(String name)
- public void set(Object obj, Object value)
- public Object get(Object obj)
首先getDeclaredField()获取一个域,一个String参数域名
Field.set()设置Field域的值,需要和某个特定对象关联起来,因此接受两个参数,第一个是对象,第二个是你想设置的值
Field.get()返回对象的Field域值,也需要和某个特定对象关联。
可以看出甚至是编译期常量private final都可以修改
fTest f=new fTest();
Field field=fTest.class.getDeclaredField("a");
field.setAccessible(true);
field.set(f,10);
System.out.println(field.get(f));
方法信息
class mTest{
public void f(String a){}
private Object g(String a,int b) {
return null;
}
}
class Test{
public static void main(String[] args) throws Exception{
Method[] methods=mTest.class.getDeclaredMethods();
for(Method method:methods)
System.out.println(method);
}
}
//output:
//public void mTest.f(java.lang.String)
//private java.lang.Object mTest.g(java.lang.String,int)
调用私有方法
- public Method getDeclaredMethod(String name, Class<?>… parameterTypes)
- public Object invoke(Object obj, Object… args)
getDeclaredMethod()返回一个方法,需要两个参数,第一个是方法名,第二个是方法参数Class数组
Method.invoke()指行对象上的方法,需要域特定对象关联,因此第一个参数是对象,第二个是传入方法的参数
你看这里传入参数的方式是不是很方便⊙0⊙ ⊙0⊙。
mTest m=new mTest();
Method method=mTest.class.getDeclaredMethod("g",new Class[]{String.class,int.class});
method.setAccessible(true);
method.invoke(m,new Object[]{"String",1});
反射对接口的破坏
interface通常用于隔离构建,降低耦合,但这种降低耦合的方式可以被破坏。
一种是基于RTTI的运行是类型检查的合理转型,另一种是反射
getDeclaredMethod是Class类的方法,以Class对象的方法名为参数
interface A{
void f();
}
class B implements A{
public void f() { }
public void g() { }
public static void main(String[] args) throws Exception {
A a=new B();
// Error:a.g();
//方法一
if(a instanceof B) {
B b = (B) a;
b.g();
}
//方法二
Method method=a.getClass().getDeclaredMethod("g");
method.setAccessible(true);
method.invoke(a);
}
}