反射(Reflect)是学习各种框架的基础!!!
目录
1.反射简介
2.反射案例(目的仅用于感受什么是反射)
(1)案例准备:一个接口,三个实现类
(2)案例准备:演示的入口类:ReflectSample类
(1)以前写代码的时候,要实例化一个对象,需要使用new关键字实例化指定的类,这是把类实例化的工作写死在代码中的;这种固定写死的代码不够灵活,在实际工作中总会不太方便;即原先创建对象的时机是程序编译的时候。
反射的根本目的:把创建对象的时机从【程序编译的时候】 延迟到 【程序运行时】;
(2)反射JDK1.2才有;其隶属于java.lang.reflect包,所有与反射相关的类都存放在这个包中;
(3)后续的java高级框架,这些框架在应用程序启动的时候,会动态的读取配置文件的信息,同时利用反射技术在运行的时候去创建不同的对象;
反射让java程序变得更加灵活,更加容易被管理。
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; } }
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会执行该类的;