反射的基本使用
1. 什么是反射
反射:就是对象的反向处理。
那么正的的操作是什么?当我们实例化一个对象,首先要创建一个类,new一个它的构造方法,就能实例化一个对象。它的处理流程就是:包名.类名;通过包名,在找到类名。
反射中的“反”:就是根据对象来取得对象的来源信息。而这个反的的操作核心取决于Object的一个方法。取得Class对象。
public final native Class<?> getClass();
该方法返回的是一个Class类对象,这个Class描述的就是类。
在反射的世界里,看中的不在是一个对象,而是对象身后的组成类(类,构造,普通,成员)。
2. Class类对象的三种获取方式
对类型(类)的一个抽象,就是JDK中的Class类,用来描述我们所定义的类。
Class的获取方式:
- 通过对象的
getClass
方法获取,比如:obj.getClass();- 通过
类名.class
获取类的对象;- 通过Class类的静态方法
forName(String className)
获取Class对象,要捕获异常。
在以上三个方法中,我们可以看出,除了第一种方法会产生类的实例化对象外,其他的两种都不会产生类的实例化对象。所以在取得了Class类对象的一个最直接的好处:可以通过反射实例化对象。
举例:三种获取Class对象信息的方式
public class TestReflect {
public static void main(String[] args) {
//1.第一种方式
//通过类名,调用构造方法,创建对象
Date date = new Date();
//通过date对象来获取创建date的类型,赋给Class对象
Class classz = date.getClass();
System.out.println(classz); //class java.util.Date
System.out.println(classz.getName()); //java.util.Date
//第二种方式
//不需要实例化对象, 类名.class
Class classz1 = Date.class;
System.out.println(classz1 == classz); //true
//第三种方式
//使用Class的静态方法,其中forName中的类名称是所在的包名加类名
try {
Class classz2 = Class.forName("java.util.Date");
System.out.println(classz2 == classz1); //true
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
那么怎样通过反射实例化对象,Class中提供了一个方法。如下:
public T newInstance()
throws InstantiationException, IllegalAccessException
即当我们获取对象类的信息,在通过Class对象调用newInstance()
方法(相当于new了一个对象),就实例化了一个对象。
举例:通过反射实例化对象
public class TestReflect {
public static void main(String[] args) {
//第二种方式
Class classz = Date.class;
try {
//此处就等价于new java.util.Date
Object object = classz.newInstance();
System.out.println(object);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println();
//第三种方式
try {
Class classz1 = Class.forName("java.util.Date");
Object object = classz1.newInstance();
System.out.println(object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
现在我们发现实例化对象的第二种方式:通过反射实现。
取得Class对象就意味着取得了类的指定操作权。
3. 反射的应用
简单工厂模式的应用
对于传统工厂(简单工厂)来说,当增加一个新的产品类,将修改工厂方法中的代码,这违背了开闭原则。
举例如下:
interface Fruit{
void eat();
}
class Apple implements Fruit{
@Override
public void eat() {
System.out.println("吃苹果");
}
}
class FruitFactory{
public static Fruit getFruitInstance(String fruitName){
if(fruitName.equals("Apple")){
return new Apple();
}
return null;
}
}
public class TestFactory {
public static void main(String[] args) {
Fruit fruit = FruitFactory.getFruitInstance("Apple");
fruit.eat();
}
}
如果此时想要加一个产品类橘子,那么就要修改工厂类中的代码。那么可以通过反射来解决,因为反射可以通过Class对象来newInstance()实例化一个对象。
举例:使用反射之后的简单工厂方法
interface Fruit{
void eat();
}
class Apple implements Fruit{
@Override
public void eat() {
System.out.println("吃苹果");
}
}
class FruitFactory{
public static Fruit getFruitInstance(String className){
try {
Class classz = Class.forName(className);
return (Fruit) classz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
}
public class TestFactory {
public static void main(String[] args) {
Fruit fruit = FruitFactory.getFruitInstance("www.csdn.classse.Apple");
fruit.eat();
}
}
简单工厂结合反射来使用,能够减少功能扩展带来的修改问题,在增加新的接口子类时,可以很方便的进行接口子类扩展。