一、什么是反射?
Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法。
二、反射机制的优点与缺点
为什么要用反射机制?
直接创建对象不就可以了吗,这就涉及到了动态与静态的概念
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
优点:
可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
缺点
对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
三、理解Class类和类类型
想要了解反射首先理解一下Class类,它是反射实现的基础。
类是java.lang.Class类的实例对象,而Class是所有类的类(There is a class named Class)对于普通的对象,我们一般都会这样创建和表示:
Code code1 = new Code();
上面说了,所有的类都是Class的对象,那么如何表示呢,可不可以通过如下方式呢:
Class c = new Class();
但是我们查看Class的源码时,是这样写的:
private Class(ClassLoader loader) {
classLoader = loader;
}
可以看到构造器是私有的,只有JVM可以创建Class的对象,因此不可以像普通类一样new一个Class对象,虽然我们不能new一个Class对象,但是却可以通过已有的类得到一个Class 对象,共有三种方式,如下:
Class c1 = Code.class;
这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的
Class c2 = code1.getClass();
code1是Code的一个对象,这种方式是通过一个类的对象的getClass()方法获得的
Class c3 = Class.forName("com.trigl.reflect.Code");
这种方法是Class类调用forName方法,通过一个类的全量限定名获得
四、具体示例:
public class ReflectDemo {
public int id;
private String name;
private int age;
public String tell;
public String email;
public ReflectDemo() {
super();
}
public ReflectDemo(int id, String name, int age, String tell, String email) {
super();
this.id = id;
this.name = name;
this.age = age;
this.tell = tell;
this.email = email;
}
public String toString() {
return "Demo [id=" + id + ", name=" + name + ", age=" + age + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("setName:"+name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getTell() {
return tell;
}
public void setTell(String tell) {
this.tell = tell;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
/**
*
* @description:获取Class对象的三种方式
* @author liushaocheng
* @created 2016-6-26 上午9:40:34
* @throws ClassNotFoundException
*/
@Test
public void getClazz() throws ClassNotFoundException {
//第一种:通过获取类的静态成员变量class得到
Class<ReflectDemo> class1 = ReflectDemo.class;
System.out.println(class1.getName());
//第二种:通过一个类的对象的getClass()方法获得
ReflectDemo reflectDemo = new ReflectDemo();
Class<ReflectDemo> class2 = (Class<ReflectDemo>) reflectDemo.getClass();
System.out.println(class2.getName());
//第三种:通过一个类的全量限定名获得
Class<ReflectDemo> class3 = (Class<ReflectDemo>) Class.forName("reflect.demo.ReflectDemo");
System.out.println(class3.getName());
}
看运行效果:
知道了获取Class对象的方式后,看一下反射的相关操作:
1、获取类的Fileds
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA 的Class类提供了几个方法获取类的属性。
/**
*
* @description 获取属性
* @author liushaocheng
* @created 2016-6-26 上午10:08:48
*/
@Test
public void getField() {
Class<ReflectDemo> classType = ReflectDemo.class;
//使用getFields()获取属性
Field[] fields = classType.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println();
//使用getDeclaredFields()获取属性
fields = classType.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
运行效果:
可见getFields和getDeclaredFields区别:
getFields返回的是申明为public的属性,包括父类中定义,
getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。
2、获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法Class类提供了几个方法获取类的方法。
/**
*
* @description 获取类的方法
* @author liushaocheng
* @created 2016-6-26 上午10:22:53
*/
@Test
public void getMethod() {
Class<ReflectDemo> classType = ReflectDemo.class;
//使用getMethods()获取类的方法
Method[] methods = classType.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println();
//使用getDeclaredMethods()获取类的方法
methods = classType.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
运行效果:
可见getMethods()和getDeclaredMethods()的区别:
getMethods返回的是申明为public的方法,包括父类中定义,
getDeclaredFields返回的是指定类定义的所有定义的方法,不包括父类的。
3、获取类的构造器
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 Class类提供了几个方法获取类的构造器。
/**
*
* @description 获取类的构造器
* @author liushaocheng
* @created 2016-6-26 上午10:37:43
*/
@Test
public void getConstructor() {
Class<ReflectDemo> classType = ReflectDemo.class;
//使用getConstructors()获取类的构造器方法
Constructor<?>[] constructors = classType.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println();
constructors = classType.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
运行效果:
可见getConstructors()和getDeclaredConstructors()的区别:
getConstructors返回的是申明为public的构造器,包括父类中定义,
getDeclaredConstructors返回的是指定类定义的所有定义的构造器,不包括父类的。
4、新建类的实例
通过反射机制创建新类的实例,有几种方法可以创建
/**
*
* @description 新建类的实例
* @author liushaocheng
* @created 2016-6-26 上午10:45:57
* @throws InstantiationException
* @throws IllegalAccessException
* @throws SecurityException
* @throws NoSuchMethodException
*/
@Test
public void newClass() throws Exception {
//1、调用类的Class对象的newInstance()方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败
Class<ReflectDemo> classType = ReflectDemo.class;
ReflectDemo newInstance = classType.newInstance();
System.out.println(newInstance);
System.out.println();
//2、调用默认Constructor对象的newInstance()方法
Constructor<ReflectDemo> constructor = classType.getConstructor();
ReflectDemo newInstance2 = constructor.newInstance();
System.out.println(newInstance2);
System.out.println();
//3、调用带参数Construtctor对象的newInstance()方法
Constructor<ReflectDemo> declaredConstructor = classType.getDeclaredConstructor(int.class, String.class, int.class, String.class, String.class);
ReflectDemo newInstance3 = declaredConstructor.newInstance(1,"123",20,"123456789","123456789@qq.com");
System.out.println(newInstance3);
}
运行效果:
5、调用类的方法
/**
*
* @description 调用类的方法
* @author liushaocheng
* @created 2016-6-26 上午11:07:12
* @throws Exception
*/
@Test
public void transferMethod() throws Exception {
Class<ReflectDemo> classType = ReflectDemo.class;
ReflectDemo newInstance = classType.newInstance();
Method declaredMethod = classType.getDeclaredMethod("setName", String.class);
declaredMethod.invoke(newInstance, "123");
}
运行效果:
6、设置/获取类的属性
/**
*
* @description 设置/获取类的属性
* @author liushaocheng
* @created 2016-6-26 上午11:21:12
* @throws Exception
*/
@Test
public void setUpOrgetField() throws Exception {
Class<ReflectDemo> classType = ReflectDemo.class;
ReflectDemo newInstance = classType.newInstance();
Field field = classType.getDeclaredField("tell");
field.set(newInstance, "123");
Object value = field.get(newInstance);
System.out.println(value);
}
运行结果: