一、什么是反射:
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提 出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中 LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。
反射本身并不 是一个新概念,尽管计算机科学赋予了反射概念新的含义。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机 制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用 所描述行为的状态和相关的语义。
二、什么是Java中的类反射:
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。Java 的这一能力在实际应用中用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。
Reflection 是 Java 被视为动态(或准动态)语言的关键,允许程序于执行期 Reflection APIs 取得任何已知名称之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可于执行期生成instances、变更 fields 內容或唤起 methods。
三、Java类反射中所必须的类:
Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
反射的功能及其作用
功能如下:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理。
具体作用
假如有两个程序员,一个程序员在写程序的时需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码是不能通过编译的。此时,利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。
Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。如eclipse中,一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。
五:获取Class对象
在使用反射的各种功能之前需要做的是获取Class对象实例,有3种获取class方法的实例如下:
package java反射测试;
/**
* 获取class对象的3种方式
* @author xuxiao
*
*/
public class classLoader {
public static void main(String[] args) throws ClassNotFoundException {
//1.通过对象的getClass方法加载其class对象
A a = new A();
Class class1 = a.getClass();
//2.通过字节码文件获取
Class class2=A.class;
//3.通过class类的静态方法获取
Class class3=Class.forName("java反射测试.A");
//测试它们相等吗?
System.out.println((class1==class2)+" "+(class1==class3));
}
}
最后输出的结果也是true,true,很好理解,不加说明了。
六:获取一个对象的父类与实现的接口
package java反射测试;
import java.io.Serializable;
/**
* 获取一个对象的父类与实现的接口
* @author xuxiao
*
*/
public class TestReflect implements Serializable {
private static final long serialVersionUID = -2862585049955236662L;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java反射测试.TestReflect");
// 取得父类
Class<?> parentClass = clazz.getSuperclass();
System.out.println("clazz的父类为:" + parentClass.getName());
Class<?> intes[] = clazz.getInterfaces();
System.out.println("clazz实现的接口有:");
for (int i = 0; i < intes.length; i++) {
System.out.println((i + 1) + ":" + intes[i].getName());
}
}
}
执行結果:
clazz的父类为:java.lang.Object
clazz实现的接口有:
1:java.io.Serializable
七:通过反射机制实例化一个类的对象
package java反射测试2;
import java.lang.reflect.Constructor;
/**
* 通过反射机制实例化一个类的对象
* @author xuxiao
*
*/
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> class1 = null;
class1 = Class.forName("java反射测试2.User");
// 第一种方法,实例化默认构造方法,调用set赋值(自jdk9之后只推荐第二种,不推荐第一种)
User user = (User) class1.newInstance();
user.setAge(20);
user.setName("Rollen");
System.out.println(user);
// 结果 User [age=20, name=Rollen]
// 第二种方法 取得全部的构造函数 使用构造函数赋值
Constructor<?> cons[] = class1.getConstructors();
// 查看每个构造方法需要的参数
for (int i = 0; i < cons.length; i++) {
Class<?> clazzs[] = cons[i].getParameterTypes();
System.out.print("cons[" + i + "] (");
for (int j = 0; j < clazzs.length; j++) {
if (j == clazzs.length - 1)
System.out.print(clazzs[j].getName());
else
System.out.print(clazzs[j].getName() + ",");
}
System.out.println(")");
}
// 结果
// cons[0] (java.lang.Integer,java.lang.String)
// cons[1] (java.lang.String)
// cons[2] ()
user = (User) cons[1].newInstance("xuxiao");
System.out.println(user);
// 结果 User [age=0, name=xuxiao]
user = (User) cons[0].newInstance(20, "xuxiao");
System.out.println(user);
// 结果 User [age=20, name=xuxiao]
}
}
class User {
private Integer age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this.name = name;
}
public User(Integer age, String name) {
super();
this.age = age;
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
}
执行结果
User [age=20, name=Rollen]
cons[0] (java.lang.Integer,java.lang.String)
cons[1] (java.lang.String)
cons[2] ()
User [age=null, name=xuxiao]
User [age=20, name=xuxiao]
八:通过反射获取某个类的全部属性,以及父类和实现接口的部分属性
package java反射测试3;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 通过反射获取某个类的全部属性,以及父类和实现接口的部分属性
* @author xuxiao
*
*/
public class TestReflect extends father implements Serializable {
private static final long serialVersionUID = -2862585049955236662L;
public int a;
public String b;
@SuppressWarnings("unused")
private byte e;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java反射测试3.TestReflect");
System.out.println("===============本类属性===============");
// 取得本类的全部属性
Field[] field = clazz.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 权限修饰符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class<?> type = field[i].getType();
System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");
}
System.out.println("==========实现的接口或者父类的属性==========");
// 取得实现的接口或者父类的属性
Field[] filed1 = clazz.getFields();
for (int j = 0; j < filed1.length; j++) {
// 权限修饰符
int mo = filed1[j].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class<?> type = filed1[j].getType();
System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";");
}
}
}
package java反射测试3;
public class father {
public double d;
public byte c;
@SuppressWarnings("unused")
private Integer i;
}
执行结果:
===============本类属性===============
private static final long serialVersionUID;
public int a;
public java.lang.String b;
private byte e;
==========实现的接口或者父类的属性==========
public int a;
public java.lang.String b;
public double d;
public byte c;
ps:注意到父类属性只能取到public级别的。本类的话能获得全部级别的。
九:通过反射获取某个类的全部方法和异常
package java反射测试4;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* 通过反射获取某个类的全部方法和异常
* @author xuxiao
*
*/
public class TestReflect implements Serializable {
private static final long serialVersionUID = -2862585049955236662L;
public String test1(int i) {
System.out.println(i);
return "success";
}
protected void test2() {
System.out.println("");
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java反射测试4.TestReflect");
Method method[] = clazz.getMethods();
for (int i = 0; i < method.length; ++i) {
Class<?> returnType = method[i].getReturnType();
Class<?> para[] = method[i].getParameterTypes();
int temp = method[i].getModifiers();
System.out.print(Modifier.toString(temp) + " ");
System.out.print(returnType.getName() + " ");
System.out.print(method[i].getName() + " ");
System.out.print("(");
for (int j = 0; j < para.length; ++j) {
System.out.print(para[j].getName() + " " + "arg" + j);
if (j < para.length - 1) {
System.out.print(",");
}
}
Class<?> exce[] = method[i].getExceptionTypes();
if (exce.length > 0) {
System.out.print(") throws ");
for (int k = 0; k < exce.length; ++k) {
System.out.print(exce[k].getName() + " ");
if (k < exce.length - 1) {
System.out.print(",");
}
}
} else {
System.out.print(")");
}
System.out.println();
}
}
}
执行结果:
public static void main ([Ljava.lang.String; arg0) throws java.lang.Exception
public java.lang.String test1 (int arg0)
public final native void wait (long arg0) throws java.lang.InterruptedException
public final void wait (long arg0,int arg1) throws java.lang.InterruptedException
public final void wait () throws java.lang.InterruptedException
public boolean equals (java.lang.Object arg0)
public java.lang.String toString ()
public native int hashCode ()
public final native java.lang.Class getClass ()
public final native void notify ()
public final native void notifyAll ()
十:通过反射机制调用某个类的方法
package java反射测试5;
import java.lang.reflect.Method;
/**
* 通过反射机制调用某个类的方法
* @author xuxiao
*
*/
public class TestReflect {
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java反射测试5.TestReflect");
// 调用TestReflect类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// Java 反射机制 - 调用某个类的方法1.
// 调用TestReflect的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
// Java 反射机制 - 调用某个类的方法2.
// age -> 20. name -> 张三
}
//无参构造器
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法1.");
}
//有参构造器
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法2.");
System.out.println("age -> " + age + ". name -> " + name);
}
}
执行结果:
Java 反射机制 - 调用某个类的方法1.
Java 反射机制 - 调用某个类的方法2.
age -> 20. name -> 张三
十一:通过反射机制操作某个类的属性
package java反射测试6;
import java.lang.reflect.Field;
/**
* 通过反射机制操作某个类的属性
* @author xuxiao
*
*/
public class TestReflect {
private String proprety = null;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java反射测试6.TestReflect");
Object obj = clazz.newInstance();
// 可以直接对 private 的属性赋值
Field field = clazz.getDeclaredField("proprety");
field.setAccessible(true);//private属性默认不可通过反射修改,设为true之后可修改
field.set(obj, "Java反射机制");
System.out.println(field.get(obj));
}
}
执行结果
Java反射机制
十二:反射应用于工厂模式
package java反射测试7;
interface fruit {
public abstract void eat();
}
class Apple implements fruit {
public void eat() {
System.out.println("Apple");
}
}
class Orange implements fruit {
public void eat() {
System.out.println("Orange");
}
}
//如果是普通工厂模式的话,这里要针对每种水果创建对象
//应用反射可以通过多态和反射来动态创建对象
class Factory {
public static fruit getInstance(String ClassName) {
fruit f = null;
try {
f = (fruit) Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
/**
* 对于普通的工厂模式当我们在添加一个子类的时候,就需要对应的修改工厂类。 当我们添加很多的子类的时候,会很麻烦。
* 现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。
*
*/
public class TestReflect {
public static void main(String[] args) throws Exception {
fruit f = Factory.getInstance("java反射测试7.Apple");
if (f != null) {
f.eat();
}
}
}
十三:反射总结
优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
(2)与Java动态编译相结合,可以实现无比强大的功能
缺点:
(1)使用反射的性能较低
(2)使用反射相对来说不安全
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性
任何事物,都有两面性,反射的优点,也同是就是它的缺点,所以,没有好与坏,只有最合适的场景。