认识反射机制
初识反射
反射是指对象的反向操作,既然是反向操作处理。那先来观察一下正向的操作。
import java.util.Date;
public static void main (String[] args){
Date date = new Date();
}
}
以上便是我们一般关于对象的处理流程:根据包名.类名 找到类;
所谓“反”指的是根据对象取得来取得对象的来源信息,而这个“反”的操作核心的处理就在于Object类的一个方法:取得Class对象:
public final native Class<?> getClass();
该方法返回的是一个Class类的对象,这个Class描述的就是类。
如:调用getClass()方法
package reflect;
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.getClass());
}
}
//+++++++++++++++++++++++++++++++++++
class java.util.Date
此时便是通过对象去的了对象的来源,这就是“反”的本质。
在反射的世界里面,看重的不再是一个对象,而是对象身后的组成(类、构造、成员等)
Class类对象的三种实例化模式
Class类是描述整个类的概念,也是整个反射的操作源头,在使用Class类的时候鱼药关注的依然是这个类的对象。而这个类的对象的产生模式一共有三种:
- 任何类的实例化对象都可以通过Object类中的getClass()方法取得Class类对象。
- “类.class”:直接根据某个具体的类来取得Class类的实例化对象。
- 使用Class类提供的方法:public static Class< ?>forName(String className) throws ClassNotFoundException
使用Class.forName()方法:
package reflect;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("java.util.Date");
System.out.println(cls.getName());
}
}
//++++++++++++++++++++++++++++++++++++++++++++
java.util.Date
在以上给出的三个方法中可以发现,除了第一种方法会产生Date类对象的实例化对象之外,其他的两种都不会产生Date类的实例化对象。于是取得了Class类对象有一个最直接的好处:可以通过反射实例化对象,在Class类中定义有如下方法:
public T newInstance()throws InstantiationException,IllegalAccessException
如:
public class Test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> cls = Class.forName("java.util.Date");
Object obj = cls.newInstance();//结果和下句结果相同
// Object obj = new java.util.Date();
System.out.println(obj);
}
}
//+++++++++++++++++++++
Fri Jun 01 15:59:46 GMT+08:00 2018
所以除了new之外,对象的实例化模式有了新的方式。
取得lClass对象就意味着取得了一些指定类的操作权限。
反射与工厂设计模式
工厂设计模式的原则:如果是自己编写的接口,想要取得本接口的实例化对象,最好使用工厂类来设计。单是也需要知道传统设计模式所带来的问题:
interface Ifruit {//接口
public void eat();
}
class Apple implements Ifruit{//实现
@Override
public void eat() {
System.out.println("i like apple");
}
}
class Factory {//工厂模式,代替生产对象
private Factory() {};
public static Ifruit getInstance(String ClassName) {
if ("apple".equals(ClassName)) {
return new Apple();
}
return null;
}
}
public class Test{
public static void main(String[] args) {
Ifruit ifruit = Factory.getInstance("apple");
ifruit.eat();
}
}
//+++++++++++++++++++++++++++++++++++
i like apple
传统工厂类在实际开发中根本用不到。因为如果每增加一个接口就需要修改工厂类
如果想要解决关键字new带来的问题,最好的做法就是通过反射来完成处理,因为Class类可以使用newInstant()实例化对象,同时Class.forName()能够接收类名称。
修改:
interface Ifruit {//
public void eat();
}
class Apple implements Ifruit{
@Override
public void eat() {
System.out.println("i like apple");
}
}
class Banana implements Ifruit{
@Override
public void eat() {
System.out.println("i like banana");
}
}
class Factory {
private Factory() {};
public static Ifruit getInstance(String ClassName) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Ifruit ifruit = (Ifruit)Class.forName(ClassName).newInstance();//用newInstance产生实例化对象
return ifruit;
}
}
public class Test{
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Ifruit ifruit = Factory.getInstance("reflect.Apple");//传入完整的类名
ifruit.eat();
}
}
//+++++++++++++++++++++++++++++++++++
i like apple
引入反射后,每当新增接口子类,无需修改工厂类带就可以很方便的进行接口子类扩展,相当于动态的在new传入的对象,以上就是简单工厂模式。