1.初识反射
1.1.认知反射
反射指的是对象的反向处理操作,根据对象倒推类的组成
,默认情况下,必须要先导入一个包,而后才能产生类的实例化对象,如下:
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date() ;
}
}
以上是我们正常的关于对象的处理流程:根据包名.类名
找到类,而反射的"反"指的是根据对象来取得对象的来源信息,而这个"反"的操作核心的处理就在于Object类的一个方法:取得Class对象:
public final native Class<?> getClass();
该方法返回的是一个Class类对象,这个Class描述的就是类,调用getClass()方法示例如下:
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date() ;
System.out.println(date.getClass());
}
}
此时通过对象取得了对象的来源,这就是"反"的本质,在反射的世界里面,看重的不再是一个对象,而是对象身后的组成
(类、构造、普通、成员等),Class类描述接口与类的组成,Class对象由JVM在第一次加载类时产生,并且全局唯一
1.2.取得任意类Class对象的方法
Class类是描述整个类
的概念,也是整个反射的操作源头,在使用Class类的时候需要关注的是这个类对象,而这个类对象的产生模式一共有三种:
- 调用对象的
getClass()
取得Class对象,该方法在Object类中 类名称.class
取得class对象Class.forName(类全名称)
取得Class对象
Class.forName方法示例:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("java.util.Date") ;
System.out.println(cls.getName());
}
}
1.3.反射取得实例化对象
public T newInstance():通过反射实例化类对象
public class Test {
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
Class<?> cls = Class.forName("java.util.Date") ;
Object obj = cls.newInstance() ; // 实例化对象,等价于 new java.util.Date() ;
}
}
取得了Class对象就意味着取得了一个指定类的操作权
,除了关键字new之外,对于对象的实例化模式有了第二种做法:反射
1.4.反射vs工厂模式
工厂设计模式原则:如果是自己编写的接口,要想取得本接口的实例化对象,最好使用工厂类来设计
传统工厂类:
interface IFruit {
public void eat() ;
}
class Apple implements IFruit {
@Override
public void eat() {
System.out.println("[Apple] 吃苹果 ");
}
}
class FruitFactory {
private FruitFactory() {}
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 fruit = FruitFactory.getInstance("apple") ;
fruit.eat() ;
}
}
以上传统工厂有一个很大的问题:每增加一个接口的子类就需要修改工厂类去new对应的对象,如下:
interface IFruit {
public void eat() ;
}
class Apple implements IFruit {
@Override
public void eat() {
System.out.println("[Apple] 吃苹果 ");
}
}
class Orange implements IFruit {
@Override
public void eat() {
System.out.println("[Orange] 吃橘子 ");
}
}
class FruitFactory {
private FruitFactory() {}
public static IFruit getInstance(String className) {
if ("apple".equals(className)) {
return new Apple() ;
}else if ("orange".equals(className)) {
return new Orange() ;
}
return null ;
}
}
想解决关键字new带来的问题,最好的做法就是通过反射来完成处理,因为Class类可以使用newInstance()实例化对象,同时Class.forName()能够接收类名称:
interface IFruit {
public void eat() ;
}
class Apple implements IFruit {
@Override
public void eat() {
System.out.println("[Apple] 吃苹果 ");
}
}
class Orange implements IFruit {
@Override
public void eat() {
System.out.println("[Orange] 吃橘子 ");
}
}
class FruitFactory {
private FruitFactory() {}
public static IFruit getInstance(String className) {
IFruit fruit = null ;
try {
fruit = (IFruit) Class.forName(className).newInstance() ;
} catch (InstantiationException | IllegalAccessException |
ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return fruit ;
}
}
public class Test {
public static void main(String[] args) {
IFruit fruit = FruitFactory.getInstance("xpu.edu.Orange") ;
fruit.eat() ;
}
}
//[Orange] 吃橘子
引入反射后,每当新增接口子类,无需去修改工厂类代码就可以很方便的进行接口子类扩容。以上这种工厂类代码我们称之为简单工厂模式,反射是简单工厂的一种实现方式
2.反射与类操作
利用反射可以做出一个对象具备的所有操作行为,最为关键的是这一切的操作都可以基于Object进行
2.1.取得父类(父接口)信息
在java中任何的程序类都一定会有父类,在Class类中就可以通过如下方法来取得父类或者实现的父接口:
- 取得类的包名称::public Package getPackage()
- 取得父类的Class对象:public native Class<? super T> getSuperclass()
- 取得实现的父接口:public Class<?>[] getInterfaces()
示例如下:
interface IFruit {}
interface IMessage{}
class CLS implements IFruit,IMessage{}
public class Test {
public static void main(String[] args) {
// 取得类对象
Class<?> cls = CLS.class ;
// 取得Package名称
System.out.println(cls.getPackage().getName());
// 取得父类名称
System.out.println(cls.getSuperclass().getName());
// 取得实现的父接口对象
Class<?>[] iClass = cls.getInterfaces() ;
for (Class<?> class1 : iClass) {
System.out.println(class1.getName());
}
}
}
//xpu.edu
//java.lang.Object
//xpu.edu.IFruit
//xpu.edu.IMessage
通过反射可以取得类结构上的所有关键信息