- 浏览: 670455 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
yigeisme:
你好,不已.html和.jsp和.jpg结尾的正则表达式怎么写 ...
深入入门正则表达式(java) - 2 - 基本实例 -
su1216:
多谢指正yigeisme 写道1-12(小时,月份)正则:^( ...
深入入门正则表达式(java) - 2 - 基本实例 -
yigeisme:
1-12(小时,月份)正则:^(1[012]|\d)$应该改成 ...
深入入门正则表达式(java) - 2 - 基本实例 -
heikefangxianceshi:
小三将军 写道楼主,我想问下你给的Real.tar.gz是什么 ...
android手机root后的安全问题 (一) -
heikefangxianceshi:
这个程序运行的前提是手机root,但你的手机怎么root的呢? ...
android手机root后的安全问题 (一)
java 运行时类型识别(RTTI) - 1 - Class与instanceof
本文将叙述如何运行时查看类信息,其中包括变量,方法,以及通过反射修改变量,执行方法等
包括如何反射匿名内部类及如何执行其方法,但是笔者强烈不建议这么做,这里只是演示反射而已
下面是一个测试类
package reflect; public class Outer { static{ System.out.println("Testing.."); } TestInterface ti = new TestInterface() { public String test() { return "this is ti"; } }; public Outer(String name){ System.out.println("Outer"); } public String toString(){ System.out.println("Outer toString"); return new TestInterface() { public String test() { return "this is a test!"; } }.test(); } @SuppressWarnings("unused") private void privateMethod(){ System.out.println("privateMethod"); } protected void protectedMethod(){ System.out.println("protectedMethod"); } void packageMethod(){ System.out.println("packageMethod"); } public static void staticMethod(){ System.out.println("staticMethod"); } public interface TestInterface { public String test(); } public static class StaticInner { private static final String TAG = "StaticInnerTAG"; public StaticInner(){ System.out.println("StaticInner"); } public String toString(){ System.out.println("StaticInner toString"); return TAG; } } private class Inner{ String name; public Inner(){ System.out.println("Inner"); } public Inner(String name){ System.out.println("reflect.Outer.Inner.Inner(String name)"); this.name = name; } } }
其中包括了普通内部类,静态内部类,内部匿名类,接口等
其中外部类Outer没有默认构造器,String reflect.Outer.Inner.getName()是private的……
外部类
Constructor,Method,Class.forName,newInstance
下面来看如何对上述的类进行反射
首先先看外部类Outer
public static void main(String[] args) { try { Class<?> outer = Class.forName("reflect.Outer"); outer = Outer.class; Constructor<?>[] constructors = outer.getConstructors(); for (Constructor<?> constructor : constructors) { Class<?>[] types = constructor.getParameterTypes(); System.out.println(constructor.getName() + "(" + arrayToString(types) + ")"); } Constructor<?> outerConstructor = outer.getConstructor(String.class); Outer outerInstance = (Outer) outerConstructor.newInstance("a outer"); System.out.println(outerInstance); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public static String arrayToString(Class<?>[] classes){ StringBuilder stringBuilder = new StringBuilder(); for (Class<?> type : classes) { stringBuilder.append(type.getCanonicalName()); stringBuilder.append(","); } if(classes.length > 0){ stringBuilder.deleteCharAt(stringBuilder.length() - 1); } return stringBuilder.toString(); }
打印结果
Testing.. reflect.Outer(java.lang.String) Outer Outer toString this is a test!
下面简单分析下
Class<?> outer = Class.forName("reflect.Outer"); //outer = Outer.class;
我们对类reflect.Outer进行反射,这里使用Outer.class也可以获得Class对象
之前说过使用类字面量不会初始化该类,而Class.forName则会初始化 ,当使用Outer.class时候log如下
reflect.Outer(java.lang.String) Testing.. Outer Outer toString this is a test!
顺序改变了,打印的时候Testing..实际是下面这句触发的
Outer outerInstance = (Outer) outerConstructor.newInstance("a outer");
这时候加载Outer这个类,然后进行初始化
接下来我们查看了Outer的所有构造器Constructor,并打印出所需要的参数(与普通方法区别开来)
构造器只有一个,参数是String
如何执行这个带有String作为参数的构造器来返回一个Outer实例
Constructor<?> outerConstructor = outer.getConstructor(String.class); Outer outerInstance = (Outer) outerConstructor.newInstance("a outer"); System.out.println(outerInstance);
我们先取得我们需要的Constructor,然后,Constructor提供了newInstance方法,这样就可以获得Outer实例
最后打印实例,调用了toString函数
如果你尝试调用
outer.newInstance();
则会看到如下异常
java.lang.InstantiationException: reflect.Outer
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:325)
at reflect.Test.main(Test.java:30)
这是因为Outer没有提供默认构造器
在获得Constructor时其实是有下面两个选择的,至于区别,我们放在Method里说
outer.getConstructors(); outer.getDeclaredConstructors()
现在看看如何获得类的方法,顺便看看Declared的作用
不如直接打印出来,这样比较直观
Method[] methods = outer.getMethods(); for (Method method : methods) { Class<?>[] types = method.getParameterTypes(); System.out.println(method.getReturnType().getName() + " " + outer.getName() + "." + method.getName() + "(" + arrayToString(types) + ")"); } System.out.println("--------------------------------------"); methods = outer.getDeclaredMethods(); for (Method method : methods) { Class<?>[] types = method.getParameterTypes(); System.out.println(method.getReturnType().getName() + " " + outer.getName() + "." + method.getName() + "(" + arrayToString(types) + ")"); }Class<?> outer = Outer.class;
结果如下
void reflect.Outer.staticMethod() java.lang.String reflect.Outer.toString() void reflect.Outer.wait(long) void reflect.Outer.wait() void reflect.Outer.wait(long,int) boolean reflect.Outer.equals(java.lang.Object) int reflect.Outer.hashCode() java.lang.Class reflect.Outer.getClass() void reflect.Outer.notify() void reflect.Outer.notifyAll() -------------------------------------- void reflect.Outer.privateMethod() void reflect.Outer.protectedMethod() void reflect.Outer.packageMethod() void reflect.Outer.staticMethod() java.lang.String reflect.Outer.toString()
调用getMethods时,Outer的方法只打印出了toString,其余结果均为父类Object的公有方法
调用getDeclaredMethods时,则只打印出在Outer中声明定义的方法
他们均打印出了公共的静态方法
所有带Declared和不带Declared的成对的方法都和上面的类似
如何利用反射执行一个方法,下面以void reflect.Outer.privateMethod()为例
Method method = outer.getDeclaredMethod("privateMethod"); method.setAccessible(true); method.invoke(outerInstance, (Object[])null); method.setAccessible(false);
首先privateMethod是私有方法,所以为了能得到对应的Method对象,我们需要调用getDeclaredMethod
为了能访问私有方法,我们需要进行setAccessible(true)的设置
然后需要有个对象来执行,我们选择刚才的outerInstance
这时控制台输出
privateMethod
干完活后,恢复其设置setAccessible(false)
下面是静态方法的执行
Method method = outer.getDeclaredMethod("staticMethod"); method.setAccessible(true); method.invoke(Outer.class, (Object[])null); method.setAccessible(false);
ps:使用method.invoke(outerInstance, (Object[])null);也能执行,但是不该这样
内部类
isInterface,Field,isAccessible,setAccessible,getModifiers,Modifier.toString()
下面看看内部类的反射
Class<?>[] classes = outer.getDeclaredClasses(); for (Class<?> clazz : classes) { if(clazz.isInterface()){ System.out.println("interface : " + clazz.getName()); }else{ System.out.println("class : " + clazz.getName()); } }
输出
class : reflect.Outer$Inner class : reflect.Outer$StaticInner interface : reflect.Outer$TestInterface
看来反射提供的api功能还是很全的
下面是如何反射静态内部类
try { Class<StaticInner> staticInner = StaticInner.class; StaticInner staticInnerInstance = staticInner.newInstance(); }catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
也可以使用Class.forName方式,如果StaticInner是不可见的,那么上面的代码则无法编译,下面看看Class.forName
try { Class<StaticInner> staticInner = (Class<StaticInner>) Class.forName("reflect.Outer.StaticInner"); StaticInner staticInnerInstance = staticInner.newInstance(); }catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
如果你和上面的写法一样,那么很不幸,运行时会得到如下错误
java.lang.ClassNotFoundException: reflect.Outer.StaticInner
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:186)
at reflect.Test.main(Test.java:11)
我们去bin目录下可以发现这样的文件Outer$StaticInner.class
反射代码只需做如下改动
Class<StaticInner> staticInner = (Class<StaticInner>) Class.forName("reflect.Outer$StaticInner");
.变成了$
这里newInstance之所以能执行,是因为StaticInner有默认构造器
下面看看StaticInner中生命了哪些变量
Class<StaticInner> staticInner = StaticInner.class; Field[] fields = staticInner.getDeclaredFields(); for (Field field : fields) { Class<?> type = field.getType(); field.setAccessible(true); System.out.println(Modifier.toString(field.getModifiers()) + " " + type.getName() + " " + field.getName()); } StaticInner StaticInnerInstance = staticInner.newInstance(); Field field = staticInner.getDeclaredField("TAG"); boolean accessible = field.isAccessible(); if(!accessible){ field.setAccessible(true); } System.out.println(field.get(StaticInnerInstance)); field.set(StaticInnerInstance, "TAG"); System.out.println(field.get(StaticInnerInstance)); if(!accessible){ field.setAccessible(false); }
结果如下
private java.lang.String TAG StaticInner StaticInnerTAG TAG
StaticInner只声明了一个变量,名字为TAG,类型为String
即使是private变量,设置setAccessible(true)之后也能改变其值
普通内部类的反射和上面类似
最后说下匿名内部类
匿名内部类的作用是仅仅使用一次,所以也没有必要进行反射,实际上也很难进行反射
例子中有两个匿名内部类
TestInterface ti = new TestInterface() { public String test() { return "this is ti"; } }; public String toString(){ System.out.println("Outer toString"); return new TestInterface() { public String test() { return "this is a test!"; } }.test(); }
在bin目录下发现有Outer$1.class和Outer$2.class
getDeclaredClasses发现也没有匿名内部类的信息
try { Class<Outer> outer = Outer.class; Class<?>[] classes = outer.getDeclaredClasses(); for (Class<?> clazz : classes) { System.out.println(clazz.getName()); } }catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); }
结果
reflect.Outer$Inner reflect.Outer$StaticInner reflect.Outer$TestInterface
只有这三个,包括一个接口
如果非要对匿名内部类进行反射,也不是不可能
下面演示如何反射一个匿名内部类,仅仅是演示,没有任何意义,也不推荐这么做
我们以上面的toString方法里面的内部类做例子
try { Class<?> clazz = Class.forName("reflect.Outer$2"); Constructor<?>[] constructors = clazz.getDeclaredConstructors(); constructors[0].setAccessible(true); Class<?>[] types = constructors[0].getParameterTypes(); for (Class<?> type : types) { System.out.println("Parameter Types:" + type.getName()); } TestInterface testInterface = (TestInterface) constructors[0].newInstance(new Outer("")); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { Class<?>[] parameterTypes = method.getParameterTypes(); System.out.println(method.getName() + "(" + arrayToString(parameterTypes) + ")"); } Method method = clazz.getDeclaredMethod("test"); String string = (String)method.invoke(testInterface); System.out.println(string); }catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); }
结果如下
Parameter Types:reflect.Outer Testing.. Outer test() this is a test!
下面看看代码都做了什么,依次说明
首先获取Outer$2的Class
然后获取其构造器,查看所需要的参数,我们发现内部匿名类也需要一个外部类的支持
然后我们newInstance生成实例,声明为一个接口,由于要传入外部类,这里我们直接new一个,所以会初始化外部类,打印第2,3句
接下来查看内部类的方法,找到test(),这是第4句打印的结果
最后用实例化好的内部匿名类执行这个方法,所以打印出了最后一句
执行第一个匿名内部类的方法代码简单些,同样不推荐这么做
try { Class<Outer> clazz = Outer.class; Outer o = new Outer(""); //System.out.println(o.ti.test()); Field field = clazz.getDeclaredField("ti"); TestInterface testInterface = (TestInterface) field.get(o); System.out.println(testInterface.test()); }catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
为了演示反射,这里没有使用System.out.println(o.ti.test());
至此,反射演示结束
由于写本篇blog的时候多次修改代码,所以上面可能有些地方不太一致,如果发现,敬请指正
转贴请保留以下链接
本人blog地址
发表评论
-
深入入门正则表达式(java) - 命名捕获
2015-10-25 21:57 6623深入入门正则表达式(java) - 引言 深入入门正则表 ... -
标示与掩码
2015-10-21 23:00 0掩码(英语:Mask) ... -
java泛型
2013-07-21 12:23 0java中的泛型 1.为什么要引入泛型 在有泛型之 ... -
java获取系统语言(区分简体中文和繁体中文)
2012-09-12 18:25 10834之前做android应用时遇到过一个问题,就是根据语言的不同而 ... -
小心程序中的时间(时间调整/闰秒)
2012-07-03 15:07 6144先来看一个java中关于时间计算的例子 import jav ... -
java 运行时类型识别(RTTI) - 1 - Class与instanceof
2012-05-29 14:48 6487java 运行时类型识别(RTTI) - 1 - Class与 ... -
java中的clone(+标记接口说明)
2012-04-22 14:27 1717复习一下clone,顺便整 ...
相关推荐
在Java编程中,运行时类型识别(Runtime Type Identification,简称RTTI)是一种关键特性,它允许程序在运行时检查对象的实际类型。RTTI是Java多态性的重要基础,使得代码能够根据对象的实际类型执行不同的操作。...
Java的RTTI(Runtime Type Information,运行时类型信息)机制是Java语言的一个重要特性,它允许程序在运行时检查对象的实际类型。RTTI使得在编译时未知类型的对象能够在运行时进行适当的处理,从而增强了代码的灵活...
RTTI是Run-time Type Identification的缩写,即运行时类型识别。Java语言通过RTTI可以在运行时知道一个对象的类型信息。RTTI在Java中主要通过两种形式存在:一种是传统的类型转换,也就是instanceof关键字和类的...
从给定文件的【部分内容】中我们可以了解到,该文档主要讲述了Java中运行时类型识别(RTTI)的原理和用途,以及Java中的反射机制。在此基础上,我们进一步探讨Java中RTTI和反射的相关知识点。 知识点一:运行时类型...
Java的RTTI(运行时类型识别)和反射机制是两种强大的工具,它们允许程序在运行时检查和操作类的信息及对象。RTTI是Java的一种特性,它使得在编译后的程序中仍然可以在运行时获取对象的实际类型信息。这在处理多态性...
RTTI(RunTime Type Information)是Java在运行时获取类型信息的机制,其使用一种类型对象(Type Object)来实现,这种对象在程序运行时可用于识别类和接口类型。Java使用Class对象来执行RTTI。每个类都有一个Class...
Java提供了两种获取运行时类型信息的方式。除了上述的“传统”RTTI,还有Java 1.1引入的**反射(Reflection)**机制。反射允许程序在运行时动态地访问和操作类、接口、字段和方法的信息,即使在编译时这些信息未知。...
Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息。 1、Class对象 理解RTTI...
本篇主要是深入对Java中的Class对象进行分析,这对后续深入理解反射技术非常重要,主要内容如下:认识Class对象之前,先来了解一个概念,RTTI(Run-TimeTypeIdentification)运行时类型识别,对于这个词一直是C++中...
- 动态类型系统:支持运行时类型识别(RTTI)和反射(Reflection)机制。 - 标准库:提供广泛且强大的功能集合。 #### 三、Java编程中的关键概念 - **对象创建与初始化**:讲解如何创建Java对象以及对象初始化的过程...
RTTI(Runtime Type Identification)和反射机制则赋予了程序在运行时识别对象类型以及访问类内部信息的能力。泛型编程提高了Java代码的复用性和类型安全性。容器类如List、Set和Map为处理数据集合提供了丰富的方法...
在Java中,运行时识别对象类型的两种主要方法是RTTI(运行时类型识别)和Java反射。RTTI通常在类型转换时使用,例如从数组中取出元素并自动转型。而反射则更加强大,它允许程序在运行时获取和操作任何类的属性、方法...
第十一章“运行期类型识别”讲解了运行期类型信息(RTTI)和反射,这是动态获取类信息和操作的关键技术。 第十二章“传递和返回对象”讨论了对象的传递方式,包括引用传递、克隆、只读类的设计等,这些都是处理对象...
4. **类型信息**:Java支持运行时类型识别(RTTI),即在程序运行时获取对象和类的信息。RTTI包括传统的类型转换和反射机制。反射允许在运行时动态访问类、接口、字段和方法的信息,创建和调用对象,实现强大的动态...
此外,包(package)和导入(import)机制提供了清晰的代码组织结构,而动态类型系统(dynamictype system)则增强了语言的灵活性,支持运行时类型识别(RTTI)和反射(Reflection)机制。 #### Java标准库 Java的标准库是其...
然而C++是不支持反射机制,虽然C++有RTTI(运行时类型识别)。但是想要实现C++对象序列化,序列化就是存储到磁盘上,将对象变成一定格式的二进制编码,然后要用的时候再将保存在磁盘上的二进制编码转化成一个内存中的...
10.8.3运行时类型识别320 10.8.4强制类型转换321 10.8.5继承规则322 10.9擦拭323 10.10擦拭带来的错误324 10.10.1静态成员共享问题325 10.10.2重载冲突问题325 10.10.3接口实现问题326 10.11泛型的局限326 ...