反射

 

 

 

  1. Junit介紹 (***** 瞭解 *****)

Java Unit Java單元測試框架

 

Junit是Java語言編寫單元測試框架,最直觀的理解,就是取代java類中的main方法。Junit屬於第三方工具,一般情況下需要導入jar包,而多數Java開發環境都集成了Junit。

 

Junit的使用

創建“MyJunit”java項目,並創建“cn.itcast.junit”包

  1. 編寫測試類,簡單理解Junit可以用於取代java的main方法
  2. 在測試類方法上添加註解 @Test
  3. @Test修飾的方法要求:public void 方法名() {…} ,方法名自定義建議test開頭,沒有參數。

  1. 添加Eclipse中集成的Junit庫,鼠標點擊“@Test”,使用快捷鍵“ctrl + 1”,點擊“Add Junit …”

結果

      

  1. 使用:選中方法右鍵,執行當前方法;選中類名右鍵,執行類中所有方法(方法必須標記@Test)

  1. 常用註解

@Test,用於修飾需要執行的方法

@Before,測試方法前執行的方法

@After,測試方法後執行的方法

  1. import org.junit.After;
  2. import org.junit.Before;
  3. import org.junit.Test;
  4.  
  5. public class JunitDemo {
  6.        @Before
  7.        public void test_Before() {
  8.               System.out.println("Before 註解的方法 ...");
  9.        }
  10.       
  11.        @After
  12.        public void test_After() {
  13.               System.out.println("After 註解的方法 ...");
  14.        }
  15.       
  16.        @Test
  17.        public void test_01() {
  18.               System.out.println("測試 test01 方法 ...");
  19.        }
  20.       
  21.        @Test
  22.        public void test_02() {
  23.               System.out.println("測試 test02 方法 ...");
  24.        }
  25.       
  26.        @Test
  27.        public void test_03() {
  28.               System.out.println("測試 test03 方法 ...");
  29.        }
  30. }

 

  1. 常見使用錯誤,如果沒有添加“@Test”,使用“Junit Test”進行運行,將拋異常

 

 

  1. 類加載器 (***** 瞭解 *****)

 

類加載器:類加載器是負責加載類的對象。將class文件(硬盤)加載到內存生成Class對象。

所有的類加載器 都是  java.lang.ClassLoader 的子類

 

類的加載說明 :

類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個 java.lang.Class對象,用來封裝類在方法區內的數據結構.

 

 

注意 : 只有Java虛擬機才能創建class類的對象.

 

重點 : 類加載的最終產品是位於堆區中的 Class對象.

Class對象封裝了類在方法區內的數據結構 ,並且向Java程序員提供了訪問方法區內的數據結構的接口,這些接口都定義在了 `反射` 包中.

 

 

  1. 引導類加載器
  1. package cn.itcast.classloader;
  2.  
  3. import java.util.Properties;
  4.  
  5. import org.junit.Test;
  6.  
  7. public class ClassLoaderDemo01 {
  8.       
  9.        @Test
  10.        public void demo01() {
  11.               // 確定引導類加載器類型: null
  12.               ClassLoader cl = String.class.getClassLoader();
  13.               System.out.println(cl);
  14.        }
  15. }

 

2. 擴展類加載器

 

  1. package cn.itcast.classloader;
  2.  
  3. import org.junit.Test;
  4.  
  5. import sun.net.spi.nameservice.dns.DNSNameService;
  6.  
  7. public class ClassLoaderDemo02 {
  8.       
  9.        @Test
  10.        public void demo01() {
  11.               // 添加項目訪問規則 -> Properties -> BuildPath -> Library
  12.               // -> JRE System -> Access rules -> Edit -> add -> sun/**
  13.              
  14.               // 確定擴展類加載器類型: Launcher$ExtClassLoader
  15.               ClassLoader cl = DNSNameService.class.getClassLoader();
  16.               System.out.println(cl);
  17.        }
  18. }

 

3. 應用類加載器

 

  1. package cn.itcast.classloader;
  2.  
  3. import org.junit.Test;
  4.  
  5. import sun.net.spi.nameservice.dns.DNSNameService;
  6.  
  7. public class ClassLoaderDemo03 {
  8.       
  9.        @Test
  10.        public void demo03() {
  11.               // 確定應用類加載器類型: Launcher$AppClassLoader
  12.               ClassLoader cl = ClassLoaderDemo03.class.getClassLoader();
  13.               System.out.println(cl);
  14.        }
  15. }

 

4. 類加載器之間的關係

 

  1. package cn.itcast.classloader;
  2.  
  3. import org.junit.Test;
  4.  
  5. public class ClassLoaderDemo04 {
  6.        @Test
  7.        public void demo01() {
  8.               // 驗證三個類加載器之間的關係:
  9.               ClassLoader cl1 = ClassLoaderDemo04.class.getClassLoader();
  10.               System.out.println(cl1);    // AppClassLoader
  11.              
  12.               ClassLoader cl2 = cl1.getParent();
  13.               System.out.println(cl2);    // ExtClassLoader
  14.              
  15.               ClassLoader cl3 = cl2.getParent();
  16.               System.out.println(cl3);    // null
  17.        }
  18. }

 

 

 

 

  1. 反射詳解 (***** 瞭解 *****)

 

反射概述 :

Java反射機制是在運行狀態中,對指定的類,任意的方法或任意的字段進行操作,這種動態獲取的信息以及動態調用對象方法的功能稱爲java語言的反射機制。

簡而言之,反射就是:在運行時通過代碼操作類

想要操作類,就必須先獲得該類的字節碼對象Class 對象。通過Class提供的方法對類進行進一步的解剖,從而實現各種操作。

在進行具體操作之前,大家需要先掌握類各個組成的專業描述

Class類

Constructor 構造方法

Method 方法

Field 字段 / 屬性

instance 實例 / 實例對象

invoke 調用, 執行

 

 

 

  1. 三種獲取Class對象的方式

 

  1. /*
  2.  * 不同的應用場景, 需要使用不同的方式獲取 Class 對象.
  3.  *
  4.  * 1. 通過字符串 (全限定名) 獲得.  `包名 + 類名`
  5.  *     格式 : Class cls = Class.forName("字符串");
  6.  *     場景 : 開發中, 從配置文件中獲取 `全限定類名`, 並通過反射進行所有操作.
  7.  *
  8.  * 2. 通過 Java 類型獲取.
  9.  *     格式 : Class cls = 類名.class;
  10.  *     場景 : 確定方法形參列表時, 需要通過類型獲得.
  11.  *            例如 : public void init(String s, int i) {}
  12.  *            類型對應的Class參數列表爲: init(String.class, int.class);
  13.  *
  14.  * 3. 通過實例對象獲得.
  15.  *     格式 : Class cls = obj.getClass();
  16.  *     場景 : 方法內部通過變量名(實例對象名)獲得.
  17.  *            例如 : public void init(Object obj) {
  18.  *                         obj.getClass();
  19.  *            }
  20.  */

 

 

  1. public class ClassDemo {
  2.        @Test
  3.        public void demo01() throws ClassNotFoundException {
  4.               Class<?> cls = Class.forName("cn.itcast.practice.ClassDemo");
  5.               System.out.println(cls);
  6.        }
  7.       
  8.        @Test
  9.        public void demo02() {
  10.               Class<?> cls = String.class;
  11.               System.out.println(cls);
  12.        }
  13.       
  14.        @Test
  15.        public void demo03() {
  16.               Object obj = new String();
  17.               Class<?> cls = obj.getClass();
  18.               System.out.println(cls);
  19.        }
  20. }

 

 

 

  1. 供一個 Student類, 用於之後的反射操作

 

  1. package cn.itcast.reflect;
  2.  
  3. // 提供 Student , 用於之後的反射操作.
  4. public class Student {
  5.  
  6.        public static void main(String[] args) {
  7.               System.out.println("Student 類的 main 方法被調用... ");
  8.               System.out.println("args[0]=" + args[0] + ", args[1]=" + args[1]);
  9.        }
  10.        // 屬性
  11.        private String name;
  12.        private int age;
  13.       
  14.        public String description; 
  15.        // 無參構造方法
  16.        public Student() {
  17.               System.out.println("無參構造方法被調用...");
  18.        }
  19.  
  20.        public Student(String name, int age) {
  21.               System.out.println("  String name, int age 參數的構造方法被調用...");
  22.               this.name = name;
  23.               this.age = age;
  24.        }
  25.  
  26.        // 私有構造方法
  27.        private Student(String name, int age, String description) {
  28.               System.out.println("私有構造方法被調用...");
  29.               this.name = name;
  30.               this.age = age;
  31.               this.description = description;
  32.        }
  33.        // 私有方法
  34.        private void show(int num) {
  35.               System.out.println("私有方法: " + num);
  36.        }
  37.       
  38.        public String getDescription() {
  39.               return description;
  40.        }
  41.        public void setDescription(String description) {
  42.               this.description = description;
  43.        }
  44.        public String getName() {
  45.               return name;
  46.        }
  47.        public void setName(String name) {
  48.               this.name = name;
  49.        }
  50.        public int getAge() {
  51.               return age;
  52.        }
  53.        public void setAge(int age) {
  54.               this.age = age;
  55.        }
  56.       
  57.        @Override
  58.        public String toString() {
  59.               return "Student [name=" + name + ", age=" + age + ", description=" + description + "]";
  60.        }
  61. }

 

 

 

  1. 使用反射調用構造方法創建對象

 

 

  1. package cn.itcast.reflect;
  2.  
  3. import java.lang.reflect.Constructor;
  4.  
  5. import org.junit.Test;
  6.  
  7. public class ConstructorDemo {
  8.        // 普通方式 : 直接 new 對象.
  9.        @Test
  10.        public void demo01() {
  11.               // 觸發 `無參構造方法`
  12.               // Student stu = new Student();
  13.              
  14.               // 觸發 `有參構造方法`
  15.               // Student stu = new Student("Jack", 30);
  16.              
  17.               // 觸發 `私有構造方法` 錯誤!
  18.               // Student stu = new Student("Jack", 30, "學霸");
  19.               // System.out.println(stu);
  20.        }
  21.       
  22.        // 通過反射調用無參構造方法獲得實例對象
  23.        @Test
  24.        public void demo02() throws Exception {
  25.               // 1. 獲取Class對象
  26.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  27.               // 2. 通過cls直接創建對象, 相當於: new Student();
  28.               Object obj = cls.newInstance();
  29.        }
  30.       
  31.        // 通過反射調用有參構造方法, 獲得實例對象
  32.        @Test
  33.        public void demo03() throws Exception {
  34.               // 1. 獲取Class對象
  35.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  36.               // 2. 獲得構造方法, 相當於: Student(String name, int age);
  37.               // getConstructor(Class<?>... parameterTypes)
  38.               Constructor<?> cons = cls.getConstructor(new Class[]{String.class, int.class});
  39.               // 3. 調用構造方法, 獲得實例對象, 相當於: new Student();
  40.               // newInstance(Object ... initargs)
  41.               Object obj = cons.newInstance(new Object[]{"Jack", 30});
  42.               System.out.println(obj);
  43.        }
  44.       
  45.        // 通過私有構造方法獲得實例對象
  46.        @Test
  47.        public void demo04() throws Exception {
  48.               // 1. 獲取 Class 對象
  49.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  50.               // 2. 獲取構造方法
  51.               Constructor<?> cons = cls.getDeclaredConstructor(new Class[]{String.class, int.class, String.class});
  52.               // 暴力訪問 (默認不允許)
  53.               cons.setAccessible(true);
  54.               // 3. 調用構造方法, 獲得實例對象
  55.               Object obj = cons.newInstance(new Object[]{"Jack", 30, "學霸"});
  56.               System.out.println(obj);
  57.        }
  58. }

 

 

 

 

 

 

  1. 使用反射執行方法

 

 

  1. package cn.itcast.reflect;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. import org.junit.Test;
  6.  
  7. public class MethodDemo {
  8.        @Test
  9.        public void demo01() {
  10.               Student stu = new Student();
  11.               stu.setName("Jack");
  12.               stu.setAge(30);
  13.               System.out.println(stu);
  14.              
  15.               String name = stu.getName();
  16.               int age = stu.getAge();
  17.               System.out.println("name: " + name + ", age: " + age);
  18.              
  19.               // stu.show(); 錯誤! 無法調用私有方法.
  20.        }
  21.       
  22.        @Test
  23.        public void demo02() throws Exception {
  24.               // 1. 獲得實例
  25.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  26.               Object obj = cls.newInstance();
  27.              
  28.               // 2.1 獲取 setName(String name) 方法
  29.               Method setNameMethod = cls.getMethod("setName", String.class);
  30.               // 2.2 調用方法, 傳遞實際參數
  31.               setNameMethod.invoke(obj, "Jack");
  32.               // 2.3 獲取 setAge(int age) 方法
  33.               Method setAgeMethod = cls.getMethod("setAge", int.class);
  34.               // 2.4 調用
  35.               setAgeMethod.invoke(obj, 30);
  36.              
  37.               System.out.println(obj);
  38.              
  39. //            Method getNameMethod = cls.getMethod("getName", null);
  40. //            Object name = getNameMethod.invoke(obj, null);
  41. //            Method getAgeMethod = cls.getMethod("getAge", null);
  42. //            Object age = getAgeMethod.invoke(obj, null);
  43.               Method getNameMethod = cls.getMethod("getName");
  44.               Object name = getNameMethod.invoke(obj);
  45.               Method getAgeMethod = cls.getMethod("getAge");
  46.               Object age = getAgeMethod.invoke(obj);
  47.               System.out.println("name: " + name + ", age: " + age);
  48.        }
  49.       
  50.        @Test
  51.        public void demo03() throws Exception {
  52.               // 1. 獲得實例
  53.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  54.               Object obj = cls.newInstance();
  55.              
  56.               // 2. 獲取方法並調用執行
  57.               Method showMethod = cls.getDeclaredMethod("show", int.class);
  58.               showMethod.setAccessible(true); // 暴力訪問
  59.               Object result = showMethod.invoke(obj, 100);
  60.              
  61.               // 如果方法沒有返回結果, 那麼結果爲 null
  62.               System.out.println(result);
  63.        }
  64.       
  65.        // 執行靜態方法 main, 無需獲得實例, 但是必須要獲得 Class 對象
  66.        @Test
  67.        public void demo04() throws Exception {
  68.               // 1. 獲得 Class 對象
  69.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  70.              
  71.               // 2. 獲得 main 方法
  72.               Method mainMethod = cls.getMethod("main", new Class[]{String[].class});
  73.               // 特點注意 : 數組類型的參數書寫格式
  74.               mainMethod.invoke(null, new Object[]{new String[]{"Hello", "World"}});
  75.        }
  76. }

 

可變參數的方法調用方式 :

 

 

 

  1. 使用反射獲取屬性

 

 

  1. package cn.itcast.reflect;
  2.  
  3. import java.lang.reflect.Field;
  4.  
  5. import org.junit.Test;
  6.  
  7. public class FieldDemo {
  8.        @Test
  9.        public void demo01() {
  10.               Student stu = new Student();
  11.               stu.description = "描述信息";
  12.               System.out.println(stu);
  13.        }
  14.       
  15.        @Test
  16.        public void demo02() throws Exception {
  17.               // 1. 獲得實例
  18.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  19.               Object obj = cls.newInstance();
  20.              
  21.               // 2. 獲得屬性
  22.               Field descField = cls.getField("description");
  23.               descField.set(obj, "描述信息: 學霸");
  24.              
  25.               System.out.println(obj);
  26.        }
  27.       
  28.        @Test
  29.        public void demo03() throws Exception {
  30.               // 1. 獲得實例
  31.               Class<?> cls = Class.forName("cn.itcast.reflect.Student");
  32.               Object obj = cls.newInstance();
  33.              
  34.               // 2. 獲得屬性並設置數值
  35.               Field nameField = cls.getDeclaredField("name");
  36.               nameField.setAccessible(true);
  37.               nameField.set(obj, "Jack");
  38.               Field ageField = cls.getDeclaredField("age");
  39.               ageField.setAccessible(true);
  40.               ageField.set(obj, 30);
  41.              
  42.               System.out.println(obj);
  43.              
  44.               // 查看屬性
  45.               Object name = nameField.get(obj);
  46.               Object age = ageField.get(obj);
  47.               System.out.println("name: " + name + ", age: " + age);
  48.        }
  49. }

 

 

 

 

 

 

 

  1. 反射綜合案例 – 舉辦晚會 (***** 練習 *****)

 

 

 

 

 

 

 

 

 

party.properties

 

  1. #singable=cn.itcast.classloader.LiuDeHua
  2. #dancable=cn.itcast.classloader.GirlsTeam
  3. #performable=cn.itcast.classloader.LiuQian
  4.  
  5. singable=cn.itcast.classloader.ZhangXueYou
  6. dancable=cn.itcast.classloader.GirlsGeneration
  7. performable=cn.itcast.classloader.ZhaoBenShan

 

Dancable

 

  1. package cn.itcast.classloader;
  2.  
  3. public interface Dancable {
  4.        void dance();
  5. }

 

Singable

 

  1. package cn.itcast.classloader;
  2.  
  3. public interface Singable {
  4.        void sing();
  5. }

 

Performable

 

  1. package cn.itcast.classloader;
  2.  
  3. public interface Performable {
  4.        void perform();
  5. }

 

PartyFactory

 

  1. package cn.itcast.classloader;
  2.  
  3. import java.io.FileReader;
  4. import java.io.IOException;
  5. import java.util.Properties;
  6.  
  7. public class PartyFactory {
  8.       
  9.        private static Properties prop = new Properties();
  10.       
  11.        static {
  12.               try {
  13.                     prop.load(new FileReader("party.properties"));
  14.               } catch (IOException e) {
  15.                     e.printStackTrace();
  16.               }
  17.        }
  18.       
  19.        public static Singable getSingable() throws Exception {
  20.               String className = prop.getProperty("singable");
  21.               Class<?> cls = Class.forName(className);
  22.               return (Singable) cls.newInstance();
  23.        }
  24.       
  25.        public static Dancable getDanceble() throws Exception {
  26.               String className = prop.getProperty("dancable");
  27.               Class<?> cls = Class.forName(className);
  28.               return (Dancable) cls.newInstance();
  29.        }
  30.       
  31.        public static Performable getPerformable() throws Exception {
  32.               String className = prop.getProperty("performable");
  33.               Class<?> cls = Class.forName(className);
  34.               return (Performable) cls.newInstance();
  35.        }
  36. }

 

EveningParty

 

  1. package cn.itcast.classloader;
  2.  
  3. public class EveningPartyDemo {
  4.        public static void main(String[] args) throws Exception {
  5.              
  6.               System.out.println("晚會開始了...");
  7.              
  8.               // 歌曲
  9.               Singable singable = PartyFactory.getSingable();
  10.               singable.sing();
  11.              
  12.               // 舞蹈
  13.               Dancable danceble = PartyFactory.getDanceble();
  14.               danceble.dance();
  15.              
  16.               // 表演
  17.               Performable performable = PartyFactory.getPerformable();
  18.               performable.perform();
  19.              
  20.               System.out.println("難忘今宵!");
  21.        }
  22. }

 

 

ZhangXueYou

 

  1. package cn.itcast.classloader;
  2.  
  3. public class ZhangXueYou implements Singable {
  4.        @Override
  5.        public void sing() {
  6.               System.out.println("張學友 演唱 `一路上有你`!");
  7.        }
  8. }

 

GirlsGeneration

 

  1. package cn.itcast.classloader;
  2.  
  3. public class GirlsGeneration implements Dancable {
  4.        @Override
  5.        public void dance() {
  6.               System.out.println("少女時代 Gee Gee Gee!");
  7.        }
  8. }

 

ZhaoBenShan

 

  1. package cn.itcast.classloader;
  2.  
  3. public class ZhaoBenShan implements Performable {
  4.        @Override
  5.        public void perform() {
  6.               System.out.println("趙本山 表演 `賣柺`!");
  7.        }
  8. }

 

LiuDeHua

 

  1. package cn.itcast.classloader;
  2.  
  3. public class LiuDeHua implements Singable {
  4.        @Override
  5.        public void sing() {
  6.               System.out.println("劉德華 演唱 `愛你一萬年`!");
  7.        }
  8. }

 

GirlsTeam

 

  1. package cn.itcast.classloader;
  2.  
  3. public class GirlsTeam implements Dancable {
  4.        @Override
  5.        public void dance() {
  6.               System.out.println("女子團隊 `性感廣場舞`!");
  7.        }
  8. }

 

LiuQian

 

  1. package cn.itcast.classloader;
  2.  
  3. public class LiuQian implements Performable {
  4.        @Override
  5.        public void perform() {
  6.               System.out.println("劉謙 表演 `大變活人`!");
  7.        }
  8. }

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章