Java反射作为其动态语言的标志性特点之一我们很有必要掌握,至少得知道其基本用法~ ~本文尝试着从构造器、属性、方法这三点进行讲解反射的用法。在开始之前我先准备好了一个Person类,此类包含了有参构造器、无参构造器、私有属性、公开属性、以及私有方法和公开方法。
package com.geo.reflect;
public class Person {
public String name = "张三";
protected String sex = "男";
private int age = 23;
public boolean isOnline = false;
private Person() {
}
public Person(String name, int age, boolean isonline) {
this.name = name;
this.age = age;
this.isOnline = isonline;
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String getSex() {
return sex;
}
private void setSex(String sex) {
this.sex = sex;
}
protected int getAge() {
return age;
}
protected void setAge(int age) {
this.age = age;
}
public boolean getOnline() {
return isOnline;
}
public void setOnline(boolean isonline) {
this.isOnline = isonline;
}
@Override
public String toString() {
return "Hi~I am Person Class";
}
}
一、反射构造器
1.获取一个String类型参数的构造器
//获取带有一个String类型的构造器,即Person(String str)
Constructor consParamStr = mClass.getConstructor(String.class);
System.out.println(consParamStr);
-------------------------- 以下文打印结果 ----------------------------
public com.geo.reflect.Person(java.lang.String)
2.获取三个参数的构造器
// 获取带有三个参数的构造器
Class[] cla = { String.class, Integer.class, Boolean.class };
Constructor consParamThr = mClass.getConstructor(cla);
System.out.println(consParamThr);
-------------------------- 以下文打印结果 ----------------------------
public com.geo.reflect.Person(java.lang.String,int,boolean)
执行以上代码你会发现会报错,根本执行不通过,因为Person类的三参构造器public Person(String name, int age, boolean isonline)的第二个和第三个参数并不是Integer.class和Boolean.class,而应该改为
Integer.TYPE和Boolean.TYPE或
int.class和boolean.class即可,修改后的代码如下:
// 获取带有三个参数的构造器
Class[] cla = { String.class, Integer.TYPE, Boolean.TYPE};
Constructor consParamThr = mClass.getConstructor(cla);
System.out.println(consParamThr);
-------------------------- 以下文打印结果 ----------------------------
public com.geo.reflect.Person(java.lang.String,int,boolean)
3.一次性获取所有构造器
Constructor[] cons = mClass.getConstructors();
System.out.println("构造器个数:"+cons.length);
for(Constructor cu : cons){
System.out.println("构造器名称:"+cu.getName());
}
-------------------------- 以下文打印结果 ----------------------------
构造器个数:3
构造器名称:com.geo.reflect.Person
构造器名称:com.geo.reflect.Person
构造器名称:com.geo.reflect.Person
可以看到,即使Person类有一个私有构造器也会获取到。
4.获取构造器参数和参数类型
Class[] cla = { String.class, Integer.TYPE, boolean.class};
Constructor consParamThr = mClass.getConstructor(cla);
System.out.println("构造器名称:"+consParamThr);
//获取构造器参数
System.out.println("构造器参数个数:"+consParamThr.getParameterCount());
Parameter[] params = consParamThr.getParameters();
for(Parameter pam : params){
System.out.println("参数类型:"+pam.getType());
System.out.println("参数名称:"+pam.getName());
}
-------------------------- 以下文打印结果 ----------------------------
构造器名称:public com.geo.reflect.Person(java.lang.String,int,boolean)构造器参数个数:3参数类型:class java.lang.String参数名称:arg0参数类型:int参数名称:arg1参数类型:boolean参数名称:arg2
5.根据构造器创建实例
Class[] cla = { String.class, Integer.TYPE, Boolean.TYPE};
Constructor consParamThr = mClass.getConstructor(cla);
System.out.println("构造器名称:"+consParamThr);
//获取构造器参数
System.out.println("构造器参数个数:"+consParamThr.getParameterCount());
Parameter[] params = consParamThr.getParameters();
for(Parameter pam : params){
System.out.println("参数类型:"+pam.getType());
System.out.println("参数名称:"+pam.getName());
}
try {
//注意在使用构造器创建对象时,需要传递像应的参数值,就像我们在new对象一样
Object instance = consParamThr.newInstance("伍佰",33,true);
System.out.println(instance.toString());
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
}
-------------------------- 以下文打印结果 ----------------------------
构造器名称:public com.geo.reflect.Person(java.lang.String,int,boolean)
构造器参数个数:3
参数类型:class java.lang.String
参数名称:arg0
参数类型:int
参数名称:arg1
参数类型:boolean
参数名称:arg2
姓名:伍佰 性别:男 年龄:33
在使用构造器的时候需要注意,如果我们的类没有empty的构造器或者构造器是private类型的,那么我们是无法使用该构造器来创建实例的,这个规则和Java语法一致(即如果类没有构造器那么默认的就是无参数构造器,如果存在有参构造器,那么在创建实例的时候就不会使用无参数构造器),因此,我们的Person类中有一个私有的构造器,所以下面的代码会报错:
try {
//获取无参构造器
Constructor noParamCs = mClass.getConstructor(null);
//此时调用会报错
Object instance = noParamCs.newInstance(null);
System.out.println(instance.toString());
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
}
-------------------------- 以下文打印结果 ----------------------------
java.lang.NoSuchMethodException: com.geo.reflect.Person.<init>() at java.lang.Class.getConstructor0(Unknown Source) at java.lang.Class.getConstructor(Unknown Source) at com.geo.reflect.MainRefl.reflectCons(MainRefl.java:47) at com.geo.reflect.MainRefl.main(MainRefl.java:23)
因此,私有构造器虽然可以反射获取到,但是并不能用来创建实例,解决办法是将私有构造器该为public或者将所有的构造器删除(此时类默认的就是无参构造器)
二、反射属性
1.根据指定字段字符串获取属性
try {
Field nameFe = mClass.getDeclaredField("name");
Field sexFe = mClass.getDeclaredField("sex");
Field ageFe = mClass.getDeclaredField("age");
System.out.println(nameFe.getName() + "\t" + sexFe.getName() + "\t"
+ ageFe.getName());
} catch (NoSuchFieldException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
-------------------------- 以下文打印结果 ----------------------------
name sex age
2.反射获取到属性值
要想反射获取到属性的值,该属性的值必须是static类型的。
Field nameFe = mClass.getDeclaredField("name");
Field sexFe = mClass.getDeclaredField("sex");
Field ageFe = mClass.getDeclaredField("age");
System.out.println(nameFe.getName() + "\t" + sexFe.getName() + "\t"
+ ageFe.getName() + "=" + ageFe.getInt("age"));
三、反射方法
1.获取所有方法
Method[] methods = mClass.getDeclaredMethods();
for(Method me : methods){
System.out.println("名字:"+me.getName());
System.out.println("参数个数"+me.getParameterCount());
Parameter[] params = me.getParameters();
for(Parameter pa: params){
System.out.printf("参数名字:"+pa.getName());
System.out.println("\n参数类型:"+pa.getType());
}
System.out.println("\n=========================");
}
2.根据方法名获取方法
Method method = mClass.getDeclaredMethod("setName", String.class);
注意,在根据方法名获取方法的时候第二个参数是方法参数的类型,如果是无参函数就直接给个nuull即可,如下:
Method method = mClass.getDeclaredMethod("getName", null);
3.反射出方法并调用invoke
//反射创建实例
Person person = (Person) mClass.newInstance();
//反射出方法
Method method = mClass.getDeclaredMethod("setName", String.class);
//设置名字为“刘邦”
method.invoke(person, "刘邦");
//最后打印结果就是刘邦
System.out.println(person.getName());