- 浏览: 288220 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
yhxf_ie:
网上都是这个方法 改了之后仍然无效啊! 真急人
让Gradle支持中文 -- 关于 "编码 GBK 的不可映射字符"错误的解决 -
smart152819:
夜行侠老师gradle教学视频地址:http://www.it ...
Gradle笔记 -
laorer:
gradle init --type pom
MAVEN项目秒变Gradle项目 -
sulpha:
Gradle 2.0以上,需要把Compile改为JavaCo ...
让Gradle支持中文 -- 关于 "编码 GBK 的不可映射字符"错误的解决 -
marshan:
默认情况下都报错 没有setupBuild这个task 楼主提 ...
MAVEN项目秒变Gradle项目
Java 反射机制
摘要
Reflection
是 Java 被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过 Reflection APIs 取得任何一个已知名称的 class
的内部信息,包括其 modifiers (诸如
public, static 等等)、 superclass
(例如 Object
)、实现之 interfaces (例如
Cloneable ),也包括 fields 和 methods 的所有信息,并可于运行时改变 fields 内容或唤起 methods 。本文借由实例,大面积示范 Reflection
APIs 。
关于本文:
读者基础:具备
Java 语言基础。
本文适用工具:
JDK1.5
关键词:
Introspection (内省、内观)
Reflection (反射)
有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定(
dynamic binding )、动态链接( dynamic
linking )、动态加载( dynamic loading )等。然而 “ 动态 ” 一词其实没有绝对而普遍适用的严格定义,有时候甚至像对象导向当初被导入编程领域一样,一人一把号,各吹各的调。
一般而言,开发者社群说到动态语言,大致认同的一个定义是: “ 程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言 ” 。从这个观点看, Perl , Python , Ruby 是动态语言, C++ , Java , C# 不是动态语言。
尽管在这样的定义与分类下 Java
不是动态语言,它却有着一个非常突出的动态相关机制: Reflection 。这个字的意思是 “ 反射、映象、倒影 ” ,用在 Java 身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的 classes 。换句话说,
Java 程序可以加载一个运行时才得知名称的 class ,获悉其完整构造(但不包括 methods 定义),并生成其对象实体、或对其 fields 设值、或唤起其
methods 1 。这种 “ 看透 class ” 的能力( the ability of the
program to examine itself )被称为 introspection (
内省、内观、反省 )。
Reflection 和
introspection 是常被并提的两个术语。
Java
如何能够做出上述的动态特性呢?这是一个深远话题,本文对此只简单介绍一些概念。整个篇幅最主要还是介绍
Reflection APIs ,也就是让读者知道如何探索 class 的结构、如何对某个
“ 运行时才获知名称的
class ”
生成一份实体、为其 fields 设值、调用其
methods 。本文将谈到 java.lang.Class ,以及 java.lang.reflect 中的 Method 、 Field 、 Constructor
等等 classes
。
“ Class ” class
众所周知
Java 有个
Object class ,是所有 Java classes
的继承根源,其内声明了数个应该在所有 Java class 中被改写的
methods :
hashCode() 、
equals() 、
clone() 、
toString() 、
getClass() 等。其中 getClass()
返回一个 Class
object 。
Class
class 十分特殊。它和一般 classes 一样继承自
Object ,其实体用以表达 Java
程序运行时的 classes 和 interfaces ,也用来表达
enum 、 array 、 primitive Java types ( boolean, byte, char,
short, int, long, float, double )以及关键词
void 。当一个
class 被加载,或当加载器( class
loader )的 defineClass() 被
JVM 调用,
JVM 便自动产生一个
Class object 。如果您想借由 “ 修改 Java 标准库源码 ” 来观察 Class object
的实际生成时机(例如在 Class 的 constructor 内添加一个
println() ),不能够!因为 Class
并没有 public
constructor (见 图 1 )。本文最后我会拨一小块篇幅顺带谈谈 Java 标准库源码的改动办法。
Class
是 Reflection
故事起源。针对任何您想探勘的 class ,唯有先为它产生一个
Class object ,接下来才能经由后者唤起为数十多个的 Reflection APIs 。这些 APIs 将在稍后的探险活动中一一亮相。
#001
public final
#002 class Class <T> implements java.io.Serializable,
#003
java.lang.reflect.GenericDeclaration,
#004
java.lang.reflect.Type,
#005
java.lang.reflect.AnnotatedElement {
#006 private Class() {}
#007 public String
toString
() {
#008
return ( isInterface() ? "interface " :
#009
(isPrimitive() ? "" : "class "))
#010
+ getName();
#011
}
...
图 1 : Class class 片段。注意它的 private empty ctor
,意指不允许任何人经由编程方式产生
Class
object
。是的,其
object
只能由
JVM
产生。
“ Class ” object 的取得途径
Java
允许我们从多种管道为一个 class 生成对应的 Class object 。 图 2 是一份整理。
Class object
诞生管道
|
示例
|
运用 getClass()
注:每个
class 都有此函数
|
String str =
"abc";
Class c1 =
str.getClass();
|
运用
Class.getSuperclass() 2
|
Button b = new
Button();
Class c1 =
b.getClass();
Class c2 =
c1.getSuperclass();
|
运用 static method
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 classes
的 TYPE 语法
|
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;
|
图 2 : Java 允许多种管道生成 Class object 。
Java classes 组成分析
首先容我以
图 3 的 java.util.LinkedList 为例,将 Java class
的定义大卸八块,每一块分别对应 图 4 所示的 Reflection API
。 图 5 则是“获得 class 各区块信息”的程序示例及执行结果,它们都取自本文示例程序的对应片段。
package
java.util; //(1)
import
java.lang.*; //(2)
public class LinkedList < E >
//(3)(4)(5)
extends AbstractSequentialList <E> //(6)
implements List <E>, Queue <E>,
Cloneable,
java.io.Serializable //(7)
{
private
static class Entry
<E> { … }//(8)
public
LinkedList () { … } //(9)
public
LinkedList (Collection<? extends E> c) {
… }
public E
getFirst () { … } //(10)
public E
getLast () { … }
private
transient Entry<E> header = … ; //(11)
private
transient int size
= 0;
}
图 3 :将一个 Java class 大卸八块,每块相应于一个或一组
Reflection
APIs (图 4 )。
Java classes 各成份所对应的 Reflection APIs
图 3 的各个 Java class 成份,分别对应于 图 4 的 Reflection API ,其中出现的 Package
、 Method
、 Constructor 、Field 等等 classes ,都定义于 java.lang.reflect 。
Java class
内部模块(参见 图 3 )
|
Java class
内部模块说明
|
相应之
Reflection API ,多半为 Class methods 。
|
返回值类型
(return type)
|
(1)
package
|
class
隶属哪个 package
|
getPackage()
|
Package
|
(2)
import
|
class
导入哪些 classes
|
无直接对应之
API 。
解决办法见
图 5-2 。
|
|
(3)
modifier
|
class
(或 methods,
fields )的属性
|
int
getModifiers()
Modifier.toString(int)
Modifier.isInterface(int)
|
int
String
bool
|
(4) class name
or interface name
|
class/interface
|
名称 getName()
|
String
|
(5) type
parameters
|
参数化类型的名称
|
getTypeParameters()
|
TypeVariable
<Class>[]
|
(6) base
class
|
base
class (只可能一个)
|
getSuperClass()
|
Class
|
(7) implemented
interfaces
|
实现有哪些
interfaces
|
getInterfaces()
|
Class[]
|
(8) inner
classes
|
内部 classes
|
getDeclaredClasses()
|
Class[]
|
(8') outer
class
|
如果我们观察的
class 本身是
inner classes ,那么相对它就会有个 outer
class 。
|
getDeclaringClass()
|
Class
|
(9)
constructors
|
构造函数
getDeclaredConstructors()
|
不论 public 或 private 或其它 access level ,皆可获得。另有功能近似之取得函数。
|
Constructor[]
|
(10)
methods
|
操作函数
getDeclaredMethods()
|
不论 public 或 private 或其它 access level ,皆可获得。另有功能近似之取得函数。
|
Method[]
|
(11)
fields
|
字段(成员变量)
|
getDeclaredFields() 不论 public 或 private 或其它 access level
,皆可获得。另有功能近似之取得函数。
|
Field[]
|
图 4 : Java class 大卸八块后(如图 3 ),每一块所对应的 Reflection API
。本表并非
Reflection APIs
的全部。
Java Reflection API
运用示例
图 5 示范 图 4 提过的每一个 Reflection
API ,及其执行结果。程序中出现的 tName() 是个辅助函数,可将其第一自变量所代表的 “ Java class 完整路径字符串 ” 剥除路径部分,留下 class
名称,储存到第二自变量所代表的一个 hashtable 去并返回(如果第二自变量为 null
,就不储存而只是返回)。
#001 Class c = null;
#002 c = Class.forName (args[0]);
#003
#004 Package p;
#005 p = c. getPackage ();
#006
#007 if (p
!= null)
#008
System.out.println("package "+p. getName ()+";");
执行结果(例):
package java.util;
图 5-1 :找出 class 隶属的 package 。其中的 c 将继续沿用于以下各程序片段。
#001 ff = c. getDeclaredFields ();
#002 for
(int i = 0; i < ff.length; i++)
#003
x = tName(ff[i].getType().getName(), classRef);
#004
#005 cn = c. getDeclaredConstructors ();
#006 for
(int i = 0; i < cn.length; i++) {
#007
Class cx[] = cn[i].getParameterTypes();
#008
for (int j = 0; j < cx.length; j++)
#009
x = tName(cx[j].getName(), classRef);
#010
}
#011
#012 mm = c. getDeclaredMethods ();
#013 for
(int i = 0; i < mm.length; i++) {
#014
x = tName(mm[i].getReturnType().getName(), classRef);
#015
Class cx[] = mm[i].getParameterTypes();
#016
for (int j = 0; j < cx.length; j++)
#017
x = tName(cx[j].getName(), classRef);
#018
}
#019 classRef.remove(c.getName());
// 不必记录自己(不需 import 自己)
执行结果(例):
import java.util.ListIterator;
import java.lang.Object;
import java.util.LinkedList$Entry;
import java.util.Collection;
import java.io.ObjectOutputStream;
import
java.io.ObjectInputStream;
图 5-2 :找出导入的 classes ,动作细节详见内文说明。
#001 int mod = c. getModifiers ();
#002 System.out.print( Modifier.toString (mod)); // 整个 modifier
#003
#004 if ( Modifier.isInterface (mod))
#005 System.out.print(" ");
// 关键词 "interface" 已含于 modifier
#006
else
#007 System.out.print("
class "); // 关键词 "class"
#008 System.out.print(tName(c. getName (), null)); // class 名称
执行结果(例):
public class
LinkedList
图 5-3 :找出 class 或 interface 的名称,及其属性( modifiers )。
#001 TypeVariable<Class>[] tv;
#002 tv = c. getTypeParameters (); // warning: unchecked conversion
#003 for
(int i = 0; i < tv.length; i++) {
#004 x =
tName(tv[i].getName(), null); // 例如 E,K,V...
#005 if (i == 0) //
第一个
#006
System.out.print("<" + x);
#007 else // 非第一个
#008
System.out.print("," + x);
#009 if (i == tv.length-1)
// 最后一个
#010
System.out.println(">");
#011
}
执行结果(例):
public abstract interface Map <K,V>
或 public class LinkedList <E>
图 5-4 :找出 parameterized types
的名称
#001 Class
supClass;
#002 supClass = c. getSuperclass ();
#003 if (supClass != null) // 如果有 super class
#004
System.out.print(" extends" +
#005 tName(supClass. getName (),classRef));
执行结果(例):
public
class LinkedList<E>
extends
AbstractSequentialList,
图 5-5 :找出 base class 。执行结果多出一个不该有的逗号于尾端。此非本处重点,为简化计,不多做处理。
#001 Class
cc[];
#002 Class
ctmp;
#003 // 找出所有被实现的 interfaces
#004 cc = c. getInterfaces ();
#005 if
(cc.length != 0)
#006 System.out.print(",
/r/n" + " implements "); // 关键词
#007 for (Class cite : cc) //JDK1.5
新式循环写法
#008
System.out.print(tName(cite. getName (), null)+", ");
执行结果(例):
public
class LinkedList<E>
extends
AbstractSequentialList,
implements List, Queue,
Cloneable, Serializable,
图 5-6 :找出 implemented interfaces
。执行结果多出一个不该有的逗号于尾端。此非本处重点,为简化计,不多做处理。
#001 cc = c. getDeclaredClasses (); // 找出 inner classes
#002 for
(Class cite : cc)
#003
System.out.println(tName(cite. getName (), null));
#004
#005 ctmp = c. getDeclaringClass (); // 找出 outer classes
#006 if
(ctmp != null)
#007
System.out.println(ctmp. getName ());
执行结果(例):
LinkedList$Entry
LinkedList$ListItr
图 5-7 :找出 inner classes 和 outer class
#001 Constructor cn[];
#002 cn = c. getDeclaredConstructors ();
#003 for
(int i = 0; i < cn.length; i++) {
#004 int md = cn[i].
getModifiers ();
#005
System.out.print(" " + Modifier.toString(md) + " " +
#006
cn[i].getName());
#007 Class cx[] =
cn[i]. getParameterTypes
();
#008
System.out.print("(");
#009
for (int j = 0; j < cx.length; j++) {
#010
System.out.print(tName(cx[j].getName(), null));
#011
if (j < (cx.length - 1)) System.out.print(", ");
#012
}
#013
System.out.print(")");
#014
}
执行结果(例):
public java.util.LinkedList(Collection)
public
java.util.LinkedList()
图 5-8a :找出所有 constructors
#004 System.out.println(cn[i]. toGenericString ());
执行结果(例):
public java.util.LinkedList(java.util.Collection<?
extends E>)
public
java.util.LinkedList()
图 5-8b :找出所有 constructors 。本例在 for 循环内使用 toGenericString()
,省事。
#001 Method mm[];
#002 mm = c. getDeclaredMethods ();
#003 for
(int i = 0; i < mm.length; i++) {
#004 int md = mm[i].
getModifiers ();
#005
System.out.print(" "+Modifier.toString(md)+" "+
#006 tName(mm[i].
getReturnType ().getName(), null)+" "+
#007
mm[i].getName());
#008 Class cx[] =
mm[i]. getParameterTypes
();
#009
System.out.print("(");
#010
for (int j = 0; j < cx.length; j++) {
#011
System.out.print(tName(cx[j].getName(), null));
#012
if (j < (cx.length - 1)) System.out.print(", ");
#013
}
#014
System.out.print(")");
#015
}
执行结果(例):
public Object get(int)
public int size()
图 5-9a :找出所有 methods
#004 System.out.println(mm[i]. toGenericString ());
public E java.util.LinkedList.get(int)
public int
java.util.LinkedList.size()
图 5-9b :找出所有 methods 。本例在 for 循环内使用 toGenericString()
,省事。
#001 Field ff[];
#002 ff = c. getDeclaredFields ();
#003 for
(int i = 0; i < ff.length; i++) {
#004 int md = ff[i].
getModifiers ();
#005
System.out.println(" "+Modifier.toString(md)+" "+
#006
tName(ff[i].getType().getName(), null) +" "+
#007
ff[i].getName()+";");
#008
}
执行结果(例):
private transient LinkedList$Entry header;
private transient int
size;
图 5-10a :找出所有 fields
#004
System.out.println("G: " + ff[i].toGenericString());
private transient
java.util.LinkedList.java.util.LinkedList$Entry<E> ??
java.util.LinkedList.header
private transient int
java.util.LinkedList.size
图 5-10b :找出所有 fields 。本例在 for 循环内使用 toGenericString()
,省事。
找出 class 参用 (导入) 的所有 classes
没有直接可用的
Reflection API 可以为我们找出某个 class
参用的所有其它 classes 。要获得这项信息,必须做苦工,一步一脚印逐一记录。我们必须观察所有 fields 的类型、所有
methods (包括
constructors )的参数类型和回返类型,剔除重复,留下唯一。这正是为什么 图 5-2 程序代码要为 tName()
指定一个 hashtable (而非一个
null )做为第二自变量的缘故: hashtable 可为我们储存元素(本例为字符串),又保证不重复。
本文讨论至此,几乎可以还原一个 class 的原貌(唯有 methods 和 ctors 的定义无法取得)。接下来讨论 Reflection
的另三个动态性质: (1) 运行时生成 instances , (2) 执
行期唤起
methods ,
(3) 运行时改动
fields 。
运行时生成 instances
欲生成对象实体,在 Reflection
动态机制中有两种作法,一个针对“无自变量 ctor ”,
一个针对“带参数
ctor ” 。 图 6 是面对“无自变量 ctor ”的例子。如果欲调用的是“带参数 ctor “就比较麻烦些,
图 7 是个例子,其中不再调用 Class
的 newInstance() ,而是调用 Constructor
的 newInstance() 。
图 7 首先准备一个 Class[]
做为 ctor
的参数类型(本例指定为一个 double 和一个 int ),然后以此为自变量调用
getConstructor() ,获得一个专属 ctor 。接下来再准备一个 Object[]
做为 ctor 实参值(本例指定
3.14159 和
125 ),调用上述专属
ctor 的 newInstance() 。
#001 Class
c = Class.forName("DynTest");
#002
Object obj = null;
#003 obj = c.newInstance (); // 不带自变量
#004
System.out.println(obj);
图 6 :动态生成“ Class object 所对应之 class ”的对象实体;无自变量。
#001 Class
c = Class.forName("DynTest");
#002
Class[] pTypes = new Class[] { double.class, int.class };
#003 Constructor ctor = c.getConstructor (pTypes);
#004 // 指定 parameter list ,便可获得特定之 ctor
#005
#006
Object obj = null;
#007 Object[] arg = new Object[] {3.14159,
125}; // 自变量
#008 obj = ctor.newInstance (arg);
#009
System.out.println(obj);
图 7 :动态生成“ Class object 对应之 class ”的对象实体;自变量以 Object[] 表示。
运行时 调用 methods
这个动作和上述调用“带参数之 ctor ”相当类似。首先准备一个
Class[] 做为
ctor 的参数类型(本例指定其中一个是 String ,另一个是 Hashtable ),然后以此为自变量调用 getMethod() ,获得特定的
Method object 。接下来准备一个
Object[] 放置自变量,然后调用上述所得之特定 Method
object 的 invoke() ,如 图 8 。知道为什么索取 Method object
时不需指定回返类型吗?因为 method overloading 机制要求 signature
(署名式)必须唯一,而回返类型并非 signature 的一个成份。换句话说,只要指定了 method 名称和参数列,就一定指出了一个独一无二的 method 。
#001 public String func (String s, Hashtable ht)
#002
{
#003 … System.out.println("func invoked"); return
s;
#004
}
#005
public static void main(String args[])
#006
{
#007 Class
c = Class.forName("Test");
#008 Class
ptypes[] = new Class[2];
#009
ptypes[0] = Class.forName("java.lang.String");
#010
ptypes[1] = Class.forName("java.util.Hashtable");
#011 Method m = c. getMethod (" func ",ptypes);
#012 Test
obj = new Test();
#013
Object args[] = new Object[2];
#014
arg[0] = new String("Hello,world");
#015
arg[1] = null;
#016 Object r = m. invoke (obj, arg);
#017
Integer rval = (String)r;
#018
System.out.println(rval);
#019
}
图 8 :动态唤起 method
运行时变更 fields 内 容
与先前两个动作相比,“变更 field 内容”轻松多了,因为它不需要参数和自变量。首先调用 Class 的 getField() 并指定
field 名称。获得特定的 Field
object 之后便可直接调用 Field
的 get()
和 set()
,如 图 9 。
#001
public class Test {
#002 public double d ;
#003
#004
public static void main(String args[])
#005
{
#006 Class
c = Class.forName("Test");
#007 Field f = c. getField (" d "); // 指定 field 名称
#008 Test
obj = new Test();
#009 System.out.println("d= " +
(Double) f.get (obj));
#010
f .set (obj, 12.34);
#011 System.out.println("d= " + obj.
d );
#012
}
#013
}
图 9 :动态变更 field 内容
Java 源码改动办法
先前我曾提到,原本想借由“改动 Java 标准库源码”来测知
Class object
的生成,但由于其 ctor 原始设计为 private ,也就是说不可能透过这个管道生成 Class
object (而是由 class loader
负责生成),因此“在 ctor 中 打印出某种信息”的企图也就失去了意义。
这里我要谈点题外话:如何修改 Java 标准库源码并让它反应到我们的应用程序来。假设我想修改 java.lang.Class ,让它在某些情况下打印某种信息。首先必须找出标准源码!当你下载 JDK 套件并安装妥当,你会发现
jdk150/src/java/lang 目录(见 图 10 )之中有 Class.java ,这就是我们此次行动的标准源码。备份后加以修改,编译获得 Class.class 。接下来准备将 .class
搬移到 jdk150/jre/lib/endorsed (见 图 10 )。
这是一个十分特别的目录, class
loader 将优先从该处读取内含 classes 的 .jar 文件 —— 成功的条件是 .jar 内的 classes 压缩路径必须和
Java 标准库的路径完全相同。为此,我们可以将刚才做出的 Class.class 先搬到一个为此目的而刻意做出来的 /java/lang 目录中,压缩为
foo.zip (任意命名,唯需夹带路径 java/lang ),再将这个
foo.zip 搬到
jdk150/jre/lib/endorsed 并改名为 foo.jar 。此后你的应用程序便会优先用上这里的 java.lang.Class 。整个过程可写成一个批处理文件( batch
file ),如 图 11 ,在 DOS Box 中使用。
图 10 : JDK1.5 安装后的目录组织。其中的 endorsed 是我新建。
del e:/java/lang/*.class // 清理干净
del c:/jdk150/jre/lib/endorsed/foo.jar
// 清理干净
c:
cd
c:/jdk150/src/java/lang
javac -Xlint:unchecked Class.java
// 编译源码
javac -Xlint:unchecked ClassLoader.java
/ / 编译另一个源码(如有必要)
move *.class e:/java/lang // 搬移至刻意制造的目录中
e:
cd e:/java/lang // 以下压缩至适当目录
pkzipc -add -path=root c:/jdk150/jre/lib/endorsed/foo.jar
*.class
cd e:/test // 进入测试目录
javac -Xlint:unchecked Test.java //
编译测试程序
java Test // 执行测试程序
图 11 :一个可在 DOS Box 中使用的批处理文件( batch file ),用以自动化 java.lang.Class
的修改动作。 Pkzipc(.exe) 是个命令列压缩工具, add 和 path 都是其命令。
更多信息
以下是视野所及与本文主题相关的更多讨论。这些信息可以弥补因文章篇幅限制而带来的不足,或带给您更多视野。
l " Take an in-depth
look at the Java Reflection API -- Learn about the new Java 1.1 tools forfinding
out information about classes ", by Chuck
McManis 。此篇文章所附程序代码是本文示例程序的主要依据(本文示例程序示范了更多 Reflection APIs ,并采用 JDK1.5 新式的 for-loop 写法)。
l " Take a look inside
Java classes -- Learn to deduce properties of a Java class from inside aJava
program ", by Chuck McManis 。
l " The basics of Java
class loaders -- The fundamentals of this key component of the
Javaarchitecture ", by Chuck
McManis 。
l 《 The Java Tutorial
Continued 》 , Sun microsystems. Lesson58-61, "Reflection".
注 1 用过诸如 MFC 这类所谓 Application Framework 的程序员也许知道, MFC
有所谓的 dynamic
creation 。但它并不等同于 Java 的动态加载或动态辨识;所有能够在 MFC 程序中起作用的 classes ,都必须先在编译期被编译器 “
看见 ” 。
注 2 如果操作对象是 Object , Class.getSuperClass() 会返回 null 。
转自:http://www.j2medev.com/Article/Class3/Class7/200604/1995.html
发表评论
-
Gradle笔记
2012-10-30 08:21 368076.1 每个构建包含一个或多个 "Proj ... -
Mybatis+Proxool+Spring多数据源切换
2012-08-10 13:57 6905话不多说直接上代码,用者自提,不喜勿喷,3Q < ... -
JSTL 学习、应用记录
2011-07-28 14:34 1225JSTL 学习、应用记录 原来一直没有看过,我说过我是新 ... -
Spring两大核心-AOP和IoC
2011-07-11 10:43 1427Spring两大核心-AOP和 ... -
java内存泄露解析
2011-07-11 10:42 1545原因有很多种, ... -
java 23种设计模式
2011-07-11 10:40 869工厂模式, 工厂方法模式,单例模式, 外观(Facad ... -
Class.forName和New的比较
2011-07-11 10:36 1151Class.forName和New的比较 ... -
null或空值的判断处理-java
2011-07-11 10:33 1403null或空值的判断处理-java 原帖地址 ... -
java中字符串链接性能比较
2011-07-11 10:31 1204原帖地址:http://blog.csdn.net/bes ... -
[转]提高Java反射速度的方法以及对setAccessable的误解
2011-05-30 15:20 2003mercyblitz 写道 ouchxp 写道 ... -
用MyElipse配置WebLogic
2011-04-12 16:16 1361(1)安装Weblogic设置如下: 首先建立domai ... -
Myeclipse9.0正式版下载地址(附破解包)
2011-04-12 11:09 4588用者自提,谢绝乱喷 Windows http:// ... -
C#之int挑战Java之Integer
2010-10-25 16:55 1913C#之int挑战Java之Integer ... -
是 String , StringBuffer 还是 StringBuilder ?
2010-07-06 09:39 1145相信大家对 String 和 StringBuffer 的 ... -
选择抽象类还是接口
2010-07-06 09:33 1119Java接口与Java抽象类的区别: 1. Ja ... -
JAVA程序员葵花宝典
2010-03-31 08:54 1239话不多说,先下载再说^^ -
Struts2笔记 - 10 自定义类型转换器
2010-02-10 17:05 1046package struts2.demo.action; ... -
Struts2笔记 - 09 请求参数的接收
2010-02-10 15:21 1441采用基本类型接收请求参数(get/post)在Action类中 ... -
Struts2笔记 - 08配置多个Struts配置文件
2010-02-10 14:54 1158动态方法调用和使用通配符定义 由请求参数指定调用action ... -
Struts2笔记 - 07 配置多个Struts配置文件
2010-02-08 16:13 1019配置多个Struts配置文件 <struts> ...
相关推荐
java反射机制java反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制...
Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查和操作类、接口、对象等的内部结构。通过反射,开发者能够在运行时动态地获取类的信息(如类名、方法名、参数类型)并调用方法,创建对象,甚至...
JAVA反射机制应用 JAVA反射机制是JAVA语言中的一种动态机制,它能够在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。这种动态获取的信息以及动态...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、对象等的内部信息。通过Java反射机制,开发者可以在不知道具体类名的情况下创建对象,调用方法,访问和修改私有成员变量,以及...
Java反射机制是Java编程语言中的一个重要特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类集中在java.lang.reflect包下,包括Class、Constructor、Method和...
### Java反射机制深入理解 #### 一、反射机制概述 Java反射机制是一种强大的工具,它允许程序在运行时检查和操作任何类、方法、构造函数和字段等元素。这种能力对于构建灵活的应用程序和框架非常有用,特别是那些...
Java反射机制是Java语言提供的一种强大工具,它允许在程序运行时动态地获取类的信息以及对类的对象进行操作。在Java中,静态编译时类型检查确保了代码的稳定性,但有时我们需要在运行时根据需求动态地创建对象、调用...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、对象等的内部结构。通过反射,开发者可以动态地获取类的信息并调用其方法,创建对象,访问私有成员,甚至改变类的行为。在深入...
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时获取和操作任何已知名称的类的内部信息。这一机制使得Java具备了一定的动态性,虽然在传统的分类中Java被视为静态类型语言。通过反射,开发者可以在...
Java 反射机制是 Java 语言中的一个重要特性,它允许程序在运行时动态地获取类的信息(如类名、属性、方法等)并调用对象的方法,甚至修改对象的状态。这一机制极大地增强了 Java 程序的灵活性和可扩展性,尤其是在...
这篇博文"Java反射机制学习(二)"可能深入探讨了如何利用反射进行动态类型处理、访问私有成员以及创建对象等核心概念。在这里,我们将详细讨论Java反射的基本用法及其在实际开发中的应用。 1. **什么是反射**: ...
java反射机制和动态代理的原理,熟悉反射机制和动态代理
### Java反射机制详解 #### 一、Java反射机制概述 Java反射机制是Java语言的一个重要特性,它允许程序在运行时获取类的信息并操作对象。Java反射机制的主要作用包括:获取类的所有属性和方法、构造动态实例、调用...
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。这种机制使得Java具有高度的灵活性和动态性,可以在编译时未知类的情况下进行类的加载、实例化、方法调用等操作...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、字段和方法的信息。这个特性使得Java具备了高度的灵活性,能够在运行时动态地发现和使用类的属性和方法,即使这些信息在编译时...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查并操作类、接口、字段和方法的信息,打破了通常编译时静态绑定的限制。通过反射,我们可以动态地创建对象,调用方法,访问和修改字段值,甚至...
### Java反射机制详解 #### 一、引言 在Java面试中,经常会出现与反射机制相关的题目。这是因为Java反射机制不仅是Java语言的一项重要特性,也是理解Java动态特性的关键所在。通过本文,我们将深入探讨Java反射...
java反射机制核心代码,小弟一直弄不明白,怎么通过反射来调用私有成员方法,看了这个后,你可以随心调用private方法,和属性,记得添加setAccessable(true),哦,要不还是不行,如:method.setAccessable(true);
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并进行操作。通过反射,开发者可以在程序执行时发现并访问类的字段(fields)、方法(methods)以及构造器(constructors),...