成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java動(dòng)態(tài)性(2) - 之反射機(jī)制(Reflection)

妤鋒シ / 3373人閱讀

摘要:的動(dòng)態(tài)性反射機(jī)制動(dòng)態(tài)編譯動(dòng)態(tài)執(zhí)行代碼動(dòng)態(tài)字節(jié)碼操作動(dòng)態(tài)語言程序運(yùn)行時(shí)可以改變程序得結(jié)構(gòu)或變量類型典型語言等如下代碼不是動(dòng)態(tài)語言但有一定的動(dòng)態(tài)性我們可以利用反射機(jī)制字節(jié)碼操作獲得類似動(dòng)態(tài)語言的特性的動(dòng)態(tài)性讓編程的時(shí)候更加靈活反射機(jī)制反射機(jī)制指

1.Java的動(dòng)態(tài)性

反射機(jī)制

動(dòng)態(tài)編譯

動(dòng)態(tài)執(zhí)行JavaScript代碼

動(dòng)態(tài)字節(jié)碼操作

2.動(dòng)態(tài)語言
程序運(yùn)行時(shí),可以改變程序得結(jié)構(gòu)或變量類型.典型語言:

Python,Ruby,JavaScript等.

如下JavaScript代碼

function test(){
    var s = "var a=3;var b=5;alert(a+b);";
    eval(s);
}

C,C++,Java不是動(dòng)態(tài)語言,但Java有一定的動(dòng)態(tài)性,我們可以利用反射機(jī)制,字節(jié)碼操作獲得類似動(dòng)態(tài)語言的特性

Java的動(dòng)態(tài)性讓編程的時(shí)候更加靈活

3.反射機(jī)制

反射機(jī)制指的是可以在運(yùn)行期間加載一些知道名字的類
對于任意一個(gè)已加載的類,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能調(diào)用它的任意一個(gè)方法或?qū)傩?/p>

Class c = Class.forName("com.test.User");

類加載完之后,在堆內(nèi)存中會產(chǎn)生一個(gè)Class類的對象(一個(gè)類只有一個(gè)Class對象),這個(gè)對象包含了完整的類的結(jié)構(gòu)信息,我們可以通過這個(gè)對象看到類的結(jié)果

4.Class類介紹

java.lang.Class類十分特殊,用來表示java中類型(class/interface/enum/annotation/primitive type/void)本身

Class類的對象包含了某個(gè)被加載類的結(jié)構(gòu),一個(gè)被加載的類對應(yīng)一個(gè)Class對象
當(dāng)一個(gè)class被加載,或當(dāng)加載器(class loader)的defineClass()被JVM調(diào)用,JVM便會自動(dòng)產(chǎn)生一個(gè)Class對象

Class類是Reflection的根源

針對任何你想動(dòng)態(tài)加載,運(yùn)行的類,只有先獲得相應(yīng)的Class對象

User bean:

package com.lorinda.bean;

public class User {
    
    private int id;
    private int age;
    private String uname;
    
    public User(int id, int age, String uname) {
        super();
        this.id = id;
        this.age = age;
        this.uname = uname;
    }
    
    public User() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }
     
}

Demo01 測試各種類型對應(yīng)Class對象的獲取方式:

/**
 * 測試各種類型對應(yīng)Class對象的獲取方式
 * @author Matrix42
 *
 */
public class ReflectionDemo01 {

    public static void main(String[] args) {

        String path = "com.lorinda.bean.User";
        
        try {
            Class clazz = Class.forName(path);
            System.out.println(clazz);              //class com.lorinda.bean.User
            System.out.println(clazz.hashCode());   //366712642
            //同樣的類只會被加載一次
            Class clazz2 = Class.forName(path);
            System.out.println(clazz2.hashCode());  //366712642
            
            Class strClazz = String.class;  //類名.class
            
            Class strClazz2 = path.getClass();   //對象.getClass();
            
            System.out.println(strClazz==strClazz2);//true
            
            Class intClazz = int.class;
            
            int[] arr01 = new int[10];
            int[] arr02 = new int [30];
            
            int[][] arr03 = new int[30][3];
            
            //數(shù)組的Class對象只與類型和維度有關(guān)
            System.out.println(arr01.getClass()==arr02.getClass()); //true
            
            System.out.println(arr01.getClass().hashCode());        //1829164700
            System.out.println(arr03.getClass().hashCode());        //2018699554
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
5.Class類的對象如何獲取?

對于對象可以使用getClass()

使用Class.forName() (最常使用)

使用.class

6.反射機(jī)制的常見作用

動(dòng)態(tài)加載類,動(dòng)態(tài)獲取類的信息(屬性,方法,構(gòu)造器)

動(dòng)態(tài)構(gòu)造對象

動(dòng)態(tài)調(diào)用類和對象的任意方法,構(gòu)造器

動(dòng)態(tài)調(diào)用和處理屬性

獲取泛型信息

處理注解

Demo02 獲取方法,屬性,構(gòu)造器等的信息:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 獲取方法,屬性,構(gòu)造器等的信息
 * @author Matrix42
 *
 */
public class ReflectionDemo02 {

    public static void main(String[] args) {
       
        String path = "com.lorinda.bean.User";
        
        try {
            Class clazz = Class.forName(path);

            //獲取類的名字
            System.out.println(clazz.getName());//獲得包名+類名:com.lorinda.bean.User
            System.out.println(clazz.getSimpleName());//獲得類名:User
            
            //獲取屬性信息
            //Field[] fields = clazz.getFields();//只能獲取public的field
            Field[] fields = clazz.getDeclaredFields();//獲得所有的field
            Field field = clazz.getDeclaredField("uname");//根據(jù)名字獲取field
            
            for(Field temp:fields){
                System.out.println("屬性: "+temp);
            }
            
            //獲取方法
            Method[] methods = clazz.getDeclaredMethods();
            Method method01 = clazz.getDeclaredMethod("getUname", null);
            //如果方法有參數(shù),則必須傳遞參數(shù)類型對應(yīng)的Class對象
            Method method02 = clazz.getDeclaredMethod("setUname", String.class);
            
            for(Method m:methods){
                System.out.println("方法: "+m);
            }
            
            //獲得構(gòu)造器信息
            Constructor[] constructors = clazz.getDeclaredConstructors();
            //多帶帶獲取,無參
            Constructor c1 = clazz.getDeclaredConstructor(null);
            System.out.println("構(gòu)造器: "+c1);
            //多帶帶獲取,有參
            Constructor c2 = clazz.getDeclaredConstructor(int.class,int.class,String.class);
            System.out.println("構(gòu)造器: "+c2);
            for(Constructor c:constructors){
                System.out.println("構(gòu)造器: "+c);
            }   
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

Demo03 通過反射動(dòng)態(tài)操作構(gòu)造器,方法,屬性

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import com.lorinda.bean.User;

/**
 * 通過反射動(dòng)態(tài)操作構(gòu)造器,方法,屬性
 * @auther Matrix42
 */
public class ReflectionDemo03 {
  
    public static void main(String[] args) {
        
        String path = "com.lorinda.bean.User";
        
        try {
            Class clazz = Class.forName(path);
            
            //動(dòng)態(tài)操作構(gòu)造器
            User u = (User) clazz.newInstance();    //調(diào)用了User的無參構(gòu)造方法
            
            Constructor c = clazz.getConstructor(int.class,int.class,String.class);
            
            User u2 = c.newInstance(1000,20,"Matrix42");
            System.out.println(u2.getUname());
            
            //通過反射調(diào)用普通方法
            //好處:方法名,參數(shù)都可以是變量,可以從數(shù)據(jù)庫讀取
            User u3 = (User) clazz.newInstance();
            Method method = clazz.getDeclaredMethod("setUname", String.class);
            method.invoke(u3, "Matrix42");
            System.out.println(u3.getUname());
            
            //通過反射操作屬性
            User u4 = (User) clazz.newInstance();
            Field f = clazz.getDeclaredField("uname");
            f.setAccessible(true);
            f.set(u4, "24xirtaM");  
            //默認(rèn)會報(bào)錯(cuò),添加f.setAccessible(true);關(guān)閉安全檢查
            //can not access a member of class com.lorinda.bean.User with modifiers "private"
            System.out.println(u4.getUname());  //正常調(diào)用
            System.out.println(f.get(u4));      //通過反射調(diào)用  
            
        } catch (Exception e) {
            e.printStackTrace();
        } 
    
    }

}
7.反射機(jī)制性能問題
當(dāng)你獲得靈活性的時(shí)候也會犧牲你的性能

setAccessible

啟用和禁用安全檢查的開關(guān),值為true則表示反射的對象在使用時(shí)應(yīng)取消Java語言訪問檢查.值為fals則表示反射的對象應(yīng)該實(shí)施Java語言訪問檢查.并不是為true就能訪問,為false就不能訪問

禁止安全檢查,可以提高反射的運(yùn)行速度

可以考慮使用:cglib/javasssist字節(jié)碼操作

反射性能測試:

import java.lang.reflect.Method;
import com.lorinda.bean.User;

public class ReflectionDemo04 {
    
    public static void test01(){
        
        User user = new User();
        
        long startTime = System.currentTimeMillis();
        
        for(int i=0;i<1000000000L;i++){
            user.getUname();
        }
        
        long endTime = System.currentTimeMillis();
        
        //421ms
        System.out.println("普通方法調(diào)用,執(zhí)行10億次,耗時(shí):"+(endTime-startTime)+"ms");
       
    }
    
    public static void test02() throws Exception{
        
        User user = new User();
        Class clazz = user.getClass();
        Method m = clazz.getDeclaredMethod("getUname", null);
        
        long startTime = System.currentTimeMillis();
        
        for(int i=0;i<1000000000L;i++){
            m.invoke(user, null);
        }
        
        long endTime = System.currentTimeMillis();
        
        //1650ms
        System.out.println("反射動(dòng)態(tài)調(diào)用,執(zhí)行10億次,耗時(shí):"+(endTime-startTime)+"ms");
       
    }
    
    public static void test03() throws Exception{
        
        User user = new User();
        Class clazz = user.getClass();
        Method m = clazz.getDeclaredMethod("getUname", null);
        m.setAccessible(true);
        
        long startTime = System.currentTimeMillis();
        
        for(int i=0;i<1000000000L;i++){
            m.invoke(user, null);
        }
        
        long endTime = System.currentTimeMillis();
        
        //1153ms
        System.out.println("反射動(dòng)態(tài)調(diào)用,跳過安全檢查,執(zhí)行10億次,耗時(shí):"+(endTime-startTime)+"ms");
       
    }

    public static void main(String[] args) throws Exception {
        
        test01();
        test02();
        test03();
        
    }

}

可以看出在java8中使用安全檢查的反射耗時(shí)大約是普通調(diào)用的4倍,不使用安全檢查是普通調(diào)用的2.5倍

8.反射操作泛型(Generic)

Java采用泛型擦除機(jī)制來引入泛型.Java中泛型僅僅是給編譯器javac使用的,確保數(shù)據(jù)的安全性和免去強(qiáng)制類型轉(zhuǎn)換的麻煩.但是,一旦編譯完成,所有和泛型有關(guān)的類型全部擦除.

為了通過反射操作這些類型以迎合實(shí)際開發(fā)的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種類型來代表不能被歸一到Class類中的類型但是又和原始類型齊名的類型.

ParameterizedType:表示一種參數(shù)化類型,比如Collection

GenericArrayType:表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型

TypeVariable:是各種類型變量的公共父接口

WildcardType:表示一種通配符類型表達(dá)式,比如?,? extends Number,? super Integer [wildcard就是通配符的意思]

Demo05 通過反射讀取泛型

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import com.lorinda.bean.User;

/**
 * 通過反射讀取泛型
 * @author Matrix42
 *
 */
public class ReflectionDemo05 {
    
    public void test01(Map map,List list){
        System.out.println("ReflectionDemo05.test02");
    }
    
    public Maptest02(){
        System.out.println("ReflectionDemo05.test2");
        return null;
    }

    public static void main(String[] args) {
        
        try {
            
            //獲取指定方法參數(shù)泛型信息
            Method m = ReflectionDemo05.class.getMethod("test01", Map.class,List.class);
            Type[] t = m.getGenericParameterTypes();
            for(Type paramType:t){
                System.out.println("#"+paramType);
                if(paramType instanceof ParameterizedType){
                    Type[] genericTypes = ((ParameterizedType)paramType).getActualTypeArguments();
                    for(Type genericType:genericTypes){
                        System.out.println("泛型類型: "+genericType);
                    }
                }
            }
            /*
               #java.util.Map
                                            泛型類型: class java.lang.String
                                            泛型類型: class com.lorinda.bean.User
               #java.util.List
                                            泛型類型: class com.lorinda.bean.User
             */
            //獲得指定方法返回值泛型信息
            Method m2 = ReflectionDemo05.class.getMethod("test02", null);
            Type returnType = m2.getGenericReturnType();
            if(returnType instanceof ParameterizedType){
                Type[] genericTypes = ((ParameterizedType)returnType).getActualTypeArguments();
                for(Type genericType:genericTypes){
                    System.out.println("返回值,泛型類型: "+genericType);
                }
            }
            /*
                                       返回值,泛型類型: class java.lang.Integer
                                       返回值,泛型類型: class com.lorinda.bean.User
           */
               
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
9.反射操作注解

Student類:

package com.lorinda.bean;

import com.demo.util.MField;
import com.demo.util.MTable;

@MTable("tb_student")
public class MStudent {

    @MField(columnName="id",type="int",length=10)
    private int id;
    @MField(columnName="sname",type="varchar",length=10)
    private String studentName;
    @MField(columnName="age",type="int",length=3)
    private int age;
    
    public MStudent(int id, String studentName, int age) {
        super();
        this.id = id;
        this.studentName = studentName;
        this.age = age;
    }
    
    public MStudent() {
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getStudentName() {
        return studentName;
    }
    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
      
}

Table注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value={ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MTable {

    String value();
    
}

Field注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value={ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MField {

    String columnName();
    String type();
    int length();
    
}

Demo06 通過反射讀取注解

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class ReflectionDemo06 {

    public static void main(String[] args) {

        try {
            Class clazz = Class.forName("com.lorinda.bean.MStudent");
            
            //獲得類的所有有效注解
            Annotation[] annotations = clazz.getAnnotations();
            for(Annotation a:annotations){
                System.out.println(a);
            }
            
            //獲得類的指定注解
            MTable table = (MTable) clazz.getAnnotation(MTable.class);
            System.out.println(table.value());
            
            //獲得類的屬性的注解
            Field f = clazz.getDeclaredField("studentName");
            MField field = f.getAnnotation(MField.class);
            System.out.println(field.columnName()+"--"+field.type()+"--"+field.length());
            
            //可以根據(jù)獲得的表名,字段的信息,拼出DDL語句,然后使用JDBC執(zhí)行這個(gè)SQL,在數(shù)據(jù)庫中生成相關(guān)的表
            
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71949.html

相關(guān)文章

  • ReflectionJava反射機(jī)制的應(yīng)用場景

    近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對象屬性賦值,借此機(jī)會也了解了反射的一些具體用法和使用場景,分以下兩點(diǎn)對反射進(jìn)行分析: 反射的優(yōu)勢和劣勢 反射的應(yīng)用場景 反射的優(yōu)勢和劣勢 ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...

    浠ラ箍 評論0 收藏0
  • ReflectionJava反射機(jī)制基礎(chǔ)

    摘要:反射機(jī)制是什么反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對象的方法的功能稱為語言的反射機(jī)制反射機(jī)制能做什么反射機(jī)制主要提供了以下功 反射機(jī)制是什么 反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種...

    hizengzeng 評論0 收藏0
  • Java 反射(Reflection)

    摘要:效率運(yùn)行效率使用反射減低程序的運(yùn)行效率。開發(fā)效率由于反射運(yùn)用到各個(gè)框架中,大大加快了開發(fā)的效率。 反射的核心就是Class對象,每一個(gè)類被jvm加載都會有一個(gè)對應(yīng)的class對象,這個(gè)class對象包含了這個(gè)類的結(jié)構(gòu)信息,反射就是會通過反射api反復(fù)操作這個(gè)class對象(屬性,方法,注解,構(gòu)造器,泛型),但是反射會降低程序的運(yùn)行效率,比普通方法要慢30倍,通過setAccessble...

    shengguo 評論0 收藏0
  • 樂字節(jié)Java反射一:反射概念與獲取反射源頭class

    摘要:一反射機(jī)制概念程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言,如,是動(dòng)態(tài)語言顯然,,不是動(dòng)態(tài)語言,但是有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制。相關(guān)的為二獲取源頭重點(diǎn)打開權(quán)限所有類的對象其實(shí)都是的實(shí)例。 一、Java反射機(jī)制概念 程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言,如Python, Ruby是動(dòng)態(tài)語言;顯然C++,Java,C#不是動(dòng)態(tài)語言,但是JAVA有...

    caikeal 評論0 收藏0
  • 最最最常見的Java面試題總結(jié)——第二周

    摘要:與都繼承自類,在中也是使用字符數(shù)組保存字符串,,這兩種對象都是可變的。采用字節(jié)碼的好處語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時(shí)又保留了解釋型語言可移植的特點(diǎn)。 String和StringBuffer、StringBuilder的區(qū)別是什么?String為什么是不可變的? String和StringBuffer、StringBuilder的區(qū)別 可變性...

    yearsj 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<