最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java基礎(chǔ)篇之反射機(jī)制詳解

 更新時(shí)間:2022年01月04日 10:04:30   作者:小濤今天沒敲代碼  
本文詳細(xì)講解了Java基礎(chǔ)篇之反射機(jī)制,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

思考:在講反射之前,先思考一個(gè)問題,java中如何創(chuàng)建一個(gè)對(duì)象,有哪幾種方式?

Java中創(chuàng)建對(duì)象大概有這幾種方式:

  • 1、使用new關(guān)鍵字:這是我們最常見的也是最簡(jiǎn)單的創(chuàng)建對(duì)象的方式
  • 2、使用Clone的方法:無論何時(shí)我們調(diào)用一個(gè)對(duì)象的clone方法,JVM就會(huì)創(chuàng)建一個(gè)新的對(duì)象,將前面的對(duì)象的內(nèi)容全部拷貝進(jìn)去
  • 3、使用反序列化:當(dāng)我們序列化和反序列化一個(gè)對(duì)象,JVM會(huì)給我們創(chuàng)建一個(gè)單獨(dú)的對(duì)象

上邊是Java中常見的創(chuàng)建對(duì)象的三種方式,其實(shí)除了上邊的三種還有另外一種方式,就是接下來我們要討論的 “反射”

1、反射概述

1.1什么是反射

反射就是把Java類中的各個(gè)部分,映射成一個(gè)個(gè)的Java對(duì)象,拿到這些對(duì)象后可以做一些事情。

既然說反射是反射Java類中的各個(gè)組成部分,所以說咱們得知道一個(gè)類中有哪兒些部分?

例如,一個(gè)類有:成員變量,方法,構(gòu)造方法,等信息,利用反射技術(shù)咱們可以把這些組成部分映射成一個(gè)個(gè)對(duì)象。

1.2、反射能干什么

說完反射的概念后,咱們說一下反射能干什么?

一般來說反射是用來做框架的,或者說可以做一些抽象度比較高的底層代碼,反射在日常的開發(fā)中用到的不多,但是咱們還必須搞懂它,因?yàn)楦愣朔瓷湟院?,可以幫助咱們理解框架的一些原理。所以說有一句很經(jīng)典的話:反射是框架設(shè)計(jì)的靈魂。現(xiàn)在說完這個(gè)可能還不太能理解,不急,等下說完一個(gè)快速入門的例子后,應(yīng)該會(huì)稍微有點(diǎn)感覺

1.3、怎么得到想反射的類

剛才已經(jīng)說過,反射是對(duì)一個(gè)類進(jìn)行解剖,想解剖一個(gè)東西,前提是首先你得拿到這個(gè)東西,那么怎么得到咱們想解剖的類呢?

首先大家要明白一點(diǎn),咱們寫的代碼是存儲(chǔ)在后綴名是 .java的文件里的,但是它會(huì)被編譯,最終真正去執(zhí)行的是編譯后的 .class文件。Java是面向?qū)ο蟮恼Z言,一切皆對(duì)象,所以java認(rèn)為 這些編譯后的 class文件,這種事物也是一種對(duì)象,它也給抽象成了一種類,這個(gè)類就是Class,大家可以去AIP里看一下這個(gè)類

所以拿到這個(gè)類后,就相當(dāng)于拿到了咱們想解剖的類,那怎么拿到這個(gè)類?

看API文檔后,有一個(gè)方法forName(String className); 而且是一個(gè)靜態(tài)的方法,這樣咱們就可以得到想反射的類了

到這里,看Class clazz = Class.forName("com.cj.test.Person");這個(gè)應(yīng)該有點(diǎn)感覺了吧

Class.forName("com.cj.test.Person");因?yàn)檫@個(gè)方法里接收的是個(gè)字符串,字符串的話,我們就可以寫在配置文件里,然后利用反射生成我們需要的對(duì)象,這才是我們想要的。很多框架里都有類似的配置

2、解剖類

我們知道一個(gè)類里一般有構(gòu)造函數(shù)、方法、成員變量(字段/屬性)這三部分組成

翻閱API文檔,可以看到

Class對(duì)象提供了如下常用方法:

  • public Constructor getConstructor(Class<?>…parameterTypes)
  • public Method getMethod(String name,Class<?>… parameterTypes)
  • public Field getField(String name)
  • public Constructor getDeclaredConstructor(Class<?>…parameterTypes)
  • public Method getDeclaredMethod(String name,Class<?>… parameterTypes)
  • public Field getDeclaredField(String name)

這些方法分別用于幫咱們從類中解剖出構(gòu)造函數(shù)、方法和成員變量(屬性)。

然后把解剖出來的部分,分別用Constructor、Method、Field對(duì)象表示。

2.1反射構(gòu)造方法

2.1.1反射無參的構(gòu)造函數(shù)

可以看到 默認(rèn)的無參構(gòu)造方法執(zhí)行了

從上邊的例子看出,要想反射,首先第一步就是得到類的字節(jié)碼

所以簡(jiǎn)單說一下得到類的字節(jié)碼的幾種方式

  • (1)、Class.forName("com.cj.test.Person"); 這就是上邊我們用的方式
  • (2)、對(duì)象.getClass();
  • (3)、類名.class;

2.1.2反射“一個(gè)參數(shù)”的構(gòu)造函數(shù)

2.1.3反射“多個(gè)參數(shù)”的構(gòu)造函數(shù)

2.1.4反射“私有”的構(gòu)造函數(shù)

注意:在反射私有的構(gòu)造函數(shù)時(shí),用普通的clazz.getConstructor()會(huì)報(bào)錯(cuò),因?yàn)樗撬接械?,所以提供了專門反射私有構(gòu)造函數(shù)的方法 clazz.getDeclaredConstructor(int.class);//讀取私有的構(gòu)造函數(shù),用這個(gè)方法讀取完還需要設(shè)置一下暴力反射才可以

c.setAccessible(true);//暴力反射

2.1.5反射得到類中所有的構(gòu)造函數(shù)

2.2反射類中的方法

package com.cj.test;
 
import java.util.Date;
 
public class Person {
	
	public Person(){
		System.out.println("默認(rèn)的無參構(gòu)造方法執(zhí)行了");
	}
 
	public Person(String name){
		System.out.println("姓名:"+name);
	}
	
	public Person(String name,int age){
		System.out.println(name+"="+age);
	}
	
	private Person(int age){
		System.out.println("年齡:"+age);
	}
	
	public void m1() {
		System.out.println("m1");
	}
	
	public void m2(String name) {
		System.out.println(name);
	}
	
	public String m3(String name,int age) {
		System.out.println(name+":"+age);
		return "aaa";
	}
	
	private void m4(Date d) {
		System.out.println(d);
	}
	
	public static void m5() {
		System.out.println("m5");
	}
	
	public static void m6(String[] strs) {
		System.out.println(strs.length);
	}
 
        public static void main(String[] args) {
		System.out.println("main");
	}
 
}
package com.cj.test;
 
import java.lang.reflect.Method;
import java.util.Date;
import org.junit.Test;
 
public class Demo2 {
 
	@Test//public void m1()
	public void test1() throws Exception{
		Class clazz = Class.forName("com.cj.test.Person");
		Person p = (Person)clazz.newInstance();
		Method m = clazz.getMethod("m1", null);
		m.invoke(p, null);
	}
	@Test//public void m2(String name)
	public void test2() throws Exception{
		Class clazz = Person.class;
		Person p = (Person) clazz.newInstance();
		Method m = clazz.getMethod("m2", String.class);
		m.invoke(p, "張三");
	}
	@Test//public String m3(String name,int age)
	public void test3() throws Exception{
		Class clazz = Person.class;
		Person p = (Person) clazz.newInstance();
		Method m = clazz.getMethod("m3", String.class,int.class);
		String returnValue = (String)m.invoke(p, "張三",23);
		System.out.println(returnValue);
	}
	@Test//private void m4(Date d)
	public void test4() throws Exception{
		Class clazz = Person.class;
		Person p = (Person) clazz.newInstance();
		Method m = clazz.getDeclaredMethod("m4", Date.class);
		m.setAccessible(true);
		m.invoke(p,new Date());
	}
	@Test//public static void m5()
	public void test5() throws Exception{
		Class clazz = Person.class;
		Method m = clazz.getMethod("m5", null);
		m.invoke(null,null);
	}
	@Test//private static void m6(String[] strs)
	public void test6() throws Exception{
		Class clazz = Person.class;
		Method m = clazz.getDeclaredMethod("m6",String[].class);
		m.setAccessible(true);
		m.invoke(null,(Object)new String[]{"a","b"});
	}
	@Test
	public void test7() throws Exception{
		Class clazz = Person.class;
		Method m = clazz.getMethod("main",String[].class);
		m.invoke(null,new Object[]{new String[]{"a","b"}});
	}
}

*****注意:看下上邊代碼里test6和test7的invoke方法里傳的參數(shù)和其他的有點(diǎn)不一樣

這是因?yàn)?jdk1.4和jdk1.5處理invoke方法有區(qū)別

1.5:public Object invoke(Object obj,Object…args)

1.4:public Object invoke(Object obj,Object[] args)

由于JDK1.4和1.5對(duì)invoke方法的處理有區(qū)別, 所以在反射類似于main(String[] args) 這種參數(shù)是數(shù)組的方法時(shí)需要特殊處理

啟動(dòng)Java程序的main方法的參數(shù)是一個(gè)字符串?dāng)?shù)組,即public static void main(String[] args),通過反射方式來調(diào)用這個(gè)main方法時(shí),如何為invoke方法傳遞參數(shù)呢?按jdk1.5的語法,整個(gè)數(shù)組是一個(gè)參數(shù),而按jdk1.4的語法,數(shù)組中的每個(gè)元素對(duì)應(yīng)一個(gè)參數(shù),當(dāng)把一個(gè)字符串?dāng)?shù)組作為參數(shù)傳遞給invoke方法時(shí),javac會(huì)到底按照哪種語法進(jìn)行處理呢?jdk1.5肯定要兼容jdk1.4的語法,會(huì)按jdk1.4的語法進(jìn)行處理,即把數(shù)組打散成為若干個(gè)單獨(dú)的參數(shù)。所以,在給main方法傳遞參數(shù)時(shí),不能使用代碼mainMethod.invoke(null,new String[]{“xxx”}),javac只把它當(dāng)作jdk1.4的語法進(jìn)行理解,而不把它當(dāng)作jdk1.5的語法解釋,因此會(huì)出現(xiàn)參數(shù)個(gè)數(shù)不對(duì)的問題。

上述問題的解決方法:

  • (1)mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});

這種方式,由于你傳的是一個(gè)數(shù)組的參數(shù),所以為了向下兼容1.4的語法,javac遇到數(shù)組會(huì)給你拆開成多個(gè)參數(shù),但是由于咱們這個(gè)Object[ ] 數(shù)組里只有一個(gè)元素值,所以就算它拆也沒關(guān)系

  • (2)mainMethod.invoke(null,(Object)new String[]{"xxx"});

這種方式相當(dāng)于你傳的參數(shù)是一個(gè)對(duì)象,而不是數(shù)組,所以就算是按照1.4的語法它也不會(huì)拆,所以問題搞定

編譯器會(huì)作特殊處理,編譯時(shí)不把參數(shù)當(dāng)作數(shù)組看待,也就不會(huì)數(shù)組打散成若干個(gè)參數(shù)了

對(duì)上邊的描述進(jìn)行一下總結(jié):在反射方法時(shí),如果方法的參數(shù)是一個(gè)數(shù)組,考慮到向下兼容問題,會(huì)按照J(rèn)DK1.4的語法來對(duì)待(JVM會(huì)把傳遞的數(shù)組參數(shù)拆開,拆開就會(huì)報(bào)參數(shù)的個(gè)數(shù)不匹配的錯(cuò)誤)

解決辦法:防止JVM拆開你的數(shù)組

  • 方式一:把數(shù)組看做是一個(gè)Object對(duì)象
  • 方式二:重新構(gòu)建一個(gè)Object數(shù)組,那個(gè)參數(shù)數(shù)組作為唯一的元素存在。

2.3反射類中的屬性字段

package com.cj.test;
 
import java.util.Date;
 
public class Person {
	
	public String name="李四";
	private int age = 18;
	public static Date time;
	
	public int getAge() {
		return age;
	}
	
	public Person(){
		System.out.println("默認(rèn)的無參構(gòu)造方法執(zhí)行了");
	}
 
	public Person(String name){
		System.out.println("姓名:"+name);
	}
	
	public Person(String name,int age){
		System.out.println(name+"="+age);
	}
	
	private Person(int age){
		System.out.println("年齡:"+age);
	}
	
	public void m1() {
		System.out.println("m1");
	}
	
	public void m2(String name) {
		System.out.println(name);
	}
	
	public String m3(String name,int age) {
		System.out.println(name+":"+age);
		return "aaa";
	}
	
	private void m4(Date d) {
		System.out.println(d);
	}
	
	public static void m5() {
		System.out.println("m5");
	}
	
	public static void m6(String[] strs) {
		System.out.println(strs.length);
	}
	
	public static void main(String[] args) {
		System.out.println("main");
	}
	
}
package com.cj.test;
 
import java.lang.reflect.Field;
import java.util.Date;
import org.junit.Test;
 
public class Demo3 {
	//public String name="李四";
	@Test
	public void test1() throws Exception{
		Class clazz = Person.class;
		Person p = (Person)clazz.newInstance();
		Field f = clazz.getField("name");
		String s = (String)f.get(p);
		System.out.println(s);
		
		//更改name的值
		f.set(p, "王六");
		System.out.println(p.name);
	}
	@Test//private int age = 18;
	public void test2() throws Exception{
		Class clazz = Person.class;
		Person p = (Person)clazz.newInstance();
		Field f = clazz.getDeclaredField("age");
		f.setAccessible(true);
		int age = (Integer)f.get(p);
		System.out.println(age);
		
		f.set(p, 28);
		age = (Integer)f.get(p);
		System.out.println(age);
	}
	@Test//public static Date time;
	public void test3() throws Exception{
		Class clazz = Person.class;
		Field f = clazz.getField("time");
		f.set(null, new Date());
		System.out.println(Person.time);
	}
}

以上就是自己對(duì)Java中反射的一些學(xué)習(xí)總結(jié),歡迎大家留言一起學(xué)習(xí)、討論

看完上邊有關(guān)反射的東西, 對(duì)常用框架里的配置文件是不是有點(diǎn)思路了

上邊是Spring配置文件里的常見的bean配置,這看起來是不是可以用反射很輕易的就可以實(shí)現(xiàn):解析xml然后把xml里的內(nèi)容作為參數(shù),利用反射創(chuàng)建對(duì)象。

以上所述是小編給大家介紹的Java基礎(chǔ)篇之反射機(jī)制詳解,希望對(duì)大家有所幫助。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • springboot+mybatis-plus實(shí)現(xiàn)內(nèi)置的CRUD使用詳解

    springboot+mybatis-plus實(shí)現(xiàn)內(nèi)置的CRUD使用詳解

    這篇文章主要介紹了springboot+mybatis-plus實(shí)現(xiàn)內(nèi)置的CRUD使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 詳解Java中二分法的基本思路和實(shí)現(xiàn)

    詳解Java中二分法的基本思路和實(shí)現(xiàn)

    二分法是一個(gè)非常高效的算法,它常常用于計(jì)算機(jī)的查找過程中。本文將通過示例為大家詳細(xì)講講二分法的基本思路和實(shí)現(xiàn),感興趣的可以了解一下
    2022-08-08
  • Java 實(shí)現(xiàn)協(xié)同過濾算法推薦算法的示例代碼

    Java 實(shí)現(xiàn)協(xié)同過濾算法推薦算法的示例代碼

    本文介紹了協(xié)同過濾算法的概念,包括基于用戶的協(xié)同過濾和基于物品的協(xié)同過濾,文章詳細(xì)解釋了數(shù)據(jù)準(zhǔn)備、相似度計(jì)算以及如何在Java中實(shí)現(xiàn)這些算法,通過一個(gè)簡(jiǎn)單的用戶-物品評(píng)分矩陣示例,展示了如何計(jì)算用戶和物品之間的相似度,并推薦未評(píng)分的物品,感興趣的朋友一起看看吧
    2025-02-02
  • springboot打包無法讀取yml、properties等配置文件的解決

    springboot打包無法讀取yml、properties等配置文件的解決

    這篇文章主要介紹了springboot打包無法讀取yml、properties等配置文件的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • UrlDecoder和UrlEncoder使用詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    UrlDecoder和UrlEncoder使用詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了UrlDecoder和UrlEncoder使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Java中的lambda和stream實(shí)現(xiàn)排序

    Java中的lambda和stream實(shí)現(xiàn)排序

    這篇文章主要介紹了Java中的lambda和stream實(shí)現(xiàn)排序,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • Mybatis 返回值類型和參數(shù)傳遞的配置方法

    Mybatis 返回值類型和參數(shù)傳遞的配置方法

    在 MyBatis 中,返回值類型和參數(shù)傳遞是 Mapper 接口中至關(guān)重要的兩個(gè)方面,正確理解和使用它們可以幫助我們高效、準(zhǔn)確地進(jìn)行數(shù)據(jù)庫(kù)操作,接下來通過本文給大家介紹Mybatis 返回值類型和參數(shù)傳遞的配置方法,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java實(shí)現(xiàn)支付寶支付接口的調(diào)用

    java實(shí)現(xiàn)支付寶支付接口的調(diào)用

    本文主要介紹了java實(shí)現(xiàn)支付寶支付接口的調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • IDEA連接mysql數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法

    IDEA連接mysql數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法

    這篇文章主要介紹了IDEA連接mysql數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法,文中有非常詳細(xì)的圖文示例,對(duì)出現(xiàn)Server returns invalid timezone. Go to ‘Advanced‘ tab and set ‘serverTimezone‘ prope報(bào)錯(cuò)的小伙伴們很有幫助喲,需要的朋友可以參考下
    2021-05-05
  • 四個(gè)Java常見分布式鎖的選型和性能對(duì)比

    四個(gè)Java常見分布式鎖的選型和性能對(duì)比

    當(dāng)涉及到分布式系統(tǒng)中的并發(fā)控制和數(shù)據(jù)一致性時(shí),分布式鎖是一種常見的解決方案,本文將對(duì)幾種常見的分布式鎖實(shí)現(xiàn)原理、實(shí)現(xiàn)示例、應(yīng)用場(chǎng)景以及優(yōu)缺點(diǎn)進(jìn)行詳細(xì)分析,需要的可以參考一下
    2023-05-05

最新評(píng)論

泰和县| 阳新县| 始兴县| 城市| 汝阳县| 镇江市| 奇台县| 湟源县| 衡水市| 安岳县| 稷山县| 田林县| 康平县| 全州县| 措勤县| 青田县| 毕节市| 和平县| 阿克苏市| 邳州市| 五常市| 长顺县| 鹰潭市| 定安县| 林口县| 乐陵市| 洞头县| 南乐县| 汪清县| 乡宁县| 历史| 长治县| 安乡县| 新余市| 昆明市| 合川市| 澄江县| 长垣县| 前郭尔| 岑溪市| 饶平县|