Java基礎之反射

框架都要用到反射技術,反射都要用到一個類Class.

java程序中的各個java類屬于同一類事物,描述這類事物的java類名就是Class.

得到字節碼的方式有三種:

Date.class;new Date().getClass();Class.forName("java.lang.String");最后一種是有直接返回,沒有則從硬盤加載。

有9個預定義的Class實例對象,8種基本數據類型加void.class:參考Class.isPrimitive方法doc;

public class ReflectTest {public static void main(String[] args) throws Exception {// args:javaplay.TestArgumentsString str1 = "abc";Class<?> cls1 = str1.getClass();Class<?> cls2 = String.class;Class<?> cls3 = Class.forName("java.lang.String");System.out.println(cls1 == cls2);// trueSystem.out.println(cls1 == cls3);// trueSystem.out.println(cls1.isPrimitive());// falseSystem.out.println(int.class.isPrimitive());// trueSystem.out.println(int.class == Integer.class);// false// Integer.TYPE代表它所包裝的基本類型字節碼,請查看docSystem.out.println(int.class == Integer.TYPE);// trueSystem.out.println(int[].class.isPrimitive());// falseSystem.out.println(int[].class.isArray());// trueSystem.out.println(void.class == Void.class);// false// 總之,在源程序中出現的類型,都有各自的Class實例對象,例如int[],void// 通常方式:String str = new String(new StringBuffer("abc"));// jdk5之前只能接受數組,不接受可變參數// Constructor constructor = String.class.getConstructor(new Class<?>[]// { StringBuffer.class, int.class });// 得到所有public構造方法Constructor[] constructors = Class.forName("java.lang.String").getConstructors();// 得到一個構造方法Constructor constructor1 = String.class.getConstructor(StringBuffer.class);// 反射方式(詳見doc 一目了然,不能是"abc",要用到與StringBuffer相同類型的對象)String str2 = (String) constructor1.newInstance(/* "abc" */new StringBuffer("abc"));System.out.println(str2.charAt(2));// c// Class.newInstance()方法,可省去class->constructors->new object中間獲取構造方法的環節// 從而直接創建對象,但它只能調用默認的無參構造方法,該方法內部先得到默認構造方法,然后用該構造方法創建對象,其中// 用到了緩存機制來保存默認構造方法的實例,這樣能省點事,直接調用newInstance而不用獲取構造方法的反射String o = (String) Class.forName("java.lang.String").newInstance();// 成員變量的反射ReflectPoint pt1 = new ReflectPoint(3, 5);Field fieldY = pt1.getClass().getField("y");// fieldY的值是多少?是5,錯!fieldY不是對象身上的變量,而是類上,要用它去取某個對象上對應的值System.out.println(fieldY.get(pt1));Field fieldX = pt1.getClass().getDeclaredField("x");// 私有成員要用DeclaredfieldX.setAccessible(true);// 設置true才可以訪問,暴力反射System.out.println(fieldX.get(pt1));// 將任意一個對象中的所有String類型的成員變量所對應的字符串內容中的"b"改成"a"changeStringValue(pt1);System.out.println(pt1);// 成員方法的反射// 普通方式:str.charAt(1),反射方式如下:Method methodCharAt = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt.invoke(str1, 1));// System.out.println(methodCharAt.invoke(null, 1));//靜態方法第一個參數才為null// 1.4還有可變參數,只能用數組,又因為參數五花八門,所以用Object,1.4的調用語法如下:System.out.println(methodCharAt.invoke(str1, new Object[] { 1 }));// 對接受數組參數的成員方法進行反射// 寫程序的時候不知道要執行哪個類的mainTestArguments.main(new String[] { "111", "222", "333" });String startingClassName = args[0];Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);mainMethod.invoke(null, new Object[] { new String[] { "111", "222", "333" } });// 原因在于1.5要兼容1.4mainMethod.invoke(null, (Object) new String[] { "111", "222", "333" });// 也行,總之,只能接受一個參數// mainMethod.invoke(null, (Object) new String[] { "111" }, (Object) new// String[] { "222" });// 不行// mainMethod.invoke(null, new String[] { "111" });// 不行/*** 啟動java程序的main方法的參數是一個字符串數組,通過反射方式調用時,如何傳遞參數呢,按1.5的語法,整個數組是一個參數,* 而按1.4的語法,數組中的每個元素對應一個參數,當把一個字符串數組作為參數傳遞給invoke方法時,javac會按照哪種方法進行* 處理呢?1.5肯定要兼容1.4,會按1.4的語法來處理,即把數組打散成若干個單獨的參數,所以,在給main方法傳遞參數時,不能使用* mainMethod.invoke(null,new* String[]{"xxx"}),javac會把它當作1.4語法來理解,會把里面的"xxx"當作需要傳遞的String[]{},所以* 參數類型不對。*//** 數組與Object的關系及其反射類型 . 1.具有相同維數和元素類型的數組屬于同一個類型,即具有相同的Class實例對象* 2.代表數組的Class實例對象的getSuperclass()方法返回的父類為Object類對應的Class* 3.基本類型的一維數組可以被當作Object類型使用,不能當作Object[]類型使用;非基本類型的一維數組,既* 可以當做Object類型使用,又可以當作Object[]類型使用* 4.Arrays.asList()方法處理int[]和String[]時的差異*/int[] a1 = new int[] { 1, 2, 3 };Integer[] a11 = new Integer[] { 1, 2, 3 };int[] a2 = new int[4];int[][] a3 = new int[2][3];String[] a4 = new String[] { "a", "b", "c" };System.out.println(a1.getClass() == a2.getClass());// true 數組的類型和維度相同就一樣// System.out.println(a1.getClass() == a4.getClass());//false// System.out.println(a1.getClass() == a3.getClass());//falseSystem.out.println(a1.getClass().getName());// [I Class的getName方法有詳細說明[ISystem.out.println(a1.getClass().getSuperclass().getName());// java.lang.ObjectSystem.out.println(a4.getClass().getSuperclass().getName());// java.lang.ObjectSystem.out.println(a4.getClass().getName());// [Ljava.lang.String;System.out.println(String.class.getName());// java.lang.StringSystem.out.println(String.class.getSuperclass().getName());// java.lang.ObjectSystem.out.println(a11.getClass().getName());// [Ljava.lang.Integer;System.out.println(a11.getClass().getSuperclass().getName());// java.lang.ObjectObject aObj1 = a1;Object bObj2 = a4;Object aObj11 = a11;// Object[] aObj3 = a1;// 不能賦值,int不是ObjectObject[] aObj4 = a3;// a3是一維數組的數組,Object相當于一個一維int數組,此時Object[]表示一維數組(int[])的數組Object[] aObj5 = a4;// String是ObjectObject[] aObj6 = a11;// 由此引申的一個問題System.out.println(a1);// [I@5fb7a531System.out.println(a4);// [Ljava.lang.String;@11be650f// 確實轉換成了數組,只是數組里只有一個元素,這個元素也是數組System.out.println(Arrays.asList(a1));// [[I@5fb7a531]// 字符串卻可以轉換,原因在于asList接受的是Object[](1.4)和T...(1.5),如果是String[]就按// 1.4的形式(因為符合1.4的形式,要向下兼容)轉換成了list了,// 如果是int[]就不符合Object[]的形式,就會按1.5的形式T...來處理,也即當成一個int[](即T)類型的元素System.out.println(Arrays.asList(a4));// [a, b, c]// 數組的反射printObject(a1);// 1 2 3printObject(a4);// a b cprintObject("xyz");// xyz// 有沒有辦法得到數組的類型?// 目前沒有 Object[] a = new Object[]{"a",1};// a[0].getClass();// 即只能得到某個具體元素的類型,不能得到整個數組的元素類型// 寫框架這些東西是必備,不寫框架,翻某些磚頭似的書像翻小說一樣了,this is 進步。}public static void changeStringValue(Object obj) throws Exception {Field[] fields = obj.getClass().getFields();for (Field field : fields) {if (field.getType() == String.class) {// 同一份字節碼,推薦用==String oldValue = (String) field.get(obj);String newValue = oldValue.replace("b", "a");field.set(obj, newValue);}}}public static void printObject(Object obj) {Class clazz = obj.getClass();if (clazz.isArray()) {// 對數組進行反射的類Arrayint len = Array.getLength(obj);for (int i = 0; i < len; i++) {System.out.println(Array.get(obj, i));}} else {System.out.println(obj);}}}class TestArguments {public static void main(String[] args) {for (String arg : args) {System.out.println(arg);}}
}
public class ReflectPoint {private int x;public int y;public String str1 = "ball";public String str2 = "basketball";public String str3 = "itcast";public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + x;result = prime * result + y;return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;ReflectPoint other = (ReflectPoint) obj;if (x != other.x)return false;if (y != other.y)return false;return true;}@Overridepublic String toString() {return "ReflectPoint [x=" + x + ", y=" + y + ", str1=" + str1 + ", str2=" + str2 + ", str3=" + str3 + "]";}}

反射就是把java類中的各種成分映射成相應的java類,例如,一個java類用一個Class類的對象表示,一個類中的組成部分:成員變量、方法、構造方法、包等信息也用一個個的java類來表示,它們是Field、Method、Constructor、Package等。

一個類中的每個成員都可以用相應的反射API類的一個實例對象來表示,通過調用Class類的方法可以得到這些實例對象。

ArrayList_HashSet比較及hashcode分析:

public class ReflectTest2 {public static void main(String[] args) {Collection<ReflectPoint> collections = new HashSet<>();ReflectPoint pt1 = new ReflectPoint(3, 3);ReflectPoint pt2 = new ReflectPoint(5, 5);ReflectPoint pt3 = new ReflectPoint(3, 3);collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);pt1.y = 7;// 修改后輸出2,不修改,輸出1collections.remove(pt1);// new ArrayList<>();輸出4,添加時不比較直接按順序存儲引用變量、// new HashSet<>();輸出3,存放時會先判斷集合里有沒有這個對象,有就不放不是覆蓋,想覆蓋要先remove再放// HashSet比較對象時調用對象默認equals是比較內存地址(通常是根據內存地址換算出來的,效果與==等價)// 實現equals和hashcode方法后輸出2,如果此時注釋hashcode或者equals其中任意一個則又輸出3了// 原因在于它會先根據hashcode的值,算出自己要存放的最終位置所在的區域,如果只注釋hashcode是有可能輸出2的,因為存放的區域可能相同,也可能不同// 再調用equals進行比較是否有相等的對象(hashcode只在hash算法的集合中才有意義,其它集合沒有任何價值),// 這就是輸出3的原因,pt1和pt3存放的區域不一樣,原因是沒有實現hashcode則根據內存地址進行計算存放的區域,// 為了讓相等的對象也肯定放在相同的區域,就有一個說法,如果兩個對象equals相等,則應該也要讓hashcode相等(不是hash集合就不要搞hashcode)// 注意:當一個對象被存儲進hashset集合中,就不能修改這個對象中那些參與計算哈希值的字段了。否則就刪除不了了,日積月累,// 不斷的添加、修改、刪除對象,而程序卻一直使用這個hash集合就會造成內存泄漏!因為hash集合中有很多對象已經沒用了卻沒釋放// 由hashcode的作用講到內存泄漏,由內存泄漏講到hashcode的作用!System.out.println(collections.size());}}

反射的作用->實現框架的功能

框架與工具類有區別,工具類被用戶的類調用,而框架則是調用用戶提供的類。

用反射技術開發框架的原理:簡單框架,把要使用的類放到配置文件里面

在工程根目錄下創建config.properties文件:

className=java.util.HashSet
public class ReflectTest2 {public static void main(String[] args) throws Exception {InputStream ips = new FileInputStream("config.properties");Properties props = new Properties();props.load(ips);ips.close();// 跟操作系統說,把window干掉,把自己關聯的系統/物理資源釋放,自己則由垃圾回收器管理String className = props.getProperty("className");Collection<ReflectPoint> collections = (Collection<ReflectPoint>) Class.forName(className).newInstance();// Collection<ReflectPoint> collections = new HashSet<>();ReflectPoint pt1 = new ReflectPoint(3, 3);ReflectPoint pt2 = new ReflectPoint(5, 5);ReflectPoint pt3 = new ReflectPoint(3, 3);collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);// pt1.y = 7;// 修改后輸出2,不修改,輸出1// collections.remove(pt1);System.out.println(collections.size());// config.properties文件內容是HashSet:2,ArrayList:4}}

用類加載器的方式管理資源和配置文件

public class ReflectTest2 {public static void main(String[] args) throws Exception {// eclipse會自動把包下面的java文件或者普通文件編譯后拷貝到classpath路徑下// InputStream ips = new FileInputStream("config.properties");// 類加載器能加載.class文件,那加載普通文件也是順帶的事,下表示在classpath指定的根目錄下去找指定的文件// 根目錄下肯定沒有,只是根目錄下的javaplay目錄下才有,此時不能定寫成/javaplay// ssh框架內部用的就是用的類加載器加載的配置文件,所以ssh的配置文件必須放在classpath指定的目錄下,原因就是它// 用的是類加載器讀取的配置文件,而第一種不僅可以讀還可以寫即保存,類加載器的方式只能讀不能寫InputStream ips11 = ReflectTest2.class.getClassLoader().getResourceAsStream("javaplay/config.properties");// 類提供了一個便捷方法不用獲取類加載器就可以加載配置文件,而且默認加載與自己同一個包內的配置文件InputStream ips2 = ReflectTest2.class.getResourceAsStream("config.properties");// 也可以相對路徑InputStream ips3 = ReflectTest2.class.getResourceAsStream("resource/config.properties");// 也可以絕對路徑,此時必須要以/開頭,不管相對還是絕對內部都是調用InputStream ips = ReflectTest2.class.getResourceAsStream("/javaplay/resource/config.properties");Properties props = new Properties();props.load(ips);ips.close();// 跟操作系統說,把window干掉,把自己關聯的系統/物理資源釋放,自己則由垃圾回收器管理String className = props.getProperty("className");Collection<ReflectPoint> collections = (Collection<ReflectPoint>) Class.forName(className).newInstance();// Collection<ReflectPoint> collections = new HashSet<>();ReflectPoint pt1 = new ReflectPoint(3, 3);ReflectPoint pt2 = new ReflectPoint(5, 5);ReflectPoint pt3 = new ReflectPoint(3, 3);collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);System.out.println(collections.size());// config.properties文件內容是HashSet:2,ArrayList:4}}


?

?

?


?

?

轉載于:https://www.cnblogs.com/john8169/p/9780569.html

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

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

相關文章

php socketconnect連接失敗_PHP設計模式之模板方法模式

模板方法模式&#xff0c;也是我們經常會在不經意間有會用到的模式之一。這個模式是對繼承的最好詮釋。當子類中有重復的動作時&#xff0c;將他們提取出來&#xff0c;放在父類中進行統一的處理&#xff0c;這就是模板方法模式的最簡單通俗的解釋。就像我們平時做項目&#xf…

linux系統硬件配置查看方法

一&#xff1a;查看cpu more /proc/cpuinfo | grep "model name" grep "model name" /proc/cpuinfo 如果覺得需要看的更加舒服 grep "model name" /proc/cpuinfo | cut -f2 -d: 二&#xff1a;查看內存 grep MemTotal /proc/meminfo grep MemT…

java String源碼學習

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/**char數組用于字符的存儲 */private final char value[];/** 緩存string的hash碼 */private int hash; // Default to 0public String() {/**無參構造函數,打印值為&quo…

JBoss AS 7.1.0.Final“ Thunder”發布-Java EE 6 Full Profile認證!

在JBoss AS7上進行了大約一年的開發后&#xff0c;我們現已發布7.1.0.Final“ Thunder” &#xff01; 可從此處的通常位置下載該文件。 對于JBoss AS7團隊來說&#xff0c;這是一個非常大的成就&#xff0c;我們為此版本感到非常自豪。 這個版本包含了7.1.0.CR1b的許多錯誤修復…

數據庫建表練習(10.11作業)

轉載于:https://www.cnblogs.com/HRZJ/p/5951897.html

天干地支計算公式_天干地支主怎樣計算?

回答&#xff1a;少女時代級別&#xff1a;碩士研究生2009-01-08 20:34:04來自&#xff1a;貴州省貴陽市我國古代是用天干地支來紀年的&#xff0c;現代社會已很少使用。一來現今社會已經離不開國際化&#xff0c;沿用老的歷法已經不現實&#xff1b;二來天干地支在民間多用于算…

從程序員到CTO的Java技術路線圖

時間:2013-05-29 17:39來源:www.chengxuyuans.com在技術方面無論我們怎么學習&#xff0c;總感覺需要提升自已不知道自己處于什么水平了。但如果有清晰的指示圖供參考還是非常不錯的&#xff0c;這樣我們清楚的知道我們大概處于那個階段和水平。 Java程序員 高級特性 反射、泛型…

Linux的網卡相關

檢測linux下網卡是否正常 1.dmesg | grep eth 如果出現以下 eth0: link up 說明是網卡正常的 eth0: registered as PCnet/PCI II 79C970Aeth0: link upeth0: no IPv6 routers present 2.如果所用網卡是pcI總線的 。用命令&#xff1a;lspci 能看到網卡是存在的。 3.用ethtool…

設置Spring 3開發環境

本教程簡要說明了如何設置典型的環境來開發基于Spring的應用程序。 除了可以正常工作的Windows XP客戶端具有足夠的CPU能力和內存外&#xff0c;本教程沒有其他先決條件。 在教程中&#xff0c;我們將需要安裝以下組件&#xff1a; Java 6 JDK更新26 用于Java EE開發人員的Ecl…

3. 跟蹤標記 (Trace Flag) 1204, 1222 抓取死鎖信息

跟蹤標記&#xff1a;1204/1222 功能及用途&#xff1a; 捕獲SQL Server死鎖信息&#xff0c;并自動存放到錯誤日志(ERRORLOG)中。 舉例&#xff1a; USE tempdb GO CREATE TABLE t1(id int) INSERT t1 SELECT 1CREATE TABLE t2(id int) INSERT t2 SELECT 1 GO --開啟1204/1222…

postgresql建表帶注釋_postgresql建表帶自增id和注釋語句

work是表名&#xff0c;nextval(work_myid_seq::regclass)這個是自增id的設置CREATE TABLE "public"."work" ("id" int8 NOT NULL DEFAULT nextval(work_myid_seq::regclass),"wid" int8,"address" varchar(100) COLLATE &q…

js中window.onload 與 jquery中$(document.ready()) 測試

js中window.onload 與 jquery中$(document.ready())區別&#xff0c;驗證代碼如下(調換js代碼和Jquer代碼書寫順序測試&#xff0c;運行結果一樣&#xff0c;因此與代碼書寫位置沒關系)&#xff1a;<html> <head> <script typetext/javascript srcjquery-1.11.1…

5. Longest Palindromic Substring

更新&#xff1a; 之前那種dp太笨重了有個非常的輕巧的做法&#xff0c;原理都是一樣的。 轉移方程不變&#xff0c;但是不需要特別的初始化 判斷某個格子是不是true&#xff0c;是 1.要么長度小于3&#xff0c;要么dp[start1][end-1]true 2.并且s.charAt(start) s.charAt(end…

Java中的定制國際化(i18n)

國際化&#xff08;i18n&#xff09;在我們的軟件項目中非常重要。 它主要帶來以下好處&#xff1a; 將UI字符串外部化為除代碼文件之外的外部文件&#xff0c;以及易于管理的UI內容。 支持多種語言。 在這篇文章中&#xff0c;將為Eclipse和Java項目提供一個簡短的i18n實際示…

SEO 百度后臺主動推送鏈接

實踐步驟&#xff0c;先用爬蟲程序將本網站的所有連接爬取出來&#xff0c;再用python文件處理程序把爬蟲來的東東整理成一行一個鏈接的文本格式。再用postman接口測試工具&#xff0c;使用post方式&#xff0c;將所有的鏈接post過去&#xff0c;這樣主動推送是最為快速的提交方…

linux版本 如何查kali_000_Kali Linux版本查看和apt源配置

1.查看系統版本# cat /etc/issue# lsb_release -a2.查看內核信息# uname -a3.更新源# cp /etc/apt/source.list{,.bak}# vim /etc/apt/sources.list//備注&#xff1a;國外源速度太慢&#xff0c;這里禁止&#xff1b;網絡中的部分源已經過期&#xff0c;建議更換其它源。# kal…

nyoj--127--星際之門(一)(生成樹的數量)

星際之門&#xff08;一&#xff09; 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;3描述公元3000年&#xff0c;子虛帝國統領著N個星系&#xff0c;原先它們是靠近光束飛船來進行旅行的&#xff0c;近來&#xff0c;X博士發明了星際之門&…

Oracle 常用的一些函數

字符函數 SELECT UPPER(hello WORLD) FROM DUAL; //將小寫字母變為大寫字母SELECT LOWER(hello WORLD) FROM DUAL; //將大寫字母變為小心字母SELECT INITCAP(hello WORLD) FROM DUAL; //將字符串的首字母大寫SELECT CONCAT(hello, world) FROM DUAL; //字符串拼…

Apache Camel 2.9發布–十大變化

在2011年的最后一天&#xff0c;阿帕奇駱駝制品被成功地推到了中央行銷倉庫&#xff0c;距離香檳酒瓶破裂并進入2012年僅1.5個小時之遙。 2.9版是創紀錄的發行版&#xff0c;自5個月前發布2.8版以來&#xff0c;已解決了約500張JIRA票證。 以下是10個最明顯的改進和新功能的分…

HTML5筆記——formData

注&#xff1a;formData中的數據在控制臺上的console里面是打印不出來的&#xff0c;只能在控制臺的network里面查看到具體的發送數據和發送選項 文章出處&#xff1a;夢想天空 XMLHttpRequest Level 2 添加了一個新的接口——FormData。利用 FormData 對象&#xff0c;我們可以…