天天看點

反射學習筆記(二) - - 暴力反射 - -

src==> 源檔案存放位置
bin==> bean 檔案

_____________________________________________________________
=============================================================
++++++++++++++++++++++++  反射  筆記  +++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_____________________________________________________________
-->
                        面向對象: 萬物皆對象
    --> java類 : 類的組成部分
        ( 1 )每個類都有一個package
        ( 2 )每個類有一個類名
        ( 3 )構造方法
        ( 4 )屬性
        ( 5 )普通方法
             .......                    靜态方法 未包括
=============================================================
       --->     反射的根基 : java 開發者為我們提供了一個類來描述 java  檔案 ,這個類為Class
                同時,Class 類型對應的對象可以代表某一個某一個類的位元組碼檔案
                public class  Class  {
                        ......
                     }
                           對象代表位元組碼檔案
                           位元組碼檔案類型  ===>    . class
                          ==================================
    ---> 如何擷取某一類的位元組碼檔案?   ====>     擷取一個類的對象
    --------------------------------------------------------
    [ 注: 反射不能 new 出來  , 沒有 new ]
    三種方式擷取:
        --> 通過類名.class
        --> 類名.forName("某個類的全路徑")
        --> 對象名 .getClass( )                                    [ - 點不能丢 - ]
    ---------------------------------------------------------
        @Test           //擷取User的位元組碼檔案
        public void ReflectionTest1() throws ClassNotFoundException {
            //通過類名擷取位元組碼檔案
            Class userClass = User.class;                   <----------   第一種
            //通過.forName擷取位元組碼檔案
            Class u = Class.forName("User");                <----------   第二種
            //通過.getClass 擷取
            User user = new User();
            Class get =  user.getClass();                   <----------   第三種
            //以上三者擷取的是同一個位元組碼檔案 , sout 輸出  true
            // 注意       第三種擷取的方式需要執行個體化對象,通過對象的.getClass方法擷取
            System.out.println(u==userClass);
            System.out.println(u==get);
        }
     ----------------------------------------------------------
     所有類的底層都是位元組碼===> 二進制檔案
     ----------------------------------------------------------
     * 通過反射建立對象
     * 所謂的反射,将一個類中的  各個成員   映射    成    相對應的   java類型
     *    ==================================================================
     *     各個成員: 包括 { 包 --> package, 構造器 ---> Contructor ,  屬性字段 ---> Field ,  普通方法 ----> Method }
     *    ==================================================================
     *
     *  spring 機制 :
     *        <bean id = " xx "  class = " com.xsh.User " ></bean>
     *  ====>  通過   Class.forName( " 類的全路徑 ")    擷取  位元組碼檔案
     *         以位元組碼檔案為紐帶,建立執行個體.
     *
     ---------------------------------------------------------
                 @Test
                public void ReflectionTest2() throws Exception {
                    // 1/擷取位元組碼檔案
                    Class  userClass = Class.forName("User");
                    //2/需要建立一個對象, ===>  建立對象一定需要調用構造方法  調用類中的無參構造方法來建立構造對象
                    Constructor[] constructors = userClass.getConstructors();
                    for (Constructor constructor : constructors ) {             ====>
                        System.out.println(constructor);                        ====> for循環列印是以構造方法
                    }                                                           ====>
                    //通過位元組碼擷取無參構造方法
                    Constructor constructor =userClass.getConstructor();
                    //通過無參構造方法,建立對象
                    User u = (User) constructor.newInstance();
                    System.out.println(u);      ===>   列印出對象: 證明通過映射成功建立對象
                    //通過位元組碼擷取有參構造方法
                    Constructor constructor1 = userClass.getConstructor(String.class,int.class);
                    User uu = (User) constructor1.newInstance("張三",21);        ===> 這裡是指派給通過映射建立的對象
                    System.out.println(uu);     ===>   列印出對象: 證明通過映射成功建立對象
                }
    ------------------------------------------------------------
    反射對象和傳統對象效率相比:  反射的效率比傳統方式低很多
    ----> 建立一百個對象速度相比,低至 10~ 20 倍   我自己測是這樣的 ,  總結就是低很多...量越大,效率越低
    ------------------------------------------------------------
==================================================================================================================
    public class User {
        private String name = "張三李四";           //姓名
        int age = 26;           //年齡
        protected float weight = 60.5F;         //體重
        public float height = 180.5F;       //身高

        構造方法略過....
        }
==================================================================================================================
    1 /  在不給出任何接口的情況下( toString 方法也不給出 )如何擷取到User類中私有屬性的值  ?   ====>  反射
                -------------------------------------------------------------------------
                     * ==================================================================
                     * 通過反射擷取某一個實體對象的屬性字段及其值
                     *          1/通過反射擷取public.protect,預設修飾符修飾的屬性字段和值
                     *          2/通過暴力反射擷取 私有屬性字段及其值   private 修飾的
                     * ==================================================================
                     *  反射裡将屬性封裝成了field類型 :
                     *          修飾符         資料類型      屬性名
                     *      getFields() ===>  隻能擷取public修飾的屬性
                     *      getDeclaredFields  ====>   擷取除了私有的之外的三種修飾符修飾的字段   jdk 8   擷取全部
                       =================================================================
                    @Test
                    public void test() throws Exception {
                        //建立一個對象
                        Class c = User.class;
                        User user = (User) c.getConstructor().newInstance();
                        //擷取user這個對象的屬性字段
                        Field[] fields = c.getDeclaredFields();
                        for (Field s : fields ) {                           [ 這裡僅僅是部分方法 僅供參考 ]
                            System.out.println(s);
                        }
                        //擷取指定字段的屬性             [ 預設=> 0  public=>1 protected =>4  private =>2 ]
                        Field field = c.getDeclaredField("weight");
                        System.out.println(field.getType());        //擷取字段類型
                        System.out.println(field.getModifiers());   //傳回修飾符的值
                        System.out.println(field.getName());    //擷取字段名字
                        System.out.println(field.getDeclaringClass().getTypeName());  //擷取屬性類路徑
                    }
                       =================================================================
                           @Test
                           public void test() throws Exception {
                               //建立一個對象
                               Class c = User.class;
                               User user = (User) c.getConstructor().newInstance();
                               //擷取user這個對象的屬性字段
                               Field[] fields = c.getDeclaredFields();
                               for (Field s : fields ) {
                                //   System.out.println(s);
                               }
                               //擷取指定字段的屬性
                               Field field = c.getDeclaredField("name");
                               System.out.println(field.getType());        //擷取字段類型
                               System.out.println(field.getModifiers());   //傳回修飾符的值
                               System.out.println(field.getName());    //擷取字段名字
                               System.out.println(field.getDeclaringClass().getTypeName());  //擷取屬性類路徑
                               //暴力反射  ==>  擷取所有屬性的值   如果某個屬性被私有化,想要擷取就需要通過暴力反射
                               field.setAccessible(true);
                               Object o = field.get(user);
                               System.out.println(o);
                               //修改某字段值
                               field.set(user,"牛二劉三");
                               System.out.println(user);           //修改成功
                           }
                       =================================================================
========================================================================================================================
         [ 預設=> 0  public=>1 protected =>4  private =>2 ]   為什麼沒有3?
            1Byte  =    8  bit
            位元組          位               計算機底層 二進制    一個位元組 ==>  8 位
                                            計算機傳輸的時候每次最少是一個八位的位元組
    1==> 高電壓
    0==> 低電壓          00000000      0
                         00000010      1*2^0 = 1
                         00000100      1*2^1 = 2
                         00001000      1*2^2 = 4
          這樣的傳輸效率最高 ===   >   是以沒有 3  !
========================================================================================================================