chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

您好,歡迎來電子發(fā)燒友網(wǎng)! ,新用戶?[免費注冊]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>java源碼下載>

實例分析講解java中的反射機制

大小:0.2 MB 人氣: 2017-09-27 需要積分:0

  動態(tài)語言

  動態(tài)語言,是指程序在運行時可以改變其結(jié)構(gòu):新的函數(shù)可以被引進,已有的函數(shù)可以被刪除等在結(jié)構(gòu)上的變化。比如眾所周知的ECMA(Java)便是一個動態(tài)語言。除此之外如Ruby、Python等也都屬于動態(tài)語言,而C、C++等語言則不屬于動態(tài)語言。(引自: 百度百科)

  var execString = “alert(Math.floor(Math.random()*10));”; eval( execString);Class 反射機制

  指的是可以于運行時加載,探知和使用編譯期間完全未知的類。

  程序在運行狀態(tài)中, 可以動態(tài)加載一個只有名稱的類, 對于任意一個已經(jīng)加載的類,都能夠知道這個類的所有屬性和方法; 對于任意一個對象,都能調(diào)用他的任意一個方法和屬性;

  加載完類之后, 在堆內(nèi)存中會產(chǎn)生一個Class

  類型的對象(一個類只有一個Class對象), 這個對象包含了完整的類的結(jié)構(gòu)信息,而且這個Class對象就像一面鏡子,透過這個鏡子看到類的結(jié)構(gòu),所以被稱之為:反射。

  Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions(維度)。 The primitive Java types (boolean, byte, char, short, int, long, float, anddouble), and the keyword void are also represented as Class objects.

  - 每個類被加載進入內(nèi)存之后,系統(tǒng)就會為該類生成一個對應(yīng)的java.lang.Class

  對象,通過該Class

  對象就可以訪問到JVM中的這個類。

  Class對象的獲取

  - 對象的getClass()方法;

  - 類的.class(最安全/性能最好)屬性;

  - 運用Class.forName(String className)動態(tài)加載類,className需要是類的全限定名(最常用)。

  從Class中獲取信息

  Class類提供了大量的實例方法來獲取該Class對象所對應(yīng)的詳細信息,Class類大致包含如下方法,其中每個方法都包含多個重載版本,因此我們只是做簡單的介紹,詳細請參考JDK文檔

  獲取類內(nèi)信息

  實例分析講解java中的反射機制

  一些判斷類本身信息的方法

  實例分析講解java中的反射機制

  使用反射生成并操作對象:

  Method Constructor Field這些類都實現(xiàn)了java.lang.reflect.Member接口,程序可以通過Method對象來執(zhí)行相應(yīng)的方法,通過Constructor對象來調(diào)用對應(yīng)的構(gòu)造器創(chuàng)建實例,通過Filed對象直接訪問和修改對象的成員變量值。

  創(chuàng)建對象

  通過反射來生成對象的方式有兩種:

  - 使用Class對象的newInstance()方法來創(chuàng)建該Class對象對應(yīng)類的實例(這種方式要求該Class對象的對應(yīng)類有默認構(gòu)造器)。

  - 先使用Class對象獲取指定的Constructor對象, 再調(diào)用Constructor對象的newInstance()方法來創(chuàng)建該Class對象對應(yīng)類的實例(通過這種方式可以選擇指定的構(gòu)造器來創(chuàng)建實例)。

  通過第一種方式來創(chuàng)建對象比較常見, 像Spring這種框架都需要根據(jù)配置文件(如applicationContext.xml)信息來創(chuàng)建Java對象,從配置文件中讀取的只是某個類的全限定名字符串,程序需要根據(jù)該字符串來創(chuàng)建對應(yīng)的實例,就必須使用默認的構(gòu)造器來反射對象。下面我們就模擬Spring實現(xiàn)一個簡單的對象池, 該對象池會根據(jù)文件讀取key-value對, 然后創(chuàng)建這些對象, 并放入Map中。

  配置文件

  { “ objects”: [ { “id”: “id1”, “class”: “com.fq.domain.User”}, { “id”: “id2”, “class”:“com.fq.domain.Bean”} ] }

  ObjectPool

  /** * Created by jifang on 15/12/31. */publicclassObjectPool{privateMap《String, Object》 pool; privateObjectPool(Map《String, Object》 pool) { this.pool = pool; } privatestaticObjectgetInstance(String className) throwsClassNotFoundException, IllegalAccessException, InstantiationException { returnClass.forName(className).newInstance(); }privatestaticJSONArray getObjects(String config) throwsIOException { Reader reader =newInputStreamReader(ClassLoader.getSystemResourceAsStream(config));returnJSONObject.parseObject(CharStreams.toString(reader)).getJSONArray( “objects”); } // 根據(jù)指定的JSON配置文件來初始化對象池publicstaticObjectPool init(String config) {try{ JSONArray objects = getObjects(config); ObjectPool pool = newObjectPool(newHashMap《String, Object》()); if(objects != null&& objects.size() != 0) { for( inti = 0; i 《 objects.size(); ++i) { JSONObject object = objects.getJSONObject(i); if(object == null|| object.size() == 0) { continue; } String id = object.getString( “id”); String className = object.getString( “class”); pool.putObject(id, getInstance(className)); } } returnpool; }catch(IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { thrownewRuntimeException(e); } } publicObjectgetObject(String id) { returnpool.get(id); } publicvoidputObject(String id, Object object) { pool.put(id, object); } publicvoidclear() { pool.clear(); } }

  Client

  /** * Java學(xué)習交流QQ群:589809992 我們一起學(xué)Java! */publicclassClient{@Testpublicvoidclient() { ObjectPool pool = ObjectPool.init(“config.json”); User user = (User) pool.getObject( “id1”); System.out.println(user); Bean bean = (Bean) pool.getObject( “id2”); System.out.println(bean); } }

  User

  publicclass User { privateint id; privateStringname; privateStringpassword; publicint getId() { returnid; } publicvoidsetId( Integerid) { this .id =id; } publicStringgetName() { returnname; } publicvoidsetName( Stringname) { this .name =name; } publicStringgetPassword() {returnpassword; } publicvoidsetPassword( Stringpassword) { this .password =password; } @Override publicStringtoString() { return“User{”+“id=”+id +“, name=‘”+name +’/‘’ + “, password=‘” + password + ’/‘’ + ‘}’; } }

  Bean

  publicclass Bean { privateBoolean usefull; privateBigDecimal rate; privateStringname;publicBoolean getUsefull() { returnusefull; } publicvoidsetUsefull(Boolean usefull) { this.usefull =usefull; } publicBigDecimal getRate() { returnrate; } publicvoidsetRate(BigDecimal rate) { this .rate =rate; } publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this .name =name; } @Override publicStringtoString() {return“Bean{”+“usefull=”+usefull +“, rate=”+rate +“, name=‘”+name +’/‘’ + ‘} ’; } }

  注意: 需要在pom.xml中添加如下依賴:

  《dependency》《groupId》com.alibaba 《/groupId》《artifactId》fastjson 《/artifactId》《version》1.2.7 《/version》《/dependency》《dependency》《groupId》com.google.guava《/groupId》《artifactId》guava 《/artifactId》《version》18.0 《/version》《/dependency》

  調(diào)用方法

  當獲取到某個類對應(yīng)的Class對象之后, 就可以通過該Class對象getMethod來獲取一個Method數(shù)組或Method對象。每個Method對象對應(yīng)一個方法,在獲得Method對象之后,就可以通過調(diào)用invoke方法來調(diào)用該Method對象對應(yīng)的方法。

  @CallerSensitive public Object invoke(Object obj, Object.。。 args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 。。.}

  下面我們對上面的對象池加強:可以看到Client獲取到的對象的成員變量全都是默認值,既然我們已經(jīng)使用了JSON這么優(yōu)秀的工具,我們又學(xué)習了動態(tài)調(diào)用對象的方法,那么我們就通過配置文件來給對象設(shè)置值(在對象創(chuàng)建時), 新的配置文件形式如下:

  { “ objects”: [ { “id”: “id1”, “class”: “com.fq.domain.User”, “fields”: [ { “name”: “id”, “value”:101}, { “name”: “name”, “value”: “feiqing”}, { “name”: “password”, “value”:“ICy5YqxZB1uWSwcVLSNLcA==”} ] }, { “id”: “id2”, “class”: “com.fq.domain.Bean”, “fields”:[ { “name”: “usefull”, “value”: true}, { “name”: “rate”, “value”: 3.14}, { “name”: “name”, “value”: “bean-name”} ] }, { “id”: “id3”, “class”: “com.fq.domain.ComplexBean”, “fields”: [ { “name”: “name”, “value”: “complex-bean-name”}, { “name”: “refBean”, “ref”: “id2”} ] } ] }

  其中fields代表該Bean所包含的屬性, name為屬性名稱, value為屬性值(屬性類型為JSON支持的類型), ref代表引用一個對象(也就是屬性類型為Object,但是一定要引用一個已經(jīng)存在了的對象)

  /** *@authorjifang *@since15/12/31下午4:00 */publicclassObjectPool{privateMap《String, Object》 pool; privateObjectPool(Map《String, Object》 pool) { this.pool = pool; }privatestaticJSONArray getObjects(String config) throwsIOException { Reader reader =newInputStreamReader(ClassLoader.getSystemResourceAsStream(config));returnJSONObject.parseObject(CharStreams.toString(reader)).getJSONArray( “objects”); } privatestaticObject getInstance(String className, JSONArray fields)throwsClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { // 配置的ClassClass《?》 clazz = Class.forName(className); // 目標Class的實例對象Object targetObject = clazz.newInstance(); if(fields != null&& fields.size() != 0) { for( inti = 0; i 《 fields.size(); ++i) { JSONObject field = fields.getJSONObject(i); // 需要設(shè)置的成員變量名String fieldName = field.getString( “name”); // 需要設(shè)置的成員變量的值Object fieldValue; if(field.containsKey(“value”)) { fieldValue = field.get( “value”); } elseif(field.containsKey( “ref”)) { String refBeanId = field.getString( “ref”); fieldValue = OBJECTPOOL.getObject(refBeanId); }else{ thrownewRuntimeException( “neither value nor ref”); } String setterName = “set”+ fieldName.substring( 0, 1).toUpperCase() + fieldName.substring( 1); // 需要設(shè)置的成員變量的setter方法Method setterMethod = clazz.getMethod(setterName, fieldValue.getClass()); // 調(diào)用setter方法將值設(shè)置進去setterMethod.invoke(targetObject, fieldValue); } } returntargetObject; } privatestaticObjectPool OBJECTPOOL; // 創(chuàng)建一個對象池的實例(保證是多線程安全的)privatestaticvoidinitSingletonPool() { if(OBJECTPOOL ==null) { synchronized(ObjectPool.class) { if(OBJECTPOOL == null) { OBJECTPOOL =newObjectPool( newConcurrentHashMap《String, Object》()); } } } } // 根據(jù)指定的JSON配置文件來初始化對象池publicstaticObjectPool init(String config) { // 初始化poolinitSingletonPool(); try{ JSONArray objects = getObjects(config); for( inti = 0; objects != null&& i 《 objects.size(); ++i) { JSONObject object = objects.getJSONObject(i); if(object == null|| object.size() == 0) { continue; } String id = object.getString( “id”); String className = object.getString( “class”); // 初始化bean并放入池中OBJECTPOOL.putObject(id, getInstance(className, object.getJSONArray( “fields”))); }returnOBJECTPOOL; } catch(IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { thrownewRuntimeException(e); } } publicObjectgetObject(String id) { returnpool.get(id); } publicvoidputObject(String id, Object object) { pool.put(id, object); } publicvoidclear() { pool.clear(); } }

  Client

  /** * Java學(xué)習交流QQ群:589809992 我們一起學(xué)Java! */publicclassClient{@Testpublicvoidclient() { ObjectPool pool = ObjectPool.init(“config.json”); User user = (User) pool.getObject( “id1”); System.out.println(user); Bean bean = (Bean) pool.getObject( “id2”); System.out.println(bean); ComplexBean complexBean = (ComplexBean) pool.getObject( “id3”); System.out.println(complexBean); } }

  ComplexBean

  publicclass ComplexBean { privateStringname; privateBean refBean;publicStringgetName() { returnname; } publicvoidsetName( Stringname) { this .name=name; } publicBean getRefBean() { returnrefBean; } publicvoidsetRefBean(Bean refBean) { this .refBean =refBean; } @Override publicStringtoString() {return“ComplexBean{”+“name=‘”+name +’/‘’ + “, refBean=” + refBean + ‘} ’; } }

  Spring框架就是通過這種方式將成員變量值以及依賴對象等都放在配置文件中進行管理的,從而實現(xiàn)了較好地解耦(不過Spring是通過XML作為配置文件)。

  訪問成員變量

  通過Class對象的的getField()方法可以獲取該類所包含的全部或指定的成員變量Field,F(xiàn)iled提供了如下兩組方法來讀取和設(shè)置成員變量值。

  - getXxx(Object obj): 獲取obj對象的該成員變量的值, 此處的Xxx對應(yīng)8中基本類型,如果該成員變量的類型是引用類型, 則取消get后面的Xxx;

  - setXxx(Object obj, Xxx val): 將obj對象的該成員變量值設(shè)置成val值。此處的Xxx對應(yīng)8種基本類型, 如果該成員類型是引用類型, 則取消set后面的Xxx;

  注: getDeclaredXxx方法可以獲取所有的成員變量,無論private/public;

  /** *@authorjifang *@since16/1/2下午1:00. */publicclassClient{@Testpublicvoidclient()throwsNoSuchFieldException, IllegalAccessException { User user = newUser(); Field idFiled = User.class.getDeclaredField( “id”); setAccessible(idFiled); idFiled.setInt(user,46); Field nameFiled = User.class.getDeclaredField( “name”); setAccessible(nameFiled); nameFiled.set(user, “feiqing”); Field passwordField = User.class.getDeclaredField(“password”); setAccessible(passwordField); passwordField.set(user,“ICy5YqxZB1uWSwcVLSNLcA==”); System.out.println(user); }privatevoidsetAccessible(AccessibleObject object) { object.setAccessible( true); } }使用反射獲取泛型信息

  為了通過反射操作泛型以迎合實際開發(fā)的需要, Java新增了java.lang.reflect.ParameterizedType java.lang.reflect.GenericArrayTypejava.lang.reflect.TypeVariable java.lang.reflect.WildcardType幾種類型來代表不能歸一到Class類型但是又和原始類型同樣重要的類型。

  實例分析講解java中的反射機制

  其中, 我們可以使用ParameterizedType來獲取泛型信息。

  /** * Java學(xué)習交流QQ群:589809992 我們一起學(xué)Java! */publicclassClient{privateMap《String, Object》 objectMap; publicvoidtest(Map《String, User》 map, String string) { } publicMap《User, Bean》 test() { returnnull; } /** * 測試屬性類型 * *@throwsNoSuchFieldException */@TestpublicvoidtestFieldType()throwsNoSuchFieldException { Field field = Client.class.getDeclaredField( “objectMap”); Type gType = field.getGenericType(); // 打印type與generic type的區(qū)別System.out.println(field.getType()); System.out.println(gType); System.out.println(“**************”); if(gType instanceofParameterizedType) { ParameterizedType pType = (ParameterizedType) gType; Type[] types = pType.getActualTypeArguments(); for(Type type : types) { System.out.println(type.toString()); } } } /** * 測試參數(shù)類型 * *@throwsNoSuchMethodException */@TestpublicvoidtestParamType()throwsNoSuchMethodException { Method testMethod = Client.class.getMethod( “test”, Map.class, String.class); Type[] parameterTypes = testMethod.getGenericParameterTypes(); for(Type type : parameterTypes) { System.out.println( “type -》 ”+ type); if(type instanceofParameterizedType) { Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments(); for(Type actualType : actualTypes) { System.out.println( “/tactual type -》 ”+ actualType); } } } } /** * 測試返回值類型 * *@throwsNoSuchMethodException */@TestpublicvoidtestReturnType()throwsNoSuchMethodException { Method testMethod = Client.class.getMethod( “test”); Type returnType = testMethod.getGenericReturnType(); System.out.println( “return type -》 ”+ returnType); if(returnType instanceofParameterizedType) { Type[] actualTypes = ((ParameterizedType) returnType).getActualTypeArguments(); for(Type actualType : actualTypes) { System.out.println( “/tactual type -》 ”+ actualType); } } } }反射性能測試

  Method/Constructor/Field/Element都繼承了AccessibleObject,AccessibleObject類中有一個setAccessible方法:

  public void setAccessible(boolean flag) throws SecurityException { 。。.}

  該方法有兩個作用:

  啟用/禁用訪問安全檢查開關(guān):值為true,則指示反射的對象在使用時取消Java語言訪問檢查;值為false,則指示應(yīng)該實施Java語言的訪問檢查;

  可以禁止安全檢查, 提高反射的運行效率。

  /** *@authorjifang *@since15/12/31下午4:53. */ public classTestReflect{ @Before publicvoid testNoneReflect() { User user = newUser(); longstart = System.currentTimeMillis();for( longi = 0; i 《 Integer.MAX_VALUE; ++i) { user.getName(); } longcount = System.currentTimeMillis() - start; System.out.println( “沒有反射, 共消耗 《”+ count + “》 毫秒”); } @Test public void testNotAccess() throwsClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { User user = newUser(); Method method = Class.forName(“com.fq.domain.User”).getMethod( “getName”); longstart = System.currentTimeMillis();for( longi = 0; i 《 Integer.MAX_VALUE; ++i) { method.invoke(user, null); } longcount = System.currentTimeMillis() - start; System.out.println( “沒有訪問權(quán)限, 共消耗 《”+ count +“》 毫秒”); } @After public void testUseAccess() throwsClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { User user = newUser(); Method method = Class.forName(“com.fq.domain.User”).getMethod( “getName”); method.setAccessible( true); longstart = System.currentTimeMillis(); for( longi = 0; i 《 Integer.MAX_VALUE; ++i) { method.invoke(user, null); } longcount = System.currentTimeMillis() - start; System.out.println( “有訪問權(quán)限, 共消耗 《”+ count + “》 毫秒”); } }

  執(zhí)行上面程序,在我的機器上會有如下結(jié)果:

  機器配置信息如下:

  實例分析講解java中的反射機制

  可以看到使用反射會比直接調(diào)用慢3000毫秒,但是前提是該方法會執(zhí)行20E+次(而且服務(wù)器的性能也肯定比我的機器要高),因此在我們的實際開發(fā)中,其實是不用擔心反射機制帶來的性能消耗的,而且禁用訪問權(quán)限檢查,也會有性能的提升。

非常好我支持^.^

(0) 0%

不好我反對

(0) 0%

      發(fā)表評論

      用戶評論
      評價:好評中評差評

      發(fā)表評論,獲取積分! 請遵守相關(guān)規(guī)定!

      ?