Java中反射機(jī)制和作用詳解
前言
很多剛學(xué)Java反射的同學(xué)可能對(duì)反射技術(shù)一頭霧水,為什么要學(xué)習(xí)反射,學(xué)習(xí)反射有什么作用,不用反射,通過(guò)new也能創(chuàng)建用戶對(duì)象。
那么接下來(lái)大師就帶你們了解一下反射是什么,為什么要學(xué)習(xí)反射?
下面我們首先通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明反射的好處:
方法1、不用反射技術(shù),創(chuàng)建用戶對(duì)象,調(diào)用sayHello方法
1.1 我們首先創(chuàng)建一個(gè)User類(lèi)
package com.dashi;
/**
* Author:Java大師
* User對(duì)象,包含用戶的id和姓名以及sayHello方法
*/
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String sayHello(String who) {
return who+ "{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
1.2 創(chuàng)建測(cè)試用例
package com.dashi;
import org.junit.Test;
/**
* 創(chuàng)建Juinit測(cè)試對(duì)象
*/
public class Test01 {
@Test
public void test01(){
User user = new User();
user.setId(1);
user.setName("Java大師");
//調(diào)用sayHello方法
System.out.println(user.sayHello("user1"));
}
}
1.3運(yùn)行結(jié)果如下,打印出sayHello結(jié)果:
user1{id=1, name='Java大師'}
Process finished with exit code 0
方法2、通過(guò)反射技術(shù),創(chuàng)建用戶對(duì)象,調(diào)用sayHello方法
2.1 調(diào)用測(cè)試用例
@Test
public void test02(){
try {
//創(chuàng)建用戶對(duì)象字符串
String obj = "com.dashi.User";
//通過(guò)用戶對(duì)象字符串加載類(lèi)
Class clz = Class.forName(obj);
//通過(guò)newInstance方法,創(chuàng)建用戶對(duì)象
User user = (User)clz.newInstance();
user.setId(2);
user.setName("Java大師2");
//調(diào)用sayHello方法
System.out.println(user.sayHello("user2"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
2.2 運(yùn)行結(jié)果如下,打印出sayHello結(jié)果:
user1{id=1, name='Java大師'}
user2{id=2, name='Java大師2'}Process finished with exit code 0
通過(guò)兩者以上對(duì)比,發(fā)現(xiàn)方法1和方法2都能創(chuàng)建用戶對(duì)象,并調(diào)用sayHello方法,并且打印的結(jié)果都正確。但是方法2比方法1先進(jìn)的地方是方法2針對(duì)字符串編程,方法1針對(duì)實(shí)體類(lèi)編程。
那么針對(duì)字符串編程有什么好處呢,小伙伴們耐心接著往下看:
我們通過(guò)一個(gè)Dao層來(lái)演示下針對(duì)字符串編程的好處:
假設(shè)我們有一個(gè)IUserDao接口,里面有一個(gè)load方法,代碼如下:
package com.dashi;
public interface IUserDao {
public void load();
}
有兩個(gè)實(shí)現(xiàn)類(lèi)來(lái)實(shí)現(xiàn)該IUserDao接口,實(shí)現(xiàn)類(lèi)如下:
package com.dashi;
/**
* A實(shí)現(xiàn)類(lèi)
*/
public class AUserDao implements IUserDao{
@Override
public void load() {
System.out.println("這是AUserDao");
}
}
package com.dashi;
/**
* B實(shí)現(xiàn)類(lèi)
*/
public class BUserDao implements IUserDao{
@Override
public void load() {
System.out.println("這是BUserDao");
}
}
方法3、不通過(guò)反射技術(shù),創(chuàng)建IUserDao,調(diào)用load方法
@Test
public void testDao01(){
IUserDao userDao = new AUserDao();
userDao.load();
}
打印結(jié)果如下:
這是AUserDao
Process finished with exit code 0
方法4、通過(guò)反射技術(shù),創(chuàng)建IUserDao,調(diào)用load方法
@Test
public void testDao02(){
try {
//創(chuàng)建接口實(shí)現(xiàn)類(lèi)字符串
String dao_str = "com.dashi.AUserDao";
//通過(guò)類(lèi)加載的方式創(chuàng)建IUserDao
IUserDao userDao = (IUserDao) Class.forName(dao_str).newInstance();
//調(diào)用load方法
userDao.load();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
打印結(jié)果如下:
這是AUserDao
這是AUserDaoProcess finished with exit code 0
通過(guò)類(lèi)加載的方式,我們也創(chuàng)建了IUserDao對(duì)象,調(diào)用了load方法,和方法3的運(yùn)行結(jié)果一樣
方法5、通過(guò)反射技術(shù),創(chuàng)建IUserDao,調(diào)用load方法
@Test
public void testDao03(){
try {
//創(chuàng)建接口實(shí)現(xiàn)類(lèi)字符串
String dao_str = "com.dashi.BUserDao";
//通過(guò)類(lèi)加載的方式創(chuàng)建IUserDao
Class clz = Class.forName(dao_str);
IUserDao userDao= (IUserDao)clz.newInstance();
//創(chuàng)建調(diào)用方法字符串
String mm = "load";
//創(chuàng)建method對(duì)象
Method method = clz.getMethod(mm);
//調(diào)用通過(guò)反射調(diào)用invoke方法
method.invoke(userDao);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
運(yùn)行結(jié)果如下:
這是AUserDao
這是AUserDao
這是BUserDaoProcess finished with exit code 0
通過(guò)method.invoke方法也可以實(shí)現(xiàn)load方法的調(diào)用
方法5比方法4和方法3更加靈活,不需要知道AUserDao和BUserDao實(shí)體類(lèi),只提供類(lèi)的字符串和類(lèi)的方法名稱(chēng),通過(guò)反射就可以實(shí)現(xiàn)方法的調(diào)用
實(shí)戰(zhàn)中的實(shí)際意義
假設(shè)我們的Dao層,從mysql遷移導(dǎo)oracle,SQL server等
運(yùn)用反射技術(shù),通過(guò)字符串編程,那么我們不需要進(jìn)行Dao層實(shí)體類(lèi)的更改,只需要改動(dòng)我們的字符串名字就可以進(jìn)行Dao層的更新。比如:
1、不通過(guò)反射技術(shù),我們需要修改實(shí)現(xiàn)類(lèi)中的AUserDao改為BUserDao
IUserDao userDao = new AUserDao();
userDao.load();
``如果有幾百個(gè)Dao,我們需要修改幾百次``
``
2、運(yùn)用發(fā)射技術(shù)通過(guò)字符串編程,我們可以把字符串定義在properties文件中,通過(guò)修改properties文件中的配置即可實(shí)現(xiàn)Dao的更新
//創(chuàng)建接口實(shí)現(xiàn)類(lèi)字符串
String dao_str = "com.dashi.AUserDao"; //可以改寫(xiě)為:String dao_str = PropertyUtil.get("dao");
//通過(guò)類(lèi)加載的方式創(chuàng)建IUserDao
IUserDao userDao = (IUserDao) Class.forName(dao_str).newInstance();
//調(diào)用load方法
userDao.load();
這就是反射技術(shù)的實(shí)際運(yùn)用,通過(guò)以上實(shí)例就可以看出字符串編程和通過(guò)實(shí)現(xiàn)類(lèi)編程的最大的區(qū)別和實(shí)際的意義
并且通過(guò)反射技術(shù)可以使我們的編程更加靈活
靈活運(yùn)用反射技術(shù),我們可以設(shè)計(jì)出更加靈活的框架哦~
總結(jié)
到此這篇關(guān)于Java中反射機(jī)制和作用詳解的文章就介紹到這了,更多相關(guān)Java反射機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot使用@Cacheable出現(xiàn)預(yù)覽工具亂碼的解決方法
直接使用注解進(jìn)行緩存數(shù)據(jù),我們?cè)偈褂霉ぞ呷ヮA(yù)覽存儲(chǔ)的數(shù)據(jù)時(shí)發(fā)現(xiàn)是亂碼,這是由于默認(rèn)序列化的問(wèn)題,所以接下來(lái)將給大家介紹一下SpringBoot使用@Cacheable出現(xiàn)預(yù)覽工具亂碼的解決方法,需要的朋友可以參考下2023-10-10
解決SpringBoot運(yùn)行Test時(shí)報(bào)錯(cuò):SpringBoot Unable to find
這篇文章主要介紹了SpringBoot運(yùn)行Test時(shí)報(bào)錯(cuò):SpringBoot Unable to find a @SpringBootConfiguration,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Java 梳理總結(jié)關(guān)于static關(guān)鍵字常見(jiàn)問(wèn)題
static關(guān)鍵字基本概念我們可以一句話來(lái)概括:方便在沒(méi)有創(chuàng)建對(duì)象的情況下來(lái)進(jìn)行調(diào)用。也就是說(shuō):被static關(guān)鍵字修飾的不需要?jiǎng)?chuàng)建對(duì)象去調(diào)用,直接根據(jù)類(lèi)名就可以去訪問(wèn),讓我們來(lái)了解一下你可能還不知道情況2022-04-04
懶人 IDEA 插件推薦: EasyCode 一鍵幫你生成所需代碼(Easycode用法)
這篇文章主要介紹了懶人 IDEA 插件推薦: EasyCode 一鍵幫你生成所需代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
SpringBoot與Quartz集成實(shí)現(xiàn)分布式定時(shí)任務(wù)集群的代碼實(shí)例
今天小編就為大家分享一篇關(guān)于SpringBoot與Quartz集成實(shí)現(xiàn)分布式定時(shí)任務(wù)集群的代碼實(shí)例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
springboot多數(shù)據(jù)源配合docker部署mysql主從實(shí)現(xiàn)讀寫(xiě)分離效果
這篇文章主要介紹了springboot多數(shù)據(jù)源配合docker部署mysql主從實(shí)現(xiàn)讀寫(xiě)分離,通過(guò)使用docker獲取mysql鏡像,具體內(nèi)容詳情跟隨小編一起看看吧2021-09-09
Java?入門(mén)圖形用戶界面設(shè)計(jì)之事件處理下
圖形界面(簡(jiǎn)稱(chēng)GUI)是指采用圖形方式顯示的計(jì)算機(jī)操作用戶界面。與早期計(jì)算機(jī)使用的命令行界面相比,圖形界面對(duì)于用戶來(lái)說(shuō)在視覺(jué)上更易于接受,本篇精講Java語(yǔ)言中關(guān)于圖形用戶界面的事件處理2022-02-02

