反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等.......
首先要用反射必须要获得某个java类的Class类的对象,有三种方式:
Class<?> clz1 = String.class;
Class<?> clz2 = new String().getClass();
Class<?> clz3 = Class.forName("java.lang.String");
System.out.println(clz1==clz2);//true
System.out.println(clz2==clz3);//true
以上三种方式获得的运行时类的
Class
对象在内存中只有一个,因此直接比较地址是相同的..........
接下来将简单介绍一下Class类中的方法:
一.定义两个个测试类,里面包含一些成员变量,构造器,方法等
1>Person类,包含名字(name)和年龄(age)两个属性
public class Person {
public String name;
private int age;
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 Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person(String name) {
super();
this.name = name;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
2>Man类,继承自Person类,添加了性别(sex)属性
public class Man extends Person {
private char sex;
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public Man(String name, int age, char sex) {
super(name, age);
this.sex = sex;
}
@Override
public String toString() {
return "Man [sex=" + sex + ", toString()=" + super.toString() + "]";
}
}
二.Class类提供了四种方法获取成员变量,分别是getField,getFileds,getDeclaredField,getDeclaredFields
1>getField(String name):返回此 Class
对象所表示的类或接口的指定公共成员字段(从父类继承的也算),如果没有这个字段或者不是public修饰的,则抛出java.lang.NoSuchFieldException
Man user = new Man("张三",20,'男');
Class<?> clz = user.getClass();
Field field = clz.getField("name");
System.out.println(field);//public java.lang.String com.java5.reflect.test.Person.name
field = clz.getField("sex");//java.lang.NoSuchFieldException
2>getFields():
返回此
Class
对象所表示的类或接口的
所有
公共成员字段(
从父类继承的也算)
3>getDeclaredField(String name):返回此 Class
对象指定已声明字段(当前Class对象对应的类中声明的,继承实现的不算)
Man user = new Man("张三",20,'男');
Class<?> clz = user.getClass();
Field field = clz.getDeclaredField("sex");
System.out.println(field);//private char com.java5.reflect.test.Man.sex
field = clz.getDeclaredField("name");//java.lang.NoSuchFieldException
System.out.println(field);
4>getDeclaredFields():返回此
Class
对象所有已声明字段(
当前Class对象对应的类中声明的,继承实现的不算)
获得了Field之后,我们就可以调用各种方法获取相应的信息(注释后面为打印到控制台的值)
Man user = new Man("张三",20,'男');
Class<?> clz = user.getClass();
Field field = clz.getDeclaredField("sex");
System.out.println(user);//Man [sex=男, toString()=Person [name=张三, age=20]]
//sex成员变量是private修饰的,要设置值其accessible为true,否者抛出java.lang.IllegalAccessException异常
field.setAccessible(true);
//设置user对象sex的值
field.set(user, '女');
System.out.println(user);//Man [sex=女, toString()=Person [name=张三, age=20]]
//获取user对象sex的值
System.out.println(field.get(user));//女
//获取属性名
System.out.println(field.getName());//sex
//获取这个属性的访问修饰符,返回值是整形数值,在Modifier有详细的定义
System.out.println(field.getModifiers());//打印2,private在Modifier类中有十六进制表示为0x00000002
//判断这个属性是不是private修饰的,
System.out.println(Modifier.isPrivate(field.getModifiers()));//true
//获得这个属性的类型
System.out.println(field.getType());//char
三.类似的,Class类也提供了四种方法获取类中的方法:getMethod,getMethods,getDeclaredMethod,getDeclaredMethods,这四种方法跟Field里面的类似,只不过把属性换成了方法,因此对这四种方法不再做详细介绍,下面直接介绍Method类里面一些方法的用法..
Man user = new Man("张三",20,'男');
Class<?> clz = user.getClass();
Method method = clz.getDeclaredMethod("setSex", char.class);
System.out.println(user);//Man [sex=男, toString()=Person [name=张三, age=20]]
//判断该方法是不是private修饰的
System.out.println(Modifier.isPrivate(method.getModifiers()));//false
//如果是private修改的,则需要修改accessible为true,否者执行invoke方法报java.lang.IllegalAccessException
//method.setAccessible(true);
//相当于执行user.setSex('女')方法
method.invoke(user, '女');
System.out.println(user);//Man [sex=女, toString()=Person [name=张三, age=20]]
//获取方法名
System.out.println(method.getName());//setSex
//获取声明次method对象的类名
System.out.println(method.getDeclaringClass());//class com.java5.reflect.test.Man
//获取返回值类型
System.out.println(method.getReturnType());//void
//获取参数的类型
Class<?>[] clzs = method.getParameterTypes();
System.out.println(clzs[0].getName());//char
//判断是否带有可变参数
System.out.println(method.isVarArgs());//false
//获取方法上声明的注解
Annotation[] annotations = method.getDeclaredAnnotations();
System.out.println(annotations.length);//0