java反射 虚拟机优化_面试官问我:Java反射是什么?我回答竟然不上来......
每天凌晨00點00分,第一時間與你相約
每日英文
We all have moments of desperation. But if we can face them head on, that’s when we find out just how strong we really are.
我們都有絕望的時候,只有在勇敢面對時,我們才知道我們有多堅強。
每日掏心話
記住該記住的,忘記該忘記的,改變能改變的,接受不能改變的。
來自:火星十一郎| 責編:樂樂
鏈接:cnblogs.com/hxsyl
程序員小樂(ID:study_tech)第 935 次推文 圖源:百度
往日回顧:程序員下班關閉顯示器,卻從不關電腦,你知道為什么嗎?
正文
一.概念
反射就是把Java的各種成分映射成相應的Java類。
Class類的構造方法是private,由JVM創建。
反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查并且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法并且顯示出來。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。(來自Sun)
JavaBean 是 reflection 的實際應用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過 reflection 動態的載入并取得 Java 組件(類) 的屬性。
反射是從1.2就有的,后面的三大框架都會用到反射機制,涉及到類"Class",無法直接new CLass(),其對象是內存里的一份字節碼.
Class 類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。關注公眾號程序員小樂回復關鍵字“offer”獲取算法面試題和答案
基本的 Java類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也表示為 Class 對象。Class 沒有公共構造方法。
Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的。
Personp1=newPerson();
//下面的這三種方式都可以得到字節碼
CLassc1=Date.class();
p1.getClass();
//若存在則加載,否則新建,往往使用第三種,類的名字在寫源程序時不需要知道,到運行時再傳遞過來
Class.forName("java.lang.String");
Class.forName()字節碼已經加載到java虛擬機中,去得到字節碼;java虛擬機中還沒有生成字節碼 用類加載器進行加載,加載的字節碼緩沖到虛擬機中。
考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。
importjava.lang.reflect.*;
publicclassDumpMethods{
publicstaticvoidmain(Stringargs[]){
try{
Classc=Class.forName("java.util.Stack");
Methodm[]=c.getDeclaredMethods();
for(inti=0;i
System.out.println(m[i].toString());
}
catch(Throwablee){
System.err.println(e);
}
}
}
publicsynchronizedjava.lang.Objectjava.util.Stack.pop()
publicjava.lang.Objectjava.util.Stack.push(java.lang.Object)
publicbooleanjava.util.Stack.empty()
publicsynchronizedjava.lang.Objectjava.util.Stack.peek()
publicsynchronizedintjava.util.Stack.search(java.lang.Object)
;i++)
這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。這個程序使用Class.forName載入指定的類,然后調用 getDeclaredMethods 來獲取這個類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類。
以下示例使用 Class 對象來顯示對象的類名:
voidprintClassName(Objectobj){
System.out.println("Theclassof"+obj+
"is"+obj.getClass().getName());
}
還可以使用一個類字面值(JLS Section 15.8.2)來獲取指定類型(或 void)的 Class 對象。例如:
System.out.println("ThenameofclassFoois:"+Foo.class.getName());
在沒有對象實例的時候,主要有兩種辦法。
//獲得類類型的兩種方式
Classcls1=Role.class;
Classcls2=Class.forName("yui.Role");
注意第二種方式中,forName中的參數一定是完整的類名(包名+類名),并且這個方法需要捕獲異?!,F在得到cls1就可以創建一個Role類的實例了,利用Class的newInstance方法相當于調用類的默認的構造器。
Objecto=cls1.newInstance();
//創建一個實例
//Objecto1=newRole();//與上面的方法等價
二.常用方法
1.isPrimitive(判斷是否是基本類型的字節碼)
publicclassTestReflect{
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
Stringstr="abc";
Classcls1=str.getClass();
Classcls2=String.class;
Classcls3=null;//必須要加上null
try{
cls3=Class.forName("java.lang.String");
}catch(ClassNotFoundExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
System.out.println(cls1.isPrimitive());
System.out.println(int.class.isPrimitive());//判定指定的 Class 對象是否表示一個基本類型。
System.out.println(int.class==Integer.class);
System.out.println(int.class==Integer.TYPE);
System.out.println(int[].class.isPrimitive());
System.out.println(int[].class.isArray());
}
}
結果:
true
true
false
true
false
true
false
true
2.getConstructor和getConstructors()
java中構造方法沒有先后順序,通過類型和參數個數區分。
publicclassTestReflect{
publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException{
//TODOAuto-generatedmethodstub
Stringstr="abc";
System.out.println(String.class.getConstructor(StringBuffer.class));
}
}
3.Filed類代表某一類中的一個成員變量。
importjava.lang.reflect.Field;
publicclassTestReflect{
publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{
ReflectPointerrp1=newReflectPointer(3,4);
Fieldfieldx=rp1.getClass().getField("x");//必須是x或者y
System.out.println(fieldx.get(rp1));
/*
*private的成員變量必須使用getDeclaredField,并setAccessible(true),否則看得到拿不到
*/
Fieldfieldy=rp1.getClass().getDeclaredField("y");
fieldy.setAccessible(true);//暴力反射
System.out.println(fieldy.get(rp1));
}
}
classReflectPointer{
publicintx=0;
privateinty=0;
publicReflectPointer(intx,inty){//alt+shift+s相當于右鍵source
super();
//TODOAuto-generatedconstructorstub
this.x=x;
this.y=y;
}
}
三.典型例題
1.將所有String類型的成員變量里的b改成a。
importjava.lang.reflect.Field;
publicclassTestReflect{
publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{
ReflectPointerrp1=newReflectPointer(3,4);
changeBtoA(rp1);
System.out.println(rp1);
}
privatestaticvoidchangeBtoA(Objectobj)throwsRuntimeException,Exception{
Field[]fields=obj.getClass().getFields();
for(Fieldfield:fields){
//if(field.getType().equals(String.class))
//由于字節碼只有一份,用equals語義不準確
if(field.getType()==String.class){
StringoldValue=(String)field.get(obj);
StringnewValue=oldValue.replace('b','a');
field.set(obj,newValue);
}
}
}
}
classReflectPointer{
privateintx=0;
publicinty=0;
publicStringstr1="ball";
publicStringstr2="basketball";
publicStringstr3="itcat";
publicReflectPointer(intx,inty){//alt+shift+s相當于右鍵source
super();
//TODOAuto-generatedconstructorstub
this.x=x;
this.y=y;
}
@Override
publicStringtoString(){
return"ReflectPointer[str1="+str1+",str2="+str2+",str3="
+str3+"]";
}
}
2.寫一個程序根據用戶提供的類名,調用該類的里的main方法。
為什么要用反射的方式呢?
importjava.lang.reflect.Field;
importjava.lang.reflect.Method;
publicclassTestReflect{
publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{
Stringstr=args[0];
/*
*這樣會數組角標越界,因為壓根沒有這個字符數組
*需要右鍵在runas-configurations-arguments里輸入b.Inter(完整類名)
*
*/
Methodm=Class.forName(str).getMethod("main",String[].class);
//下面這兩種方式都可以,main方法需要一個參數
m.invoke(null,newObject[]{newString[]{"111","222","333"}});
m.invoke(null,(Object)newString[]{"111","222","333"});//這個可以說明,數組也是Object
/*
*m.invoke(null,newString[]{"111","222","333"})
*上面的不可以,因為java會自動拆包
*/
}
}
classInter{
publicstaticvoidmain(String[]args){
for(Objectobj:args){
System.out.println(obj);
}
}
}
3.模擬instanceof操作符
classS{
}
publicclassIsInstance{
publicstaticvoidmain(Stringargs[]){
try{
Classcls=Class.forName("S");
booleanb1=cls.isInstance(newInteger(37));
System.out.println(b1);
booleanb2=cls.isInstance(newS());
System.out.println(b2);
}
catch(Throwablee){
System.err.println(e);
}
}
}
在這個例子中創建了一個S 類的 Class 對象,然后檢查一些對象是否是S的實例。Integer(37) 不是,但 new S()是。關注公眾號程序員小樂回復關鍵字“Java”獲取面試題和答案
四.Method類
代表類(不是對象)中的某一方法。
importjava.lang.reflect.Field;
importjava.lang.reflect.Method;
/*
*人在黑板上畫圓,涉及三個對象,畫圓需要圓心和半徑,但是是私有的,畫圓的方法
*分配給人不合適。
*
*司機踩剎車,司機只是給列車發出指令,剎車的動作還需要列車去完成。
*
*面試經??济嫦驅ο蟮脑O計,比如人關門,人只是去推門。
*
*這就是專家模式:誰擁有數據,誰就是專家,方法就分配給誰
*/
publicclassTestReflect{
publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{
Stringstr="shfsfs";
//包開頭是com表示是sun內部用的,java打頭的才是用戶的
MethodmtCharAt=String.class.getMethod("charAt",int.class);
Objectch=mtCharAt.invoke(str,1);//若第一個參數是null,則肯定是靜態方法
System.out.println(ch);
System.out.println(mtCharAt.invoke(str,newObject[]{2}));//1.4語法
}
}
五.數組的反射
Array工具類用于完成數組的反射操作。
同類型同緯度有相同的字節碼。
int.class和Integer.class不是同一份字節碼,Integer.TYPE,TYPE代表包裝類對應的基本類的字節碼 int.
importjava.util.Arrays;
/*
*從這個例子看出即便字節碼相同但是對象也不一定相同,根本不是一回事
*
*/
publicclassTestReflect{
publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{
int[]a=newint[3];
int[]b=newint[]{4,5,5};//直接賦值后不可以指定長度,否則CE
int[][]c=newint[3][2];
String[]d=newString[]{"jjj","kkkk"};
System.out.println(a==b);//false
System.out.println(a.getClass()==b.getClass());//true
//System.out.println(a.getClass()==d.getClass());//比較字節碼a和cd也沒法比
System.out.println(a.getClass());//輸出class[I
System.out.println(a.getClass().getName());//輸出[I,中括號表示數組,I表示整數
System.out.println(a.getClass().getSuperclass());//輸出classjava.lang.Object
System.out.println(d.getClass().getSuperclass());//輸出classjava.lang.Object
//由于父類都是Object,下面都是可以的
Objectobj1=a;//不可是Object[]
Objectobj2=b;
Object[]obj3=c;//基本類型的一位數組只可以當做Object,非得還可以當做Object[]
Objectobj4=d;
//注意asList處理int[]和String[]的區別
System.out.println(Arrays.asList(b));//1.4沒有可變參數,使用的是數組,[[I@1bc4459]
System.out.println(Arrays.asList(d));//[jjj,kkkk]
}
}
六.結束語
以上就是反射機制的簡單的使用,顯然學過spring的朋友一定明白了,為什么可以通過配置文件就可以讓我們獲得指定的方法和變量,在我們創建對象的時候都是通過傳進string實現的,就好像你需要什么,我們去為你生產,還有我們一直在用Object,這就說明java語言的動態特性,依賴性大大的降低了。
總結
以上是生活随笔為你收集整理的java反射 虚拟机优化_面试官问我:Java反射是什么?我回答竟然不上来......的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ajax jsp模糊查询源码,ajax模
- 下一篇: 选中内容_Excel – 选中的单元格自