接上文….
Java 构造器
利用 Java 的反射机制你可以检查一个类的构造方法,并且可以在运行期创建一个对象。这些功能都是通过 java.lang.reflect.Constructor 这个类实现的。
获取 Constructor 对象
我们可以通 过 Class 对象来获取 Constructor 类的实例:
Class aClass = ...//获取Class对象
Constructor[] constructors = aClass.getConstructors();
返回的 Constructor 数组包含每一个声明为公有的(Public)构造方法。 如果你知道你要访问的构造方法的方法参数类型,你可以用下面的方法获取指定的构造方法,这例子返回的构造方法的方法参数为 String 类型:
Class aClass = ...//获取Class对象
Constructor constructor =
aClass.getConstructor(new Class[]{String.class});
如果没有指定的构造方法能满足匹配的方法参数则会抛出:NoSuchMethodException。
构造方法参数
你可以通过如下方式获取指定构造方法的方法参数信息:
Constructor constructor = ... //获取Constructor对象
Class[] parameterTypes = constructor.getParameterTypes();
利用 Constructor 对象实例化一个类
你可以通过如下方法实例化一个类:
Constructor constructor = MyObject.class.getConstructor(String.class);
MyObject myObject = (MyObject)
constructor.newInstance("constructor-arg1");
constructor.newInstance()方法的方法参数是一个可变参数列表,但是当你调用构造方法的时候你必须提供精确的参数,即形参与实参必须一一对应。在这个例子中构造方法需要一个 String 类型的参数,那我们在调用 newInstance 方法的时候就必须传入一个 String 类型的参数。
示例:
MyObject myObject1;
try {
Constructor constructor =
myObject.getConstructor(new Class[]{String.class,String.class});
Class[] parameterTypes = constructor.getParameterTypes();
for(Class parameterType:parameterTypes){
System.out.println("parameterType = " + parameterType.getName());
}
myObject1 = (MyObject)
constructor.newInstance("xiaokai","123456");
System.out.println("myObject1:name="+myObject1.getName()+" password="+myObject1.getPassword());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
输出结果:
constructor = MyObject
parameterType = java.lang.String
parameterType = java.lang.String
myObject1:name=xiaokai password=123456
Java 变量
使用 Java 反射机制你可以运行期检查一个类的变量信息(成员变量)或者获取或者设置变量的值。通过使用 java.lang.reflect.Field 类就可以实现上述功能。
获取 Field 对象
可以通过 Class 对象获取 Field 对象,如下例:
Class aClass = ...//获取Class对象
Field[] methods = aClass.getFields();
返回的 Field 对象数组包含了指定类中声明为公有的(public)的所有变量集合。 如果你知道你要访问的变量名称,你可以通过如下的方式获取指定的变量:
Class aClass = MyObject.class
Field field = aClass.getField("someField");
上面的例子返回的Field类的实例对应的就是在 MyObject 类中声明的名为 someField 的成员变量,就是这样:
public class MyObject{
public String someField = null;
}
在调用 getField()方法时,如果根据给定的方法参数没有找到对应的变量,那么就会抛出 NoSuchFieldException。
变量名称
一旦你获取了 Field 实例,你可以通过调用 Field.getName()方法获取他的变量名称,如下例:
Field field = ... //获取Field对象
String fieldName = field.getName();
变量类型
你可以通过调用 Field.getType()方法来获取一个变量的类型(如 String, int 等等)
Field field = aClass.getField("someField");
Object fieldType = field.getType();
获取或设置(get/set)变量值
一旦你获得了一个 Field 的引用,你就可以通过调用 Field.get()或 Field.set()方法,获取或者设置变量的值,如下例:
Class aClass = MyObject.class
Field field = aClass.getField("someField");
MyObject objectInstance = new MyObject();
Object value = field.get(objectInstance);
field.set(objetInstance, value);
传入 Field.get()/Field.set()方法的参数 objetInstance 应该是拥有指定变量的类的实例。在上述的例子中传入的参数是 MyObjec t类的实例,是因为 someField 是 MyObject 类的实例。 如果变量是静态变量的话(public static)那么在调用 Field.get()/Field.set()方法的时候传入 null 做为参数而不用传递拥有该变量的类的实例。
示例:
MyObject myObject1;
try {
Constructor constructor =
myObject.getConstructor(new Class[]{String.class,String.class});
myObject1 = (MyObject)
constructor.newInstance("xiaokai","123456");
Field field = myObject.getDeclaredField("name");
//Object value = field.get(myObject1);
field.set(myObject1, "xiaowang");
System.out.println("name:"+myObject1.getName());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
结果:
name:xiaowang
Java 方法
使用 Java 反射你可以在运行期检查一个方法的信息以及在运行期调用这个方法,通过使用 java.lang.reflect.Method 类就可以实现上述功能。
获取 Method 对象
可以通过 Class 对象获取 Method 对象,如下例:
Class aClass = ...//获取Class对象
Method[] methods = aClass.getMethods();
返回的 Method 对象数组包含了指定类中声明为公有的(public)的所有变量集合。
如果你知道你要调用方法的具体参数类型,你就可以直接通过参数类型来获取指定的方法,下面这个例子中返回方法对象名称是“doSomething”,他的方法参数是 String 类型:
Class aClass = ...//获取Class对象
Method method = aClass.getMethod("doSomething", new Class[]{String.class});
如果根据给定的方法名称以及参数类型无法匹配到相应的方法,则会抛出 NoSuchMethodException。 如果你想要获取的方法没有参数,那么在调用 getMethod()方法时第二个参数传入 null 即可,就像这样:
Class aClass = ...//获取Class对象
Method method = aClass.getMethod("doSomething", null);
方法参数以及返回类型
你可以获取指定方法的方法参数是哪些:
Method method = ... //获取Class对象
Class[] parameterTypes = method.getParameterTypes();
你可以获取指定方法的返回类型:
Method method = ... //获取Class对象
Class returnType = method.getReturnType();
通过 Method 对象调用方法
你可以通过如下方式来调用一个方法:
//获取一个方法名为doSomesthing,参数类型为String的方法
Method method = MyObject.class.getMethod("doSomething", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
传入的 null 参数是你要调用方法的对象,如果是一个静态方法调用的话则可以用 null 代替指定对象作为 invoke()的参数,在上面这个例子中,如果 doSomething 不是静态方法的话,你就要传入有效的 MyObject 实例而不是 null。 Method.invoke(Object target, Object … parameters)方法的第二个参数是一个可变参数列表,但是你必须要传入与你要调用方法的形参一一对应的实参。就像上个例子那样,方法需要 String 类型的参数,那我们必须要传入一个字符串。
示例:
MyObject myObject1;
try {
Constructor constructor =
myObject.getConstructor(new Class[]{String.class,String.class});
myObject1 = (MyObject)
constructor.newInstance("xiaokai","123456");
Method method = MyObject.class.getMethod("getName", null);
String returnValue = (String) method.invoke(myObject1, null);
System.out.println("name:"+returnValue);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
输出结果:
name:xiaokai
Java 访问器
使用 Java 反射你可以在运行期检查一个方法的信息以及在运行期调用这个方法,使用这个功能同样可以获取指定类的 getters 和 setters,你不能直接寻找 getters 和 setters,你需要检查一个类所有的方法来判断哪个方法是 getters 和 setters。
首先让我们来规定一下 getters 和 setters 的特性:
Getter
Getter 方法的名字以 get 开头,没有方法参数,返回一个值。
Setter
Setter 方法的名字以 set 开头,有一个方法参数。
setters 方法有可能会有返回值也有可能没有,一些 Setter 方法返回 void,一些用来设置值,有一些对象的 setter 方法在方法链中被调用(译者注:这类的 setter 方法必须要有返回值),因此你不应该妄自假设 setter 方法的返回值,一切应该视情况而定。
下面是一个获取 getter方法和 setter方法的例子:
class="codeBox"
public static void printGettersSetters(Class aClass){
Method[] methods = aClass.getMethods();
for(Method method : methods){
if(isGetter(method)) System.out.println("getter: " + method);
if(isSetter(method)) System.out.println("setter: " + method);
}
}
public static boolean isGetter(Method method){
if(!method.getName().startsWith("get")) return false;
if(method.getParameterTypes().length != 0) return false;
if(void.class.equals(method.getReturnType()) return false;
return true;
}
public static boolean isSetter(Method method){
if(!method.getName().startsWith("set")) return false;
if(method.getParameterTypes().length != 1) return false;
return true;
}