1.Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
一个反射的例子
package reflections;
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = 2567283942398849L;
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
public void show(){
System.out.println("姓名:"+this.name+" 年龄:"+this.age);
}
public void display(String nation){
System.out.println("姓名:"+this.name+" 年龄:"+this.age + " 国籍:"+nation);
}
}
package reflections;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestReflection {
public static void main(String[] args) {
}
//使用反射
@Test
public void testPerson() throws Exception{
Class clazz=Person.class;
//1.创建clazz对应的运行时的类Person的对象
Person p=(Person) clazz.newInstance();
System.out.println(p);
//2.通过反射调用指定的属性
//调用声明为public的属性
Field f1=clazz.getField("name");
f1.set(p, "linlin");
//调用声明为private的属性
Field f2=clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.set(p, 18);
System.out.println(p);
//3.通过反射调用运行时类指定的方法
Method m1=clazz.getMethod("show");
m1.invoke(p);
Method m2=clazz.getMethod("display",String.class);
m2.invoke(p,"CN");
}
}
2.深入理解反射
java.lang.Class是反射的源头。
创建一个类,通过编译(javac.exe),生成对此应的.class文件,之后使用 java.exe加载(用JVM加载器完成)。这个.class文件加载到内存后,就是一个运行时类,存放在缓存区。这个运行时类本身就是一个Class的实例。
1. 每个运行时类只加载一次。
2. 有了Class的实例以后,可以进行如下操作:
a) 创建对应的运行时类的对象
b) 获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解)
c) 调用对应的运行时类的指定结构(属性、方法、构造器)
d) 反射的应用:动态代理
调用Class对象的newInstance()方法,要求:
1)类必须有一个无参数的构造器。2)类的构造器的访问权限需要足够。
难道没有无参的构造器就不能创建对象了吗?
不是!只要在操作的时候明确的调用类中的构造方法,并将参数传递进去之后,才可以实例化操作。步骤如下:
1)通过Class类的getDeclaredConstructor(Class… parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)在Constructor类中存在一个方法:
public T newInstance(Object … initargs)2.1 获取Class的实例的方法
//获取运行类实例的方法
@Test
public void testReflection1(){
//方式1:调用运行时类本身的.class属性
Class clazz1=Person.class;
System.out.println(clazz1);
//方式2:通过运行时类的对象获取
Person p = new Person();
Class clazz2=p.getClass();
System.out.println(clazz2);
//方式3:通过Class的静态方法获取
String className="reflections.Person";
Class clazz3;
try {
clazz3 = Class.forName(className);
System.out.println(clazz3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式4:通过类的加载器
ClassLoader cl=this.getClass().getClassLoader();
Class clazz4;
try {
clazz4 = cl.loadClass(className);
System.out.println(clazz4);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
2.2 类加载器
类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构。
@Test
public void testClassLoader() throws IOException{
//在源文件目录下获取文件
ClassLoader loader=this.getClass().getClassLoader(); //获取类加载器
InputStream is = loader.getResourceAsStream("reflections\\jdbc.properties");
Properties pros=new Properties();
pros.load(is);
String name = pros.getProperty("user");
System.out.println(name);
//在当前工程目录下获取文件
InputStream is1 = new FileInputStream(new File("jdbc1.properties"));
Properties pros1=new Properties();
pros.load(is1);
String name1 = pros.getProperty("pwd");
System.out.println(name1);
}
2.3 获取运行时类的结构
//通过反射获取类的属性
@Test
public void testGetFields(){
Class clazz = Person.class;
//getFields()获取运行时类中及其父类中声明为public的属性
Field[] fields = clazz.getFields();
for(int i=0;i<fields.length;i++){
System.out.println(fields[i]);
}
System.out.println();
//getDeclaredFields()获取类本身声明的所有属性(不包含父类的属性)
Field[] fields2 = clazz.getDeclaredFields();
for(Field v:fields2){
System.out.println(v);
}
}
//获取每个属性的各部分内容:权限修饰符,变量类型,变量名
@Test
public void testGetFieldContent(){
Class clazz = Person.class;
Field[] fs1 = clazz.getDeclaredFields();
for(Field f : fs1){
//获取权限修饰符
int b= f.getModifiers();
System.out.println(Modifier.toString(b));
//获取属性类型
System.out.println((f.getType()).getName());
//获取属性名
System.out.println(f.getName());
System.out.println();
}
}
//获取运行时方法
@Test
public void testGetMethods(){
Class clazz = Person.class;
//获取运行时类及其父类中所有的声明为public的方法
Method[] mds = clazz.getMethods();
for(Method m : mds){
System.out.println(m);
}
System.out.println();
//获取运行时类定义的所有方法
Method[] mds2 = clazz.getDeclaredMethods();
for(Method m : mds2){
System.out.println(m);
}
}
//获取方法的相关内容:注解,权限修饰符,返回值类型,方法名,形参列表,异常
@Test
public void testGetMethod2(){
Class clazz = Person.class;
Method[] mds2 = clazz.getDeclaredMethods();
for(Method m : mds2){
//注解
Annotation[] anns = m.getAnnotations();
for(Annotation a : anns ){
System.out.println(anns);
}
//权限修饰符
String str = Modifier.toString(m.getModifiers());
System.out.println(str);
//返回值类型
Class returnType = m.getReturnType();
System.out.println(returnType.getName());
//方法名
System.out.println(m.getName());
//形参列表
Class[] params = m.getParameterTypes();
for(int i =0;i<params.length;i++){
System.out.println("arg-" + i + ":" + params[i].getName());
}
//异常
Class[] exps = m.getExceptionTypes();
for(int i =0;i<exps.length;i++){
System.out.println("exp-" + i + ":" +exps[i].getName());
}
System.out.println();
}
}
//获取构造器
@Test
public void getConstructor(){
Class clazz = null ;
try {
clazz = Class.forName("reflections.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor c : cons){
System.out.println(c);
}
}
//获取运行时类的父类
@Test
public void getSuperclass(){
Class clazz = null ;
try {
clazz = Class.forName("reflections.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取父类
Class sc = clazz.getSuperclass();
System.out.println(sc);
//获取带泛型的父类
Type t1 = clazz.getGenericSuperclass();
System.out.println(t1);
//获取父类的泛型
Type t2 = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType) t2;
Type[] ars = param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());
}
//获取实现的接口
@Test
public void getInterface(){
Class clazz = null ;
try {
clazz = Class.forName("reflections.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class[] interfaces = clazz.getInterfaces();
for(Class i : interfaces){
System.out.println(i);
}
}
//获取所在的包
@Test
public void getPackage(){
Class clazz = null ;
try {
clazz = Class.forName("reflections.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Package ps = clazz.getPackage();
System.out.println(ps);
}
//获取注解
@Test
public void getAnnotation(){
Class clazz = null ;
try {
clazz = Class.forName("reflections.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Annotation[] as = clazz.getAnnotations();
for(Annotation a : as)
System.out.println(a);
}
2.4 获取运行时类指定的属性、方法、构造器
// 通过反射获取类的指定属性
@Test
public void testGetField()
throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
Class clazz = Person.class;
// 获取指定属性
Field name = clazz.getField("name");
// 创建运行时类
Person p = (Person) clazz.newInstance();
System.out.println(p);
// 设置类的public属性
name.set(p, "zhang");
System.out.println(p);
Field age = clazz.getDeclaredField("age");
// 设置类的private属性为可进入
age.setAccessible(true);
// 设置类的private属性
age.set(p, 22);
System.out.println(p);
Field id = clazz.getDeclaredField("id");
// 设置类的default属性为可进入
// id.setAccessible(true);
// 设置类的default属性
id.set(p, 11);
System.out.println(p);
}
// 获取运行类实例的指定的方法
@Test
public void getMethod() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
Class clazz = Person.class;
// 创建实例
Person p = (Person) clazz.newInstance();
//获取指定的声明为public方法:public Method getMethod(String name,Class<?>... parameterTypes)
Method m1 = clazz.getMethod("show");
// 调用指定的方法 :invoke(Object obj, Object... args)
Object retVal = m1.invoke(p); //无返回值,返回null
System.out.println(retVal);
//getMethod()获取指定的声明为public方法
Method m2 = clazz.getMethod("toString");
// 获取返回值对象
Object retVal2 = m2.invoke(p);//有返回值,返回null
System.out.println(retVal2);
//调用public静态方法
Method m3 = clazz.getMethod("info");
m3.invoke(p);
//调用非public的方法:Method getDeclaredMethod(String name,Class<?>... parameterTypes)
Method m4 = clazz.getDeclaredMethod("display", String.class,Integer.class);
m4.setAccessible(true);
Object retVal4 = m4.invoke(p, "CN",10);
System.out.println(retVal4);
}
//获取指定的构造器
@Test
public void getConstructor() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class clazz = null;
try {
clazz = Class.forName("reflections.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Constructor con = clazz.getConstructor(String.class,int.class);
con.setAccessible(true);
Person p = (Person) con.newInstance("zhangli",26);
System.out.println(p);
}