反射机制最重要的内容--检查类的结构
Java中java.lang.reflect下有三个类Field,Method和Constructor分别用于描述类的域方法和构造器
这三个类中都要一个GetName的方法,用来返回项目的名称
Field中有个GetType方法,用来描述域所属类型的Class对象
Method中还有一个报告返回值的方法,getReturnType()...
Class类中的getField(),getMethods(),getConstructors()方法
将分别返回类提供的public域,方法和构造器 数组,其中包含父类的共有成员
Class类中的getDeclareField(),getDeclareMethods(),getDeclareConstructors()方法
将分别返回类中声明的全部域,方法和构造器其中包括私有和保护成员,但不包括父类中的成员
这三个类中还有一个叫GetModifiers返回的是个整形,
例如可以用Modifier类中的isPublic isFinal...判断属性方法构造器是否是公共 不可变的...
还可以调用Modifier.toString方法将修饰符打印出来
Modifier.isStatic(f.getModifiers()) 返回boolean
Modifier.toString(f.getModifiers()) 返回String
首先我们学习怎么获得一个类的Class对象?
三种方法如下:
class Test
{
public String name;
private int age;
private int[] nums = {1, 2, 3};
public Test() {}
public Test(String name, int age)
{
this.name = name;
this.age = age;
}
}
public class TestReflect
{
public static void main(String[] args)
{
//获取一个类的Class对象的三种方法
//1.
Test test1 = new Test();
Class c1 = test1.getClass();
String className1 = c1.getName();
//"Test" (类名,如果类在包里面包的名字也作为类名的一部分)
//2.通过调用静态方法forName获得类名对应的Class对象,这个会抛出受查时异常
try
{
String className2 = "Test";
Class c2 = Class.forName(className2);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
//这个方法还可以快速创建一个类的实例(当不确定创建什么类时可用)
String s = "java.util.Date";
try
{
Object m = Class.forName(s).newInstance();
//调用的是默认构造方法,如果想要调用有参构造,
//必须使用Constructor类中的newInstance方法
}
catch (Exception e)
{
e.printStackTrace();
}
//3. 简单,int.class也可以返回一个Class对象
Class c3 = Test.class;
}
}
下面我们利用反射写一个所有类通用的toString方法(私有域也能访问)
这个公认的一种写法,到后面你会发现会很有用的!!(注释详细)
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
//通用的toString
class ObjectAnalyzer
{
private ArrayList<Object> visited = new ArrayList<>();
//用来记录已经被访问的对象,防止无限递归
public String toString(Object obj)
{
if(obj == null) return "null";
if(visited.contains(obj)) return "...";
visited.add(obj);
Class c1 = obj.getClass();
//传来的是个字符串
if(c1 == String.class)
{
return (String)obj;
}
//传来的是个数组
if(c1.isArray())
{
//cl.getComponentType()返回数组 构成元素的类型
String r = c1.getComponentType() + "[]{";
for (int i = 0; i < Array.getLength(obj); i++)
{
if(i > 0) r += ",";
Object val = Array.get(obj, i);
if(c1.getComponentType().isPrimitive()) //数组里面存的是基本类型
{
r += val;
}
else //不是去递归
{
r += toString(val);
}
}
return r + "}";
}
//传来的是个自定义类型,里面可能包含多个基本类型或引用类型
String r = c1.getName();
do
{
r += "[";
Field[] fields = c1.getDeclaredFields();
//拿到obj里面所有的数据域(名字和访问权限)
AccessibleObject.setAccessible(fields, true);
//设置为true,代表忽略Java中的访问控制
for(Field f : fields)
{
if(!Modifier.isStatic(f.getModifiers())) //如果不是静态的
{
if(!r.endsWith("["))
{
r += ",";
}
r += f.getName() + "=";
try
{
Class t = f.getType();
Object val = f.get(obj);
if(t.isPrimitive()) //是基本类型
{
r += val;
}
else //不是就去递归
{
r += toString(val);
}
}
catch (Exception e) { e.printStackTrace(); }
}
}
r += "]";
c1 = c1.getSuperclass();
}while(c1 != null);
return r;
}
}
测试代码:
class Test
{
public String name;
private int age;
private int[] nums = {1, 2, 3};
public Test() {}
public Test(String name, int age)
{
this.name = name;
this.age = age;
}
public static void main(String[] args)
{
Test test = new Test("Tom", 18);
String ret = new ObjectAnalyzer().toString(test);
System.out.println(ret);
//运行结果:Test[name=Tom,age=18,nums=int[]{1,2,3}][]
}
}
下面是Field类中全部方法: