java 类的反射_Java类的反射

一、类对象与反射

先来简单介绍一下反射,反射使得程序员能够更加的了解一个类,包括获得构造方法、成员方法、成员域包括注解等。

1.访问构造方法

访问构造方法有四种方式,

getDeclaredConstructors(); 获取所有构造函数,包括public、private等等

getDeclaredConstructor( Class parameterTypes); 获取相应参数类型的构造方法

getConstructors(); 获取所有公有public修饰的构造方法

getConstructor(Class parameterTypes);  获取相应参数类型的公有构造方法

importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.lang.reflect.Modifier;public classRef {private inti;privateString s;publicRef(String s1)

{

s=s1;

}public Ref(inti)

{this.i=i;

}

Ref()

{

i=0;

s="null";

}private Ref(inti1,String s2)

{

i=i1;

s=s2;

}public voidgetString()

{

System.out.println(s);

}public static voidmain(String []args)

{

Class re=Ref.class;try{//Constructors

Constructor [] c= re.getDeclaredConstructors();//所有构造方法

for(Constructor con:c)

System.out.println(con);

System.out.println("-----------------------------------------");

Constructor [] c0= re.getConstructors();//所有公有构造方法

for(Constructor con:c0)

System.out.println(con);

System.out.println("-----------------------------------------");

System.out.println(re.getConstructor(int.class));//所有公有参数为int的构造方法

System.out.println("-----------------------------------------");

System.out.println(re.getDeclaredConstructor(int.class));//参数为int的构造方法

Constructor X=re.getDeclaredConstructor(int.class,String.class);//参数为int和String的构造方法

System.out.println(X.getName());

System.out.println(X.isAccessible());

System.out.println(X.isVarArgs());int mo=X.getModifiers();

System.out.println(Modifier.isStatic(mo));

}catch(Exception e) {

e.printStackTrace();

}

}

c6acac3d8332a79eb88238994c17011e.png

注意参数parameter的形式,应写为int.class或者String.class等。上述方法返回的类型均为Constructor对象,当然它可以直接打印,但是它还有一些其他有趣的方法,getName()直接返回构造函数的名称,而getModifiers()方法返回一个int类型的值,可以用来判断是否含有某个关键字,主要方法如下:

3ed8e35fd3ee5716cb65a740de6e784b.png

72bee5442bfde30292baaa7fe6c45293.png

此外,除了getModifiers()和getName()之外,还有几个不是很重要的Constructor类的方法想在这里展示一下,首先是newInstance()和isAccessible()和setAccessible():

Constructor N=re.getDeclaredConstructor(int.class);//参数为int的构造方法

Constructor X=re.getDeclaredConstructor(int.class,String.class);//参数为int和String的构造方法

System.out.println(N.isAccessible());

System.out.println(X.isAccessible());Ref r1= (Ref)N.newInstance(5);

Ref r2= (Ref)X.newInstance(5,"XX");

r1.getString();

r2.getString();

926920165ef3f3a31c59ea02fbf2db36.png

这地方很诡异,一般的逻辑是通过isAccessible()判断是否能够通过newInstance()申请新的实例对象,如果是true的话可以,false应该是不可以,然后通过setAccessible(true)设置完后就可以了,但是上面的例子不管是public还是private都是false,然后竟然还可以使用newInstance(),惊了。其实newInstance()和new一个对象应该是差不多的,参数类型和个数一定要对上,否则抛异常。所以这里是有一点叉子的,不知道哪里出了问题。

接下来是getParameterTypes()和getExceptionTypes()。

private Ref(int o,String ss) throws IOException,NoSuchMethodException //增加异常

{

i=o;

s=ss;

}/*Constructor - isVarArgs() getParameterTypes() and getExceptionTypes()*/

//System.out.println(X.isVarArgs());

Class [] p=X.getParameterTypes();

Class [] e=X.getExceptionTypes();for(Class x:p)

System.out.println(x);for(Class x:e)

System.out.println(x);

5768d5c024d87dba13b03291f8abdd24.png

结果一目了然可以看出这两个方法是做什么的,不再多说了。

2.访问普通方法和域

实际上,访问方法和域与构造方法十分类似,均是有四种方法,名称也是相似,只不过有getConstructors()等改为getFileds()等和getMethods()等,只不过获取特定对象的参数不同,例如构造函数是要指定参数类型和个数如int.class,但是域是指定名称,方法是指定名称+参数:

importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.lang.reflect.Modifier;public classRef {private inti;privateString s;public static doubled;public voidgetString()

{

System.out.println(i+" "+s);

}public void getString(int j){System.out.println(i+" "+j+" "+s);}public static voidmain(String []args)

{

Class re=Ref.class;try{//methods or fields

System.out.println("-----------------------------------------");

Field [] f=re.getDeclaredFields();for(Field fi:f)

System.out.println(fi);

Field f1= re.getDeclaredField("d");

System.out.println(f1);

System.out.println("-----------------------------------------");

Method[] m=re.getDeclaredMethods();for(Method me:m)

{int mom=me.getModifiers();

System.out.println(Modifier.toString(mom));

}

Method m1= re.getMethod("getString",int.class);

System.out.println(m1);

Method m2= re.getMethod("getString");

System.out.println(m2);

}catch(Exception e) {

e.printStackTrace();

}

}

}

fbd4015850c49ed5182866c62982c623.png

结果与预期一致。

对于方法来说,除了getName()、getParameterTypes()和getExceptionTypes()以及getModifiiers()与构造方法使用方法完全一致,还有getReturnType()和invoke()函数值得一看,其实只看名字就知道是干嘛的了,没错就获得返回值类型和直接调用该方法:

/*Method - invoke() and getReturnType*/Ref rm= newRef();

m1.invoke(rm,15);

Class r=m2.getReturnType();

System.out.println(r);

75427fbc7e259e16c53e698b607f807d.png

需要新实例化一个对象,然后成为invoke的方法的参数(即rm)才能调用......

对于域来说,除了getName()、getModifiers(),还有set()和get()

Ref rm = newRef();

Field f1= re.getDeclaredField("d");

System.out.println(f1);

Field f2= re.getDeclaredField("s");

System.out.println(f2);

System.out.println("the former value of d is "+f1.get(rm));

System.out.println("the former value of s is "+f2.get(rm));

f1.set(rm,5.5);

f2.set(rm,"newer");

System.out.println("the latter value of d is "+f1.get(rm));

System.out.println("the latter value of s is "+f2.get(rm));

0a485b87f5cf814d219d06e383a76978.png

其实除此之外还是有setInt()、getInt()、setFloat()、setBoolean()、getFloat()、getBoolean()方法,但是使用起来并不像set()和get()方法简便,只需要注意类型的转换即可,例如上述代码中f1.set(rm,5.5)可以改成set(rm,5)也是可以的,因为int类型转化为double型没问题。然而使用setInt()时,后面的值类型必须为整型,同样的getInt()也要求该域的类型为整型或者能直接转化为整型的,例如

Field f3 = re.getDeclaredField("i");

System.out.println(f3);

System.out.println("the latter value of d is "+f3.getDouble(rm));

运行没有问题,即使i是整型,也能获得其double型,因为整型可以直接转化为双浮点型。

2567adb2d5f7f652b072c7c9afc06b30.png

但是:

f3.setFloat(rm,5.5f);

System.out.println("the latter value of d is "+f3.get(rm));

将整型成员域设置为float那是不行的,因为float不能直接转化为整型,会有信息损失。结果就是抛出IlleagalArgumentException:

b9f51215b1d4086a10371dc0cbf1b4e1.png

3.获得该类其他信息

比如获得类的包getPackage(),类的名称getName(),继承的类getSuperclass()和实现的所有接口getInterfaces(),除了因为类可以实现多个接口,因此返回的是Class数组,其他都是返回的一个对象,可以直接打印。

System.out.println(re.getPackage());

System.out.println(re.getName());

System.out.println(re.getSuperclass());

结果:

nullRefclass java.lang.Object

除了包名的结果有些意外,竟然是null,不过确实使用IDEA的过程中没有建包的过程,第一句也不是package XX,我以为是简化了,没想到是真没有,估计用Eclipse肯定是有的。再来因为本实例中的类没有继承任何类,所以获得超类直接返回Object类。至于获得接口数组可以参考之前遍历所有方法(或域)的步骤,一个foreach就可以了。

好了,反射就到此为止,希望这周能把注解搞完!下期注解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值