要记住一切都是由Class对象开始,java.lang.Class是反射入口。
获取类的基本信息
我们可以通过一个类的Class对象了解该类的基本信息。
Javaclass内部模块
Javaclass内部模块说明
相应之ReflectionAPI,多半为Classmethods。
返回值类型(returntype)
package
class隶属哪个package
getPackage()
Package
field
class的属性
按访问权限分为:
所有、可访问
getDeclaredFields();
getDeclaredField(String name);
Field[]
Field
method
class的方法
按访问权限分为:
所有、可访问
getMethods();
getMethod(String name, Class>...parameterTypes);
Method[]
Method
modifier
class(或methods,fields)的属性
intgetModifiers()
Modifier.toString(int)
Modifier.isInterface(int)
int
String
bool
classnameorinterfacename
class/interface
名称getName()
String
typeparameters
参数化类型的名称
getTypeParameters()
TypeVariable
[]
baseclass
baseclass(只可能一个)
getSuperClass()
Class或null
implementedinterfaces
实现有哪些interfaces
getInterfaces()
Class[]
innerclasses
内部classes
getDeclaredClasses()
Class[]
outerclass
如果我们观察的class本身是innerclasses,那么相对它就会有个outerclass。
getDeclaringClass()
Class
下面我们来实践一下:
Person.java
class Person {
private int age;
private String name;
public Person() {
super();
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public void say(){
System.out.println("Person say!");
}
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;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
}
测试:注:MyTestUtil是我用反射写的用于打印对象的属性值工具类。
public static void main(String[] args) {
Class demo1 = null;
try {
demo1 = Class.forName("study.javacore.test.Person");
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
Class demo = Person.class;
System.out.println(demo1 == demo);// true
System.out.println(demo.getPackage());// 包名
System.out.println(demo.getModifiers());// 访问权限修饰符,0就是没有
MyTestUtil.print(demo.getConstructors());// 构成方法
MyTestUtil.print(demo.getDeclaredFields());// 字段信息
MyTestUtil.print(demo.getMethods());// 方法信息
}
获取类的实例
获取累的实例有两种方法:
通过Class对象的newInstance方法,创建此 Class 对象所表示的类的一个新实例。
try {
// 调用的是无参的构成方法,如果没有无参数的构造方法报错。
Person person =(Person) demo.newInstance();
person.setAge(10);
person.setName("klguang");
MyTestUtil.printWithSign("person", person);
} catch (Exception e) {
System.out.println("Class newInstance wrong!!!");
e.printStackTrace();
}
通过Constructor对象,获取类的实例。
try {
Class[] types = new Class[] { int.class, String.class };
Constructor constructor = demo.getConstructor(types);
Person person2 = constructor.newInstance(20, "klguang");
MyTestUtil.printWithSign("person2", person2);
} catch (Exception e) {
System.out.println("::constructor wrong!!!");
e.printStackTrace();
}
操作实例的属性
可通过Class对象的getDeclaredFields() 或getDeclaredField(String name) 方法取得字段Field对象,然后调用field.setAccessible(true),允许访问字段,最后用field.set(Object obj,Object value)或field.get(Object obj)来设置和获取字段的值。
Person person3=new Person(20,"klguang");
Field[] fileds = demo.getDeclaredFields();
for (Field field : fileds) {
field.setAccessible(true);// 设置些属性是可以访问的
String name=field.getName();//取得field的名称
try {
Object value = field.get(person3);// 得到此属性的值
System.out.println("fieldName:"+name+"\tfieldValue:"+value);
if(name.equals("age"))
field.set(person3, 40);
} catch (Exception e) {
e.printStackTrace();
}
}
MyTestUtil.printWithSign("person after access filed", person3);
调用实例的方法
可通过Class对象的getMethods() 或getMethod(String name, Class>...parameterTypes)方法取得Method对象,通过method.invoke(Object obj, Object... args)调用obj对象的方法。
Person person4=new Person(20,"klguang");
Method methods[] = demo.getMethods();
for (java.lang.reflect.Method method : methods) {
if (method.getName().startsWith("get")) {
try {
Object value=method.invoke(person4, null);
System.out.println("method invoke , return value is "+value);
} catch (Exception e) {
System.err.println("method invoke wrong!!");
}
}
}
反射实践,控制台打印工具类
我用反射写了一个打印对象的属性值工具类MyTestUtil,在控制台格式化输出对象属性。因此,可以不用在以后测试javabean时候,复写toString();当然复写了更好。
该工具类用到的反射方法如下:
/**
*
*
* @param object
* @param recursion
* 是否要递归
* @return
*/
private static String beanToStr(Object object, boolean recursion) {
if (object == null)
return "null";
Class clazz = object.getClass();
StringBuilder sb = new StringBuilder();
//返回源代码中给出的底层类的简称
sb.append(clazz.getSimpleName()).append("[");
Field[] fields = sortFieldByType(clazz.getDeclaredFields());
int iMax = fields.length - 1;
if (iMax == -1)
return sb.append("]").toString();
for (int i = 0;; i++) {
Field field = fields[i];
field.setAccessible(true);// 设置些属性是可以访问的
String name = field.getName();// 取得field的名称
if (name.equals("serialVersionUID"))
continue;
try {
Object value = field.get(object);// 得到此属性的值
if (isSimpleType(value) || !recursion)
sb.append(name + " = " + String.valueOf(value));
else
sb.append("\r\n" + indent(clazz.getSimpleName().length() + 2," ")
+ objToStr(value, false) + "\r\n");
} catch (Exception e) {
e.printStackTrace();
}
if (i == iMax)
return sb.append("]").toString();
sb.append(",");
}
}