深入理解java中的反射机制

来源:互联网 发布:基本数据分析方法 编辑:程序博客网 时间:2024/05/21 00:16

什么是java反射机制

反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。rol.

通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。
程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。
 反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

Java反射框架主要提供以下功能:

  • 1.在运行时判断任意一个对象所属的类;
  • 2.在运行时构造任意一个类的对象;
  • 3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
  • 4.在运行时调用任意一个对象的方法

重点是运行时而不是编译时

反射的主要用途

 很多人都认为反射在实际的Java开发应用中并不广泛,其实不然。
 当我们在使用IDE(如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射最重要的用途就是开发各种通用框架。
 很多框架(比如Spring)都是配置化的(比如通过XML文件配置JavaBean,Action之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。
 举一个例子,在运用Struts 2框架的开发中我们一般会在struts.xml里去配置Action;
例如:


本人现在正在写一些反射基础的应用

使用反射创建反射对象的三种方法--都用Dog类进行举例
1.   类名.class
Class<Dog> clazz=Dog.class;

2.  getclass()方法
Dog dog=new Dog();
Class<Dog> clazz=dog.getclass();

3. class.forName()方法
try{
Class<Dog> clazz=class.forName("包名.类名 "); 
}catch(Exception e){
e.printStackTrace();
}

判断一个对象是不是那类的实例
一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,它是一个Native方法:

 4.获取方法

获取某个Class对象的方法集合,主要有以下几个方法:
getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

1
public Method[] getDeclaredMethods() throws SecurityException

getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

1
public Method[] getMethods() throws SecurityException

getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象

下面我们通过一个例子来看这些方法

//用反射调用方法
Method m=null;//创建一个Method的实体化对象
try {
m=s.getDeclaredMethod("friendlyStudy", int.class);
m.invoke(stu, 3);
m=s.getDeclaredMethod("privateStudy", int.class);
m.setAccessible(true);//调用私用方法
m.invoke(stu, 78);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System.out.println("----------------------");
System.out.println("调用构造方法");
//调用构造方法
Constructor<?>[] cons=null;
try {
cons=s.getDeclaredConstructors();//取得public的构造函数
for (Constructor<?> constructor : cons) {
System.out.println(constructor);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}




System.out.println("---------------------------");
System.out.println("调用构造方法中的具体一个方法");
Constructor<?>con=null;
try {
con=s.getConstructor(String.class,int.class);
stu=(Student)con.newInstance("zhangs",88);
System.out.println(stu.name);
System.out.println(stu.getAge());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System.out.println("=================================");
System.out.println("调用构造方法中的具体一个方法2");
Class<?> c=stu.getClass();
Constructor<?>con1=null;
try {
con1=c.getDeclaredConstructor(String.class);
con1.setAccessible(true);
stu=(Student)con1.newInstance("海绵宝宝 da shabi");
System.out.println(stu.name);

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System.out.println("=================================");
System.out.println("调用构造方法中的具体一个方法3");
Class<?> cc=null;
Constructor<?>con3=null;
try {
cc=Class.forName("javaoopFanshe1127.Student");
con3=cc.getDeclaredConstructor(String.class);
con3.setAccessible(true);
stu=(Student)con3.newInstance("海绵宝宝 ");
System.out.println(stu.name);
} catch (Exception e) {
// TODO: handle exception
}
}

-----------------------------------------------------------------------------
上面 的例子结果为
_-----------------------------------------
调用friendlyStudy学习时间是:3
调用privateStudy学习时间是:78
----------------------
调用构造方法
public javaoopFanshe1127.Student(java.lang.String,int)
private javaoopFanshe1127.Student(java.lang.String,java.lang.String)
private javaoopFanshe1127.Student(java.lang.String)
public javaoopFanshe1127.Student()
---------------------------
调用构造方法中的具体一个方法
zhangs
88
=================================
调用构造方法中的具体一个方法2
海绵宝宝 da shabi
=================================
调用构造方法中的具体一个方法3
海绵宝宝 

6.利用反射创建数组

数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子:

1
2
3
4
5
6
7
8
9
10
11
12
public static void testArray() throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");
Object array = Array.newInstance(cls,25);
//往数组里添加内容
Array.set(array,0,"hello");
Array.set(array,1,"Java");
Array.set(array,2,"fuck");
Array.set(array,3,"Scala");
Array.set(array,4,"Clojure");
//获取某一项的内容
System.out.println(Array.get(array,3));
}

其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是:

1
2
3
4
public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}

而newArray()方法是一个Native方法,它在Hotspot JVM里的具体实现我们后边再研究,这里先把源码贴出来

1
2
private static native Object newArray(Class<?> componentType, int length)
throws NegativeArraySizeException;

源码目录:openjdk\hotspot\src\share\vm\runtime\reflection.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) {
if (element_mirror == NULL) {
THROW_0(vmSymbols::java_lang_NullPointerException());
}
if (length < 0) {
THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
}
if (java_lang_Class::is_primitive(element_mirror)) {
Klass* tak = basic_type_mirror_to_arrayklass(element_mirror, CHECK_NULL);
return TypeArrayKlass::cast(tak)->allocate(length, THREAD);
} else {
Klass* k = java_lang_Class::as_Klass(element_mirror);
if (k->oop_is_array() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) {
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
}
return oopFactory::new_objArray(k, length, THREAD);
}
}

另外,Array类的set()和get()方法都为Native方法,在HotSpot JVM里分别对应Reflection::array_set和Reflection::array_get方法,这里就不详细解析了。