泛型與反射

也是重新溫習了下泛型與反射,反射基本就是一些api理解即可,不過需要注意類加載器原理,而泛型則需要理解其設計思想,可以代替Object,更加靈活,可讀性強。

泛型

泛型如果指定后,編譯階段就會檢查,不讓亂輸其他類型,必須是引用類型; 如果不指定就默認Object

// 如果指定泛型, 就必須存指定的類型  Iterator<String> iterator = arrayList.iterator();
List<String> arrayList = new ArrayList<>();
?
/*** new 集合 如果沒有指定泛型* 存放的類型是為Object類型*/
ArrayList arrayList = new ArrayList();
// Iterator iterator = arrayList.iterator();
//如果想要精確獲取,則String str = (String)iterator.next; 需要強轉,不過因為存放的不是一種類型,所以還要判斷(instanceof),否則可能轉換異常
1.Java 泛型 (generics) 是 JDK 5 中引入的一個新特性,泛型提供了編譯時類型安全檢測機制,該機制允許程序員在編譯時檢測到非法的類型。
2. 早期的時候,使用 Object 來代表任意類型。但是這樣在向上轉型的是沒有問題的,但是在向下轉型的時候存在類型轉換的問題,這樣的程序其實是不安全的。所以 Java 在 JDK5 之后提供了泛型來解決這個問題
3. 泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。
4. 泛型是一種把類型的明確工作推遲到創建對象或者調用方法的時候才去明確的特殊類型。
注意:類型參數只能代表引用型類型,不能是原始類型 (像 int,double,char 的等)。
泛型可以使用在 方法、接口、類 分別稱作為:泛型類、泛型方法、泛型接口。

泛型類

泛型類定義的格式: 格式:修飾符 class 類名 <類型>{} 范例:public class Student<T>{} 此處 T 可以隨便寫為任意標識,T、E、K、V 等型式的參數常用于表示泛型;

/*** 泛型類優化*/
public class Student<T> {private T number;public T show(T t) {return t;}
}

缺點就是: 如果想要傳遞不同類型的方法則需要創建指明多個對象; (Object強轉就不考慮了,因為需要先instanceof判斷類型)

泛型方法

可以優化掉方法重載

格式:修飾符 <類型> 返回值類型 方法名 (類型 變量名){...} 范例:public<T> void show(T t){...}

public class Student {public <T> T show(T t) {return t;}
}

優點: 可以只new一個對象,然后直接傳遞不同類型的方法,此時會正常獲取,而且我們也不用手動<指定類型>,ctrl alt v 可以正常解析獲取

泛型接口

格式:修飾符 interface 接口名 <類型>{...} 范例:public interface MayiktInterface <T>{...}

public interface Student<T> {T show(T t) {return t;} // 默認public
}
// 如果直接實現,還是Object
public class StudentImpl<T> implements Student<T> {@Overridepublic T show(T t) {return t; // 而且此時可以發現,創建后傳參,前方會隱式顯示參數的名字,t}
}
public class Test01 {public static void main(String[] args) {Student<String> stringMayikt = new StudentImpl<>();String show = stringMayikt.show("36");System.out.println(show);}
}

方法:

public interface Mayikt<T> {<M> T show(T t, M m); // 如果寫成<T> T show (T t); 則這個T對應泛型方法,而不是類上的T,所以下方如果實現則變成T1好區分
}
public class MayiktImpl<T> implements MayiktInterface<T> {@Override public <M> T show(T t, M m) {System.out.println(m);return t;}
}

泛型通配符

  1. 類型通配符 一般用于接受使用,不能夠做添加。

  2. List : 表示元素類型未知的 list,它的元素可以匹配任何類型。

  3. 帶通配符的 List 僅表示它是各種泛型 List 的父類,并不能把元素添加到其中。 (而且也是需要判斷類型的,否則此時獲得的是Object)

  4. 也是可以遍歷的,但是不能添加,比如 .add方法

  5. 類型通配符上限:<? extends 類型> List<? extends MayiktParent>: 它表示的類型是 MayiktParent 或者子類型。

  6. 類型通配符下限:<? super 類型> List<? super MayiktParent>: 它表示的類型是 MayiktParent 或者其父類型

/*** 定義的 printList方法 明確知道 接受具體 list泛型 是什么類型* List<?> 只能夠用于接受 ?------- 可以接受所有的泛型類型 不能夠用于添加* 是可以做get操作 獲取到類型是為Object類型** @param stringList*/
public static void printList(List<?> stringList) { // List<? extends People> stringList 也可以這樣傳參Object o = stringList.get(0); // 直接獲取到的是Object類型Iterator<?> iterator = stringList.iterator(); // 拿到的也是?while (iterator.hasNext()){System.out.println(iterator.next()); // 如果想要強轉iterator.next()為指定的對象,則instanceof判斷一下}
}

可變參數

  1. 可變參數 又稱 參數個數可變,用作方法的形參出現,那么方法參數個數就是 可變 的了。 (底層基于數組實現)

  2. 書寫格式: 2.1 格式:修飾符 返回值類型 方法名 (數據類型... 量名){} 2.2 范例:public static int sum (int... a) {}

  3. 可變參數 注意事項: 這里的 可變參數變量 其實是一個數組。 如果一個方法 有多個參數,包含可變參數,可變參數要放在最后

public static int sum(int... a) {int sum = 0;for (int i = 0; i < a.length; i++) {sum+=a[i];}return sum;
}

ArrayList中的asList就用到了可變參數 T...

public class Test04 {public static void main(String[] args) {/*** 使用 Arrays.asList 定義好的 元素個數 是不能夠發生變化的*/List<String> strings = Arrays.asList("mayikt", "meite", "wangmazi");// 注意 如果使用Arrays.asList 方法 創建的 集合 不能夠添加和刪除strings.set(0, "6666"); // 可以修改,不能add和removeSystem.out.println(strings);}
}

擦除機制(底層)

說明:將一個 List 集合 泛型賦值給一個沒有使用到泛型 List 集合 直接去除泛型 --- 擦除機制

反編譯后可以發現運行階段沒有泛型

List<String> strs = new ArrayList<String>();
strs.add("mayikt");
//說明:將一個List集合 泛型賦值給一個未使用泛型的集合會直接去除掉
List list = strs; // 此時仍然可以添加Object類型變量

反射

1.Java 反射機制的核心是在程序運行時動態加載類并獲取類的詳細信息,從而操作類或對象的屬性和方法。本質是 JVM 得到 class 對象之后,再通過 class 對象進行反編譯,從而獲取對象的各種信息。

2.Java 屬于先編譯再運行的語言,程序中對象的類型在編譯期就確定下來了,而當程序在運行時可能需要動態加載某些類,這些類因為之前用不到,所以沒有被加載到 JVM。通過反射,可以在運行時動態地創建對象并調用其屬性,不需要提前在編譯期知道運行的對象是誰。

Java 反射機制可以動態方式獲取到 class 相關信息 class 中成員方法、屬性,反射技術靈活調用方法 或者給我們成員屬性賦值,class.forName 初始化對象(創建我們的對象)

類加載器

xxx.getClass().getClassLoader().loadClass();
類加載器的主要作用:
類加載器(ClassLoader)是 Java 虛擬機中負責加載類的組件,它的核心職責是將類的字節碼文件(.class文件)加載到 JVM 中,并生成對應的Class對象,以便 JVM 可以使用這些類進行實例化、方法調用等操作。具體過程如下:
?
加載:在這一階段,類加載器會根據類的全限定名(包名 + 類名)找到對應的.class文件,通過 IO 操作讀取其字節碼數據,然后在 JVM 內存中創建一個對應的Class對象 。這就好比從磁盤這個 “倉庫” 中把類的 “藍圖” 搬運到 JVM 的 “工作區”,并整理成 JVM 能識別的格式。
?
鏈接:包括驗證(確保字節碼符合 JVM 規范,如文件格式正確、字節碼指令合法等)、準備(為類的靜態變量分配內存并設置初始值,比如static int num = 10; 在準備階段num會被初始化為 0 )、解析(將符號引用轉換為直接引用,讓 JVM 能準確找到要訪問的類、方法、變量等)。
?
初始化:對類的靜態變量進行賦值和執行靜態代碼塊,使類進入可使用狀態。
?
對于同一個類,類加載器不一定只會執行一次,這要分情況來看:
?
同一個類加載器:在 Java 中,為了提高性能和避免重復加載,JVM 會維護一個已加載類的緩存。當使用同一個類加載器嘗試加載一個已經加載過的類時,類加載器會直接從緩存中返回已存在的Class對象,而不會再次執行完整的加載流程。 例如,在一個普通的 Java 應用中,自定義一個類加載器加載某個類,后續再次請求加載該類時,不會重復加載。
?
不同類加載器:如果使用不同的類加載器去加載同一個類(比如自定義了多個不同的類加載器,或者應用程序中同時存在系統類加載器和自定義類加載器 ),由于類加載器的命名空間相互隔離,每個類加載器都有自己獨立的已加載類緩存,那么就會出現多次加載同一個類的情況,且不同類加載器加載出來的類,在 JVM 中被視為不同的類。例如,通過自定義類加載器加載一個User類,再通過系統類加載器加載User類,這兩個User類的Class對象在 JVM 中是不同的,它們之間不能進行類型轉換等操作。
?
不過,對于 Java 核心類庫中的類(由啟動類加載器加載),在 JVM 啟動過程中會被加載一次,之后在整個應用運行期間,不會再重復加載 。但對于自定義類或其他非核心類,類加載器的加載次數取決于類加載器的使用方式和 JVM 的運行邏輯。

類加載器: 當我們new出自定義對象時,如果發現沒有加載到程序內存中,此時就會開始執行類加載器將該對象加載,而項目剛開始運行的時候應該底層依賴了其他類,所以其他先進行加載

class不管什么方式獲取到的,都是唯一的

public class Test13 {public static void main(String[] args) throws ClassNotFoundException {// 1.獲取class方式 直接類名稱.Class<MayiktUserEntity> mayiktUserEntityClass = MayiktUserEntity.class;// 2.new 對象 通過對象獲取class  springioc容器 根據class獲取對象MayiktUserEntity mayiktUserEntity = new MayiktUserEntity();Class<? extends MayiktUserEntity> aClass = mayiktUserEntity.getClass();// 類的完整路徑地址 包的名稱+類名稱組合  第三種,企業使用最多,不過因為怕路徑寫錯,所以也要拋異常Class<?> aClass1 = Class.forName("com.mayikt.entity.MayiktUserEntity");}
}

注意 : 上述三種獲取到的class都是完全相同的,因為運行期間,一個類只會產生一個class

反射應用的幾個常見場景:
1.JDBC 中 Class.forName ("com.mysql.jdbc.Driver")---- 反射技術加載 mysql 驅動
2.Spring 底層基于反射初始化對象
3.(寫一套自己)第三方框架擴展功能 代理設計模式

初始化對象

注意: 上邊倆個創建對象代碼都是只能獲取公有的,如果想獲取全部方法,那么就Declared即可

(1)批量獲取的方法:
public Constructor[] getConstructors():所有"公有的"構造方法
public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有)
(2)單個獲取的方法,并調用:
public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"
(3) 調用構造方法:
Constructor-->newInstance(Object... initargs)
newInstance是 Constructor類的方法(管理構造函數的類)
api的解釋為: newInstance(Object... initargs) ,使用此 Constructor 對象表示的構造方法來創建
它的返回值是T類型,所以newInstance是創建了一個構造方法的聲明類的新實例對象,并為之調用。

獲取成員屬性

獲取成員變量并調用:

  1. 批量的 1.1 Field[] getFields():獲取所有的"公有字段" 1.2 Field[] getDeclaredFields():獲取所有字段,包括: 私有、受保護、默認、公有;

  2. 獲取單個的: 2.1.public Field getField(String fieldName):獲取某個"公有的"字段; 2.2.public Field getDeclaredField(String fieldName):獲取某個字段(可以是私有的)

  3. 設置字段的值 需要注意權限問題: 3.1.Field --> public void set(Object obj,Object value): 3.2.參數說明: 3.3.obj:要設置的字段所在的對象;

public class Test15 {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {// 獲取class成員屬性(反射給成員屬性賦值、反射調用我們方法)//1.java反射技術 創建對象Class<?> aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");//Field[] fields = aClass.getFields();) // 獲取所有的"公有字段"Field[] fields = aClass.getDeclaredFields(); // 獲取所有字段//2.獲取單個的:for (int i = 0; i < fields.length; i++) {System.out.println(fields[i]);}// 如何給成員屬性賦值呢?MayiktUserEntity mayiktUserEntity = (MayiktUserEntity) aClass.newInstance();Field userNameField = aClass.getDeclaredField("userName");// 反射技術給私有成員屬性賦值  參數1:傳遞對象  參數2:賦值的內容// 如果通過反射技術給私有成員屬性賦值的情況下 設置下訪問的權限userNameField.setAccessible(true); // 先設置權限才可賦值userNameField.set(mayiktUserEntity, "mayikt666"); // 這個也是獲取到對象,然后再修改System.out.println(mayiktUserEntity.getUserName());}
}

調用方法

  1. 所有的方法: 1.1.public Method [] getMethods (): 獲取所有 "公有方法";(包含了父類的方法也包含 Object 類) 1.2.public Method [] getDeclaredMethods (): 獲取所有的成員方法,包括私有的 (不包括繼承的)

  2. 獲取單個的方法: 2.1.public Method getMethod (String name,Class... parameterTypes): 參數: name:方法名; Class ...:形參的Class類型對象 public Method getDeclaredMethod(String name,Class... parameterTypes)

  3. 調用方法: Method --> public Object invoke (Object obj,Object... args): 參數說明: obj: 要調用方法的對象;

注意 此時獲取到的公有方法還包含了Object,這是和其他不同的地方

Method addUserMethod = aClass.getDeclaredMethod("addUser", String.class, Integer.class);
MayiktUserEntity mayiktUserEntity = (MayiktUserEntity) aClass.newInstance();
addUserMethod.setAccessible(true);
String result = (String) addUserMethod.invoke(mayiktUserEntity, "mayikt", 22);
System.out.println(result); //看自己編寫的方法有沒有返回值可獲取

也是調用修改方法或屬性強,如果是私有設置一下權限即可

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96396.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96396.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96396.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker端口映射與數據卷完全指南

目錄 Docker端口映射與數據卷完全指南 1. 端口映射:連接Docker容器與外部世界 1.1 為什么需要端口映射 1.2 實現端口映射 1.3 查看端口映射 1.4 修改端口映射(高級操作) 2. 數據卷:Docker數據持久化解決方案 2.1 數據持久化問題 2.2 數據卷的含義 2.3 數據卷的特點 2.4 掛載…

【Linux篇章】穿越網絡迷霧:揭開 HTTP 應用層協議的終極奧秘!從請求響應到實戰編程,從靜態網頁到動態交互,一文帶你全面吃透并征服 HTTP 協議,打造屬于你的 Web 通信利刃!

本篇摘要 本篇將介紹何為HTTP協議&#xff0c;以及它的請求與答復信息的格式&#xff08;請求行&#xff0c;請求包頭&#xff0c;正文等&#xff09;&#xff0c;對一些比較重要的部分來展開講解&#xff0c;其他不常用的即一概而過&#xff0c;從靜態網頁到動態網頁的過渡&a…

QT的項目pro qmake編譯

使用qmake管理Qt庫的子工程示例-CSDN博客 top_srcdir top_builddir

語音交互系統意圖識別介紹和構建

一、意圖識別簡介**意圖識別&#xff08;Intent Recognition&#xff09;**是語音交互系統的核心組件&#xff0c;用于理解用戶語音輸入背后的真實目的&#xff08;如查詢天氣、播放音樂等&#xff09;。輸入&#xff1a;語音轉文本&#xff08;ASR輸出&#xff09;的語句輸出&…

DINOv3 重磅發布

2025年8月14日 Meta 發布了 DINOv3 。 主頁&#xff1a;https://ai.meta.com/dinov3/ 論文&#xff1a;DINOv3 HuggingFace地址&#xff1a;https://huggingface.co/collections/facebook/dinov3-68924841bd6b561778e31009 官方博客&#xff1a;https://ai.meta.com/blog/d…

ansible playbook 實戰案例roles | 實現基于firewalld添加端口

文章目錄一、核心功能描述二、roles內容2.1 文件結構2.2 主配置文件2.3 tasks文件內容免費個人運維知識庫&#xff0c;歡迎您的訂閱&#xff1a;literator_ray.flowus.cn 一、核心功能描述 這個 Ansible Role (firewalld) 的核心功能是&#xff1a;動態地、安全地配置 firewal…

【深度學習實戰(55)】記錄一次在新服務器上使用docker的流程

使用docker&#xff1a;apt-get install dockersudo usermod -aG docker sliu &#xff08;將用戶 sliu 添加到 docker 用戶組&#xff09;newgrp docker &#xff08;刷新&#xff09;docker imagessudo docker load --input /home/sliu/workspace/env/shuai_docker.tar &…

面試后的跟進策略:如何提高錄用幾率并留下專業印象

面試結束后&#xff0c;許多求職者認為自己的任務已經完成&#xff0c;只需等待結果通知。然而&#xff0c;面試后的跟進策略同樣是求職過程中的關鍵環節&#xff0c;它不僅能提高你的錄用幾率&#xff0c;還能展示你的專業素養和持續興趣。本文將結合酷酷面試平臺的專業建議&a…

深入解析RAGFlow六階段架構

下面用“流程圖 六階段拆解”的方式&#xff0c;把 RAGFlow 的完整流程逐層剖開&#xff0c;力求把每一步的輸入、輸出、可選策略、內部機制都講清楚。 ──────────────────────── 一、總覽圖&#xff08;先建立體感&#xff09; 用戶提問 │ ├─→【…

Go語言中的迭代器模式與安全訪問實踐

Go語言中的迭代器模式與安全訪問實踐 1. 迭代器模式在Go中的演進 1.1 傳統迭代器模式回顧 在傳統面向對象語言中&#xff0c;迭代器模式通常涉及三個核心組件&#xff1a;可迭代集合接口(Iterable)迭代器接口(Iterator)具體實現類// 傳統迭代器模式示例 type Iterator interfac…

從零開始:JDK 在 Windows、macOS 和 Linux 上的下載、安裝與環境變量配置

前言 在進入 Java 世界之前&#xff0c;搭建一個穩定、可用的開發環境是每個開發者必須邁過的第一道門檻。JDK&#xff08;Java Development Kit&#xff09;作為 Java 程序開發的核心工具包&#xff0c;其正確安裝與環境變量配置直接關系到后續編譯、運行、調試等所有開發流程…

【音視頻】芯片、方案、市場信息收集

系統級芯片安霸&#xff08;Ambarella&#xff09;Ambarella H22/H32&#xff1a;高端方案&#xff0c;支持8K/4K高幀率錄制&#xff0c;低功耗&#xff0c;廣泛用于GoPro Hero 11/12、Insta360等旗艦機型。 Ambarella A12/A10&#xff1a;早期主流方案&#xff0c;支持4K60fps…

中科米堆CASAIM提供機加工件來料自動化測量尺寸方案

機加工行業面臨日益嚴格的質量追溯要求&#xff0c;來料質量的穩定性直接影響著后續生產效率與成品合格率。傳統人工檢測方式受限于接觸式工具的測量精度與操作效率&#xff0c;難以應對小批量、多品種的現代生產需求。傳統機加工件來料檢測長期面臨這些問題&#xff1a;其一&a…

MySQL只操作同一條記錄也會死鎖嗎?

大家好&#xff0c;我是鋒哥。今天分享關于【MySQL只操作同一條記錄也會死鎖嗎?】面試題。希望對大家有幫助&#xff1b; MySQL只操作同一條記錄也會死鎖嗎? 超硬核AI學習資料&#xff0c;現在永久免費了&#xff01; 在 MySQL 中&#xff0c;死鎖通常是由于多個事務對不同…

知識蒸餾 Knowledge Distillation 論文 Generalized Knowledge Distillation (GKD) 乘法法則、全概率公式、貝葉斯定理

知識蒸餾 Knowledge Distillation 論文 Generalized Knowledge Distillation (GKD) 乘法法則、全概率公式、貝葉斯定理 flyfish 代碼實踐 On-Policy Distillation of Language Models: Learning from Self-Generated Mistakes 設定&#xff08;方便算數&#xff09;&#x…

Fastjson 2.x踩坑——序列化Java字段為null值默認輸出

先上無法實現效果的代碼&#xff0c;我的目的是序列化時如果數字型字段為null則填0&#xff0c;盡可能保證數據整齊。 Data NoArgsConstructor AllArgsConstructor ToString JSONType(serializeFeatures {JSONWriter.Feature.WriteNulls,JSONWriter.Feature.WriteMapNullValue…

4G高負荷解決方案

4G高負荷解決方案 一、網絡優化手段&#xff08;低成本優先&#xff09;參數優化 調整功率控制、負荷均衡參數。優化小區重選與切換參數&#xff0c;避免高負荷小區擁塞。負荷均衡 開啟 MLB&#xff08;Mobility Load Balancing&#xff0c;移動負荷均衡&#xff09;。引導用戶…

K8S 安裝部署 Rocky Linux 10.0 + Docker + Containerd + Calico

Docker Containerd Flannel 安裝部署K8S 系統環境準備 # 1. 設置主機名 hostnamectl set-hostname k8s-n1 && bash# hostnamectl set-hostname k8s-n2 && bash # hostnamectl set-hostname k8s-n3 && bash# 2. 刪除系統自帶的容器軟件&#xff08;可…

新華三H3CNE網絡工程師認證—等價路由

等價路由就是“去同一個地方有多條路&#xff0c;時間一樣近&#xff0c;快遞站聰明地分撥送貨”的技術&#xff01;&#xff08;網絡不堵車&#xff0c;速度翻倍爽&#xff01;&#xff09;路由表中存在等價路由之后&#xff0c;前往該目的網段的IP報文路由器輝通過所有有效的…

DBLens 業界首創AI表結構變更審查,智能評估影響,助力開發效率躍升。

智能守護每一次變更&#xff1a;dblens AI 審查流程詳解 在快速迭代的軟件開發過程中&#xff0c;數據庫結構變更是常見卻高風險的操作。一次不經意的字段調整&#xff0c;可能引發線上故障、數據不一致甚至業務中斷。為應對這一挑戰&#xff0c;dblens 率先引入AI驅動的表結構…