反射

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值