`
guoshaobin
  • 浏览: 14416 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

java反射

    博客分类:
  • java
阅读更多
在Java运行时环境中,对于任意一个类能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射机制(Reflection)。
Java反射机制主要提供一下功能。
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。

Reflection是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection API取得任何一个已知名称的class的内部信息,包括其modifiers(诸如piblic,static等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。

一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。

尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是:“反射、映像、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class的能力(the ability of the program to examine itself)”被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。

在JDK中,主要由以下类来实现Java反射机制,这些类位于java.lang.reflect包中。
Class类:代表一个类。
File类:代表类的成员变量(成员变量也成为类的属性)
Method类:代表类的方法。
Construtor类:代表类的构造方法
Arry类:提供了动态创建数组,以及访问数组的元素的静态方法。

Class Class<T>Java当中每一个对象都会有一个与之关联的class对象,这个class对象是唯一的。这个class对象是在JDK启动的时候就加载进来的,那么他是我们反射的入口点。

newInstance()

Creates a new instance of the class represented by this Class object.
创建一个新的实例,是由这个Class对象所代表的那个类的实例

Class Method:对于我在类中定义的任意一个方法都会有一个与之关联的Method对象,这个Method会获得这个方法的所有信息,除了方法定义之外,其他都能获得。

Java的每一个类他里面的每一个方法都会有一个与之对应的Method对象,如果要想通过反射来调用这个方法的时候,你就要获得这个方法与之对应的Method对象,获得Method对象之后,就能通过Method对象所代表的那个方法。
getMethod(String name, Class<?>... parameterTypes)方法
想获取一个方法通过这个方法的名字和方法的参数(因为有重载所以才要参数)
invoke(Object obj, Object... args)
返回一个Object类型,其实就是方法的返回类型(引用(int--integer))

代码实例
package com.test;
import java.lang.reflect.Method;
public class InvokeTester {
public int add(int param1, int param2) {
return param1 + param2;
}

public String echo(String msg) {
return "hello:" + msg;
}

public static void main(String[] args) throws Exception {
Class<?> classType = InvokeTester.class;
  // 获得InvokeTester类所对应的Class对象
Object invokeTester = classType.newInstance();

// 以上两行代码等价于
// InvokeTester it = new InvokeTester();
Method addMethod = classType.getMethod("add", int.class, int.class);
// 这个Method对象就等价于add方法
Object result = addMethod.invoke(invokeTester, new Object[]{100,200});
//以上两行代码等价于it.add(100,200);

System.out.println((Integer) result);

Method echoMethod = classType.getMethod("echo",
new Class[] { String.class });
//以上两行代码等价于it.echo("hello");
Object result2 = echoMethod.invoke(invokeTester, new Object[]{"hello"});

System.out.println((String)result2);
}
}
getConstructor(Class<?>... parameterTypes)
获得某个特定的构造方法所对应的对象,在通过构造方法Constructor的newInstance(Object... initargs)方法生成类的实例

getDeclaredFields()获得对象的所有属性,每个属性对应一个Field对象


实例2package com.test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTester {
public Object copy(Object object) throws Exception {
Class<?> classType = object.getClass();
System.out.println("Class:" + classType.getName());

// 通过默认构造方法创建一个新的对象
Object objectCopy = classType.getConstructor(new Class[] {})
.newInstance(new Object[] {});
// 上面这行代码等价于Object objectCopy2 = classType.newInstance();这个是唯一的,
// 使用默认的构造方法,而这里使用的则是万能的,能通过不同的构造方法实例对象
// 而且getConstructor方法和newInstance方法的参数个数和类型一定要匹配
// 先是构造方法的参数类型,然后是实例对象为构造方法传的真实参数

// 获得对象的所有属性
Field fields[] = classType.getDeclaredFields();

for (int i = 0; i < fields.length; i++) {
Field field = fields[i];

String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
// 获得和属性对应的getXXX()方法的名字
String getMethodName = "get" + firstLetter + fieldName.substring(1);
// 获得和属性对应的setXXX()方法的名字
String setMethodName = "set" + firstLetter + fieldName.substring(1);

// 获得和属性对应的getXXX()方法
Method getMethod = classType.getMethod(getMethodName,
new Class[] {});
// 获得和属性对应的setXXX()方法
Method setMethod = classType.getMethod(setMethodName,
new Class[] { field.getType() });

// 调用原对象的getXXX()方法
Object value = getMethod.invoke(object, new Object[] {});
System.out.println(fieldName + ":" + value);
// 调用拷贝对象的setXXX()方法
setMethod.invoke(objectCopy, new Object[] { value });
}
return objectCopy;
}

public static void main(String[] args) throws Exception {
Customer customer = new Customer("Tom", 21);
customer.setId(new Long(1));

Customer customerCopy = (Customer) new ReflectTester().copy(customer);
System.out.println("Copy information:" + customerCopy.getId() + " "
+ customerCopy.getName() + " " + customerCopy.getAge());
}
}

class Customer {
private Long id;

private String name;

private int age;

public Customer() {
}

public Customer(String name, int age) {
this.name = name;
this.age = age;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

通过反射操作一维数组
public static void main(String args[]) throws Exception
{
Class classType = Class.forName("java.lang.String");
// 创建一个长度为10的字符串数组
Object array = Array.newInstance(classType, 10);
// 把索引位置为5的元素设为"hello"
Array.set(array, 5, "hello");
// 获得索引位置为5的元素的值
String s = (String) Array.get(array, 5);
System.out.println(s);
}


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)

Class是Reflection起源。针对任何你想探勘的class,唯有先为他产生一个cClass object,接下来才能经由后者唤起为数十多个的Reflection APIS。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics