今天的讨论主题又是老生常谈,Java反射的鼎鼎大名我想诸君多多少少都有所耳闻。正所谓难者不会会者不难,对于了解反射机制的人来讲也就那么一回事,但对初学者来讲确犹如隔雾看山。今天笔者一样会以尽可能通俗的文字来同你们一块儿揭开反射神秘的面纱。java
可以分析类能力的程序被称为反射(reflective),经过反射能够在运行时(而不是在编译时)动态地分析软件组件并描述组件的功能。框架
首先咱们要明确一点,反射并非什么很难很高深的东西。正相反,反射其实就是Java系统提供给咱们的一系列API,具体来讲就是由java.lang.reflect包提供的。就跟调用其余API一个道理,咱们只要了解了这个API用法,那就掌握了反射。函数
所谓存在即合理,既然Java给咱们提供了这个功能,那么它必定是有用的。那它具体有啥用?经过反射,咱们能够spa
试想这样一个场景,咱们有一个产品类code
public class Product {
private String mName;
private int mPrice;
}
复制代码
而后咱们如今要弄一个工厂类来生产这个产品。对象
有朋友说这有何难?看个人开发
public class Factory {
public Product create(){
return new Product();
}
}
复制代码
而后调用这个工厂来生产便可get
public class Client {
public static void main(String[] args) {
Factory mFactory = new Factory();
Product product = mFactory.create();
}
}
复制代码
乍一看好像没毛病,工厂生产的时候new一个Product不就完事了吗。string
那好,我如今要求这个工厂要生产两个不一样的产品又咋整?产品
朋友说,那也简单,我再加一个create方法不就好了
class Factory {
public ProductA createA(){
return new ProductA();
}
public ProductB createB(){
return new ProductB();
}
}
复制代码
那如今问题就来了:
有杠精可能会说:你是否是在存心刁难我?我本身写的程序我还不晓得它要生产个啥?
你还别说,还真会有这种状况。试想假如你如今是在开发一个框架给别人用,这个Product类是交由这个框架的使用者来定义的,那你怎么能知作别人究竟是定义了一个牛仍是一个马?那我如今要生产这个东西,可是我又不知道究竟是要生产一个啥玩意儿,那咋整?
嗯。。。好像确实不行。
那能不能有这样一种牛逼的技术,一个方法就能够生产一万个不一样的产品,甚至我不知道它具体是个啥东西我都能生产出来?
巧了,还真有,这个牛逼的技术就是咱们今天所说的反射。
咱们对工厂类进行改写
public class Factory {
public <T> T create(Class clazz){
Object object = null;
try {
object = Class.forName(clazz.getName()).newInstance();
} catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
e.printStackTrace();
}
return (T)object;
}
}
复制代码
而后生产
public class Client {
public static void main(String[] args) {
Factory mFactory = new Factory();
Product product = mFactory.create(Product.class);
}
}
复制代码
好了,这样咱们就使用反射建立了一个产品的实例。要建立多个不一样的产品,只须要传入不一样的参数便可。
如今来解释一下这个create方法。
首先咱们定义返回类型为泛型T,方法的形参为Class类型代表传入的是一个类。
而后Class.forName方法是经过类加载器来加载这个类,加载的实现遵循双亲委派机制。关于双亲委派机制的原理后面会写专栏介绍。
最后调用newInstance方法来返回这个类的实例。
这样咱们就经过反射得到了一个类的对象,而且在这个过程当中咱们并不关心这个加载的类究竟是个啥东西。
除了获取类的对象以外,反射还能够分析类的能力。
咱们先给产品类整几个构造函数
public class Product {
private String mName;
private int mPrice;
public Product() { }
public Product(String name) {
mName = name;
}
public Product(int price) {
mPrice = price;
}
public Product(String name, int price) {
mName = name;
mPrice = price;
}
}
复制代码
而后改写工厂类
public class Factory {
public void create(Class clazz){
//得到构造函数
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("" + constructor);
}
}
}
复制代码
跑一下看看结果
public com.samiu.archi.reflect.Product(java.lang.String,int)
public com.samiu.archi.reflect.Product(int)
public com.samiu.archi.reflect.Product(java.lang.String)
public com.samiu.archi.reflect.Product()
复制代码
OK,这不就把构造函数打印粗来了。
咱们对产品类进行改写,多整几个变量
public class Product {
//私有变量
private String mName;
private int mPrice;
//公共变量
public float width;
public float height;
}
复制代码
而后改写工厂类
public class Factory {
public void create(Class clazz){
//得到fields
Field[] fields = clazz.getFields();
System.out.println("fields:");
for (Field field : fields) {
System.out.println("" + field);
}
//得到declaredFields
Field[] declaredFields = clazz.getDeclaredFields();
System.out.println("declaredFields:");
for (Field field : declaredFields) {
System.out.println("" + field);
}
}
}
复制代码
打印一下结果
fields:
public float com.samiu.archi.reflect.Product.width
public float com.samiu.archi.reflect.Product.height
declaredFields:
private java.lang.String com.samiu.archi.reflect.Product.mName
private int com.samiu.archi.reflect.Product.mPrice
public float com.samiu.archi.reflect.Product.width
public float com.samiu.archi.reflect.Product.height
复制代码
能够看到,getFields方法获取了类的公共变量,而getDeclaredFields方法获取了类的全部变量,包括私有变量
咱们先改写产品类,给它多整几个方法
public class Product {
private String mName;
private int mPrice;
public String getName() {
return mName;
}
private void setName(String name) {
mName = name;
}
public int getPrice() {
return mPrice;
}
private void setPrice(int price) {
mPrice = price;
}
}
复制代码
而后改写工厂类
public class Factory {
public void create(Class clazz){
//得到methods
Method[] methods = clazz.getMethods();
System.out.println("methods:");
for (Method method:methods){
System.out.println(""+method);
}
System.out.println("");
//得到declaredMethods
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println("declaredMethods:");
for (Method method:declaredMethods){
System.out.println(""+method);
}
}
}
复制代码
打印一下看看
methods:
public java.lang.String com.samiu.archi.reflect.Product.getName()
public int com.samiu.archi.reflect.Product.getPrice()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
declaredMethods:
public java.lang.String com.samiu.archi.reflect.Product.getName()
private void com.samiu.archi.reflect.Product.setName(java.lang.String)
private void com.samiu.archi.reflect.Product.setPrice(int)
public int com.samiu.archi.reflect.Product.getPrice()
复制代码
能够看到,getMethods获取了类的全部公共方法,包括定义在Object类里面的公共方法,而getDeclaredMethods则获取了类本身定义的全部方法,包括私有的方法。
除了这些之外,反射还有不少实用的功能,这里就不展开细讲了,感兴趣的朋友能够本身去查阅。
今天回顾了一下Java的反射,但愿能帮到一些朋友大体弄明白反射的机制。
1.《Java核心技术 第八版》
2.《Java彻底参考手册 第八版》