反射(Reflect)是学习各种框架的基础!!!
目录
注解:.class,Class.forName()和.getClass()的区别:
1.反射简介
(1)以前写代码的时候,要实例化一个对象,需要使用new关键字实例化指定的类,这是把类实例化的工作写死在代码中的;这种固定写死的代码不够灵活,在实际工作中总会不太方便;即原先创建对象的时机是程序编译的时候。
反射的根本目的:把创建对象的时机从【程序编译的时候】 延迟到 【程序运行时】;
(2)反射JDK1.2才有;其隶属于java.lang.reflect包,所有与反射相关的类都存放在这个包中;
(3)后续的java高级框架,这些框架在应用程序启动的时候,会动态的读取配置文件的信息,同时利用反射技术在运行的时候去创建不同的对象;
反射让java程序变得更加灵活,更加容易被管理。
2.反射案例(目的仅用于感受什么是反射)
(1)案例准备:一个接口,三个实现类
MathOperation接口(四则运算接口);三个实现类:Addition类(加法类);Multiplication类(乘法类);Subtraction(减法类);一个演示的入口类:ReflectSample类;
如下:
MathOperation接口(四则运算接口):
package com.imooc.reflect;
/**
* 四则运算接口
*/
public interface MathOperation {
public float operate(int a , int b);
}
三个实现类之: Addition类(加法类):
package com.imooc.reflect;
/**
* 加法
*/
public class Addition implements MathOperation {
@Override
public float operate(int a , int b) {
System.out.println("执行加法运算");
return a + b;
}
}
三个实现类之: Multiplication类(乘法类):
package com.imooc.reflect;
public class Multiplication implements MathOperation {
@Override
public float operate(int a, int b) {
return a * b;
}
}
三个实现类之: Subtraction(减法类):
package com.imooc.reflect;
/**
* 减法运算
*/
public class Subtraction implements MathOperation {
@Override
public float operate(int a, int b) {
System.out.println("执行减法运算");
return a - b;
}
}
(2)案例准备:演示的入口类:ReflectSample类
package com.imooc.reflect;
import java.util.Scanner;
/**
* 初识反射的作用
*/
public class ReflectSample {
/**
* 传统的创建对象方式
*/
public static void case1(){
Scanner scanner = new Scanner(System.in);
System.out.print("请输入计算类名:");
String op = scanner.next();
System.out.print("请输入a:");
int a = scanner.nextInt();
System.out.print("请输入b:");
int b = scanner.nextInt();
MathOperation mathOperation = null;
if(op.equals("Addition")){
mathOperation = new Addition();
}else if(op.equals("Subtraction")) {
mathOperation = new Subtraction();
}else{
System.out.println("无效的计算类");
return;
}
float result = mathOperation.operate(a, b);
System.out.println(result);
}
/**
* 利用反射创建对象更加灵活
*/
public static void case2(){
Scanner scanner = new Scanner(System.in);
System.out.print("请输入计算类名:");
String op = scanner.next();
System.out.print("请输入a:");
int a = scanner.nextInt();
System.out.print("请输入b:");
int b = scanner.nextInt();
MathOperation mathOperation = null;
try {
mathOperation = (MathOperation) Class.forName("com.imooc.reflect." + op).newInstance();
}catch(Exception e){
System.out.println("无效的计算类");
return;
}
float result = mathOperation.operate(a, b);
System.out.println(result);
}
public static void main(String[] args) {
ReflectSample.case1();
//ReflectSample.case2();
}
}
上面case1()方法是传统的解决办法;其中只做了加法和减法的处理,即只实例化了Addition类(加法类)和Subtraction(减法类);可以设想一下,如果想要增加乘法的话,首先需要有Multiplication类(乘法的实现类),还需要在case1()方法中增加一个else if做个判断,然后再实例化Multiplication类(乘法类);如下:
缺点:为了实现功能的修改,需要修改源代码……
但在真正的企业应用中,修改源代码要慎重。而且,每次修改源代码后,都需要重新测试,重新打包,重新上线,这个过程是非常麻烦的。
在不修改源代码的情况下,动态让程序支持新的功能。就如case2()方法的内容了:
上面case2()方法利用了反射技术,在运行时动态的创建对应的对象;想增加乘法的时候,case2()的代码不需要做任何调整,只需要在“请输入计算类名”的时候输入【Multiplication】就能自动的完成乘法的逻辑。
核心:mathOperation = (MathOperation) Class.forName("com.imooc.reflect." + op).newInstance();
Class.forName():反射中最常用的方法,作用是加载指定的类;
newInstance():对Class.forName()方法获取到的类进行实例化;
……………………………………………………
Summary:
即case1()这种传统的方式,把实例化类的工作放在了【程序编译的时候】,即在【ReflectSample类】的class字节码文件产生的时候,在【ReflectSample类】中创建那些类的实例对象就已经确定了;
但是case2()这种利用反射的方式,把实例化类的工作放在了【程序运行时】,当java的编译器看到【 (MathOperation) Class.forName("com.imooc.reflect." + op).newInstance();】的时候,其并不知道要创建哪个对象,因为op的数据是在运行以后才会产生的;
利用反射,可以在程序运行时动态的决定创建哪些对象,并且访问这些对象的哪些方法和属性;
正是因为Java提供了反射这种灵活的特性,才诞生了Spring,Mybatis这些高级框架;这些高级框架都是以反射为基础的。
……………………………………………………
注解:.class,Class.forName()和.getClass()的区别:
Class.class用来返回 Class 对象。
Class.forName()是反射机制的一种,用于获取指定的Class对象。
getClass()方法是获取该对象的class(类),可以通过返回的Class对象获取类的相关信息
区别如下:
1) .getClass()是动态的,其余是静态的;
2) .class和class.forName()只能返回类内field的默认值,getClass可以返回当前对象中field的最新值;
3) Class.forName() 返回的是一个类,.newInstance() 后才创建一个对象,Class.forName()的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的;