XML中二進位制資料的處理方法
Java反射機制
目錄
- Java反射機制
- 概要
- 總結:
- ReflectTest01——獲取類的位元組碼檔案
- ReflectTest02——通過Class的newInstance()方法來例項化物件
- ReflectTest03——驗證反射機制的靈活性
- ReflectTest04——Class.forName()只是讓一個類的靜態程式碼塊執行,其它程式碼一律不執行
- AboutPath——怎麼獲取一個檔案的絕對路徑
- IoPropertiesTest——以流的形式返回讀取的檔案
- ResourceBundleTest——資源繫結器
- ReflectTest05——反射Student類獲得當中所有的Field
- ReflectTest06——通過反射機制,反編譯一個類的屬性Field
- ReflectTest07——通過反射機制設定和訪問一個java物件的屬性
- ArgsTest——可變長度引數
- ReflectTest08——反射Method
- ReflectTest09——反編譯一個類的方法
- ReflectTest10——通過反射機制怎麼呼叫一個物件的方法
- ReflectTest11——反編譯一個類的Constructor構造方法
- ReflectTest12——通過反射機制呼叫構造方法例項化java物件
- ReflectTest13——給你一個類,怎麼獲取這個類的父類,已經實現了哪些介面?
概要
概要 1、執行緒這塊還有那些內容呢?列舉一下 1.1、守護執行緒 java語言中執行緒分為兩大類: 一類是:使用者執行緒 一類是:守護執行緒(後臺執行緒) 其中具有代表性的就是:垃圾回收執行緒(守護執行緒)。 守護執行緒的特點: 一般守護執行緒是一個死迴圈,所有的使用者執行緒只要結束, 守護執行緒自動結束。 注意:主執行緒main方法是一個使用者執行緒。 守護執行緒用在什麼地方呢? 每天00:00的時候系統資料自動備份。 這個需要使用到定時器,並且我們可以將定時器設定為守護執行緒。 一直在那裡看著,沒到00:00的時候就備份一次。所有的使用者執行緒 如果結束了,守護執行緒自動退出,沒有必要進行資料備份了。 1.2、定時器 定時器的作用: 間隔特定的時間,執行特定的程式。 每週要進行銀行賬戶的總賬操作。 每天要進行資料的備份操作。 在實際的開發中,每隔多久執行一段特定的程式,這種需求是很常見的, 那麼在java中其實可以採用多種方式實現: 可以使用sleep方法,睡眠,設定睡眠時間,沒到這個時間點醒來,執行 任務。這種方式是最原始的定時器。(比較low) 在java的類庫中已經寫好了一個定時器:java.util.Timer,可以直接拿來用。 不過,這種方式在目前的開發中也很少用,因為現在有很多高階框架都是支援 定時任務的。 在實際的開發中,目前使用較多的是Spring框架中提供的SpringTask框架, 這個框架只要進行簡單的配置,就可以完成定時器的任務。 1.3、實現執行緒的第三種方式:實現Callable介面。(JDK8新特性。) 這種方式實現的執行緒可以獲取執行緒的返回值。 之前講解的那兩種方式是無法獲取執行緒返回值的,因為run方法返回void。 思考: 系統委派一個執行緒去執行一個任務,該執行緒執行完任務之後,可能 會有一個執行結果,我們怎麼能拿到這個執行結果呢? 使用第三種方式:實現Callable介面方式。 1.4、關於Object類中的wait和notify方法。(生產者和消費者模式!) 第一:wait和notify方法不是執行緒物件的方法,是java中任何一個java物件 都有的方法,因為這兩個方式是Object類中自帶的。 wait方法和notify方法不是通過執行緒物件呼叫, 不是這樣的:t.wait(),也不是這樣的:t.notify()..不對。 第二:wait()方法作用? Object o = new Object(); o.wait(); 表示: 讓正在o物件上活動的執行緒進入等待狀態,無期限等待, 直到被喚醒為止。 o.wait();方法的呼叫,會讓“當前執行緒(正在o物件上 活動的執行緒)”進入等待狀態。 第三:notify()方法作用? Object o = new Object(); o.notify(); 表示: 喚醒正在o物件上等待的執行緒。 還有一個notifyAll()方法: 這個方法是喚醒o物件上處於等待的所有執行緒。 2、反射機制(比較簡單,因為只要會查幫助文件,就可以了。) 2.1、反射機制有什麼用? 通過java語言中的反射機制可以操作位元組碼檔案。 優點類似於黑客。(可以讀和修改位元組碼檔案。) 通過反射機制可以操作程式碼片段。(class檔案。) 2.2、反射機制的相關類在哪個包下? java.lang.reflect.*; 2.3、反射機制相關的重要的類有哪些? java.lang.Class:代表整個位元組碼,代表一個型別,代表整個類。 java.lang.reflect.Method:代表位元組碼中的方法位元組碼。代表類中的方法。 java.lang.reflect.Constructor:代表位元組碼中的構造方法位元組碼。代表類中的構造方法 java.lang.reflect.Field:代表位元組碼中的屬性位元組碼。代表類中的成員變數(靜態變數+例項變數)。 java.lang.Class: public class User{ // Field int no; // Constructor public User(){ } public User(int no){ this.no = no; } // Method public void setNo(int no){ this.no = no; } public int getNo(){ return no; } } 3、關於JDK中自帶的類載入器:(聊一聊,不需要掌握,知道當然最好!) 3.1、什麼是類載入器? 專門負責載入類的命令/工具。 ClassLoader 3.2、JDK中自帶了3個類載入器 啟動類載入器:rt.jar 擴充套件類載入器:ext/*.jar 應用類載入器:classpath 3.3、假設有這樣一段程式碼: String s = "abc"; 程式碼在開始執行之前,會將所需要類全部載入到JVM當中。 通過類載入器載入,看到以上程式碼類載入器會找String.class 檔案,找到就載入,那麼是怎麼進行載入的呢? 首先通過“啟動類載入器”載入。 注意:啟動類載入器專門載入:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar rt.jar中都是JDK最核心的類庫。 如果通過“啟動類載入器”載入不到的時候, 會通過"擴充套件類載入器"載入。 注意:擴充套件類載入器專門載入:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar 如果“擴充套件類載入器”沒有載入到,那麼 會通過“應用類載入器”載入。 注意:應用類載入器專門載入:classpath中的類。 3.4、java中為了保證類載入的安全,使用了雙親委派機制。 優先從啟動類載入器中載入,這個稱為“父” “父”無法載入到,再從擴充套件類載入器中載入, 這個稱為“母”。雙親委派。如果都載入不到, 才會考慮從應用類載入器中載入。直到載入 到為止。
總結:
1、回顧反射機制 1.1、什麼是反射機制?反射機制有什麼用? 反射機制:可以操作位元組碼檔案 作用:可以讓程式更加靈活。 1.2、反射機制相關的類在哪個包下? java.lang.reflect.*; 1.3、反射機制相關的主要的類? java.lang.Class java.lang.reflect.Method; java.lang.reflect.Constructor; java.lang.reflect.Field; 1.4、在java中獲取Class的三種方式? 第一種: Class c = Class.forName("完整類名"); 第二種: Class c = 物件.getClass(); 第三種: Class c = int.class; Class c = String.class; 1.5、獲取了Class之後,可以呼叫無引數構造方法來例項化物件 //c代表的就是日期Date型別 Class c = Class.forName("java.util.Date"); //例項化一個Date日期型別的物件 Object obj = c.newInstance(); 一定要注意: newInstance()底層呼叫的是該型別的無引數構造方法。 如果沒有這個無引數構造方法會出現"例項化"異常。 1.6、如果你只想讓一個類的“靜態程式碼塊”執行的話,你可以怎麼做? Class.forName("該類的類名"); 這樣類就載入,類載入的時候,靜態程式碼塊執行!!!! 在這裡,對該方法的返回值不感興趣,主要是為了使用“類載入”這個動作。 1.7、關於路徑問題? String path = Thread.currentThread().getContextClassLoader() .getResource("寫相對路徑,但是這個相對路徑從src出發開始找").getPath(); String path = Thread.currentThread().getContextClassLoader() .getResource("abc").getPath(); //必須保證src下有abc檔案。 String path = Thread.currentThread().getContextClassLoader() .getResource("a/db").getPath(); //必須保證src下有a目錄,a目錄下有db檔案。 String path = Thread.currentThread().getContextClassLoader() .getResource("com/example/test.properties").getPath(); //必須保證src下有com目錄,com目錄下有example目錄。 //example目錄下有test.properties檔案。 這種方式是為了獲取一個檔案的絕對路徑。(通用方式,不會受到環境移植的影響。) 但是該檔案要求放在類路徑下,換句話說:也就是放到src下面。 src下是類的根路徑。 直接以流的形式返回: InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream("com/example/test.properties"); 1.8、IO + Properties,怎麼快速繫結屬性資原始檔? //要求:第一這個檔案必須在類路徑下 //第二這個檔案必須是以.properties結尾。 ResourceBundle bundle = ResourceBundle.getBundle("com/example/test"); String value = bundle.getString(key); 2、今日反射機制的重點內容 2.1、通過反射機制訪問物件的某個屬性。 2.2、通過反射機制呼叫物件的某個方法。 2.3、通過反射機制呼叫某個構造方法例項化物件。 2.4、通過反射機制獲取父類以及父型別介面。
ReflectTest01——獲取類的位元組碼檔案
怎麼獲取java.lang.Class例項?有三種方式:
-
Class c = Class.forName("完整類名帶包名");
靜態方法
方法的引數是一個字串。
字串需要的是一個完整類名。
完整類名必須帶有包名。java.lang包也不能省略。 -
Class c = 物件.getClass();
Class c1 = Class.forName("java.lang.String"); // c1代表String.class檔案,或者說c1代表String型別。
String s = "abc";
Class x = s.getClass(); // x代表String.class位元組碼檔案,x代表String型別。
System.out.println(c1 == x); // true(==判斷的是物件的記憶體地址。)
位元組碼記憶體圖:
-
Class c = 任何型別.class;
Class z = String.class; // z代表String型別
Class k = Date.class; // k代表Date型別
Class f = int.class; // f代表int型別
Class e = double.class; // e代表double型別
import java.util.Date;
/*
要操作一個類的位元組碼,需要首先獲取到這個類的位元組碼,怎麼獲取java.lang.Class例項?
三種方式
第一種:Class c = Class.forName("完整類名帶包名");
第二種:Class c = 物件.getClass();
第三種:Class c = 任何型別.class;
*/
public class ReflectTest01 {
public static void main(String[] args) {
/*
Class.forName()
1、靜態方法
2、方法的引數是一個字串。
3、字串需要的是一個完整類名。
4、完整類名必須帶有包名。java.lang包也不能省略。
*/
Class c1 = null;
Class c2 = null;
try {
c1 = Class.forName("java.lang.String"); // c1代表String.class檔案,或者說c1代表String型別。
c2 = Class.forName("java.util.Date"); // c2代表Date型別
Class c3 = Class.forName("java.lang.Integer"); // c3代表Integer型別
Class c4 = Class.forName("java.lang.System"); // c4代表System型別
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// java中任何一個物件都有一個方法:getClass()
String s = "abc";
Class x = s.getClass(); // x代表String.class位元組碼檔案,x代表String型別。
System.out.println(c1 == x); // true(==判斷的是物件的記憶體地址。)
Date time = new Date();
Class y = time.getClass();
System.out.println(c2 == y); // true (c2和y兩個變數中儲存的記憶體地址都是一樣的,都指向方法區中的位元組碼檔案。)
// 第三種方式,java語言中任何一種型別,包括基本資料型別,它都有.class屬性。
Class z = String.class; // z代表String型別
Class k = Date.class; // k代表Date型別
Class f = int.class; // f代表int型別
Class e = double.class; // e代表double型別
System.out.println(x == z); // true
}
}
ReflectTest02——通過Class的newInstance()方法來例項化物件
獲取到Class,能幹什麼?
可以通過Class的newInstance()方法來例項化物件。
注意:newInstance()方法內部實際上呼叫了無引數構造方法,必須保證無參構造存在才可以。
例如:
Class c = Class.forName("com.example.java.bean.User"); // c代表User型別。
Object obj = c.newInstance();
public class ReflectTest02 {
public static void main(String[] args) {
// 這是不使用反射機制,建立物件
User user = new User();
System.out.println(user);
// 下面這段程式碼是以反射機制的方式建立物件。
try {
// 通過反射機制,獲取Class,通過Class來例項化物件
Class c = Class.forName("com.example.java.bean.User"); // c代表User型別。
// newInstance() 這個方法會呼叫User這個類的無引數構造方法,完成物件的建立。
// 重點是:newInstance()呼叫的是無參構造,必須保證無參構造是存在的!
Object obj = c.newInstance();
System.out.println(obj); // com.example.java.bean.User@10f87f48
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
public class User {
public User(){
System.out.println("無引數構造方法!");
}
// 定義了有引數的構造方法,無引數構造方法就沒了。
public User(String s){
}
}
ReflectTest03——驗證反射機制的靈活性
為什麼說反射機制靈活?
Java程式碼寫一遍,再不改變java原始碼的基礎之上,可以做到不同物件的例項化。
非常之靈活。(符合OCP開閉原則:對擴充套件開放,對修改關閉。)
反射機制的用途是什麼?
高階框架底層使用反射機制比較多。
學會了反射機制有利於你理解剖析框架底層的原始碼。
/*
驗證反射機制的靈活性。
java程式碼寫一遍,再不改變java原始碼的基礎之上,可以做到不同物件的例項化。
非常之靈活。(符合OCP開閉原則:對擴充套件開放,對修改關閉。)
後期你們要學習的是高階框架,而工作過程中,也都是使用高階框架,
包括: ssh ssm
Spring SpringMVC MyBatis
Spring Struts Hibernate
...
這些高階框架底層實現原理:都採用了反射機制。所以反射機制還是重要的。
學會了反射機制有利於你理解剖析框架底層的原始碼。
*/
public class ReflectTest03 {
public static void main(String[] args) throws Exception{
// 這種方式程式碼就寫死了。只能建立一個User型別的物件
//User user = new User();
// 以下程式碼是靈活的,程式碼不需要改動,可以修改配置檔案,配置檔案修改之後,可以創建出不同的例項物件。
// 通過IO流讀取classinfo.properties檔案
FileReader reader = new FileReader("chapter25/classinfo2.properties");
// 建立屬性類物件Map
Properties pro = new Properties(); // key value都是String
// 載入
pro.load(reader);
// 關閉流
reader.close();
// 通過key獲取value
String className = pro.getProperty("className");
//System.out.println(className);
// 通過反射機制例項化物件
Class c = Class.forName(className);
Object obj = c.newInstance();
System.out.println(obj);
}
}
ReflectTest04——Class.forName()只是讓一個類的靜態程式碼塊執行,其它程式碼一律不執行
/*
研究一下:Class.forName()發生了什麼?
記住,重點:
如果你只是希望一個類的靜態程式碼塊執行,其它程式碼一律不執行,
你可以使用:
Class.forName("完整類名");
這個方法的執行會導致類載入,類載入時,靜態程式碼塊執行。
提示:
後面JDBC技術的時候我們還需要。
*/
public class ReflectTest04 {
public static void main(String[] args) {
try {
// Class.forName()這個方法的執行會導致:類載入。
Class.forName("com.example.reflect.MyClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public class MyClass {
// 靜態程式碼塊在類載入時執行,並且只執行一次。
static {
System.out.println("MyClass類的靜態程式碼塊執行了!");
}
}
AboutPath——怎麼獲取一個檔案的絕對路徑
為什麼不使用FileReader reader = new FileReader("chapter25/classinfo2.properties");
這種方式獲取檔案路徑的缺點?
這種方式的路徑缺點是:移植性差,在IDEA中預設的當前路徑是project的根。
這個程式碼假設離開了IDEA,換到了其它位置,可能當前路徑就不是project的根了,這時這個路徑就無效了。
怎麼獲取一個檔案的絕對路徑?
String path = Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath(); // 這種方式獲取檔案絕對路徑是通用的。
前提是:檔案需要在類路徑下。才能用這種方式。
在src下的都是類路徑下。
public class AboutPath {
public static void main(String[] args) throws Exception{
// 這種方式的路徑缺點是:移植性差,在IDEA中預設的當前路徑是project的根。
// 這個程式碼假設離開了IDEA,換到了其它位置,可能當前路徑就不是project的根了,這時這個路徑就無效了。
//FileReader reader = new FileReader("chapter25/classinfo2.properties");
// 接下來說一種比較通用的一種路徑。即使程式碼換位置了,這樣編寫仍然是通用的。
// 注意:使用以下通用方式的前提是:這個檔案必須在類路徑下。
// 什麼類路徑下?方式在src下的都是類路徑下。【記住它】
// src是類的根路徑。
/*
解釋:
Thread.currentThread() 當前執行緒物件
getContextClassLoader() 是執行緒物件的方法,可以獲取到當前執行緒的類載入器物件。
getResource() 【獲取資源】這是類載入器物件的方法,當前執行緒的類載入器預設從類的根路徑下載入資源。
*/
String path = Thread.currentThread().getContextClassLoader()
.getResource("classinfo2.properties").getPath(); // 這種方式獲取檔案絕對路徑是通用的。
// 採用以上的程式碼可以拿到一個檔案的絕對路徑。
// /C:/Users/Administrator/IdeaProjects/javase/out/production/chapter25/classinfo2.properties
System.out.println(path);
// 獲取db.properties檔案的絕對路徑(從類的根路徑下作為起點開始)
String path2 = Thread.currentThread().getContextClassLoader()
.getResource("com/example/java/bean/db.properties").getPath();
System.out.println(path2);
}
}
IoPropertiesTest——以流的形式返回讀取的檔案
public class IoPropertiesTest {
public static void main(String[] args) throws Exception{
// 獲取一個檔案的絕對路徑了!!!!!
/*String path = Thread.currentThread().getContextClassLoader()
.getResource("classinfo2.properties").getPath();
FileReader reader = new FileReader(path);*/
// 直接以流的形式返回。
InputStream reader = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("classinfo2.properties");
Properties pro = new Properties();
pro.load(reader);
reader.close();
// 通過key獲取value
String className = pro.getProperty("className");
System.out.println(className);
}
}
ResourceBundleTest——資源繫結器
import java.util.ResourceBundle;
/*
java.util包下提供了一個資源繫結器,便於獲取屬性配置檔案中的內容。
使用以下這種方式的時候,屬性配置檔案xxx.properties必須放到類路徑下。
*/
public class ResourceBundleTest {
public static void main(String[] args) {
// 資源繫結器,只能繫結xxx.properties檔案。並且這個檔案必須在類路徑下。副檔名也必須是properties
// 並且在寫路徑的時候,路徑後面的副檔名不能寫。
//ResourceBundle bundle = ResourceBundle.getBundle("classinfo2");
ResourceBundle bundle = ResourceBundle.getBundle("com/example/java/bean/db");
String className = bundle.getString("className");
System.out.println(className);
}
}
ReflectTest05——反射Student類獲得當中所有的Field
package com.example.java.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
反射Student類當中所有的Field(瞭解一下)
*/
public class ReflectTest05 {
public static void main(String[] args) throws Exception{
// 獲取整個類
Class studentClass = Class.forName("com.example.java.bean.Student");
//com.example.java.bean.Student
String className = studentClass.getName();
System.out.println("完整類名:" + className);
String simpleName = studentClass.getSimpleName();
System.out.println("簡類名:" + simpleName);
// 獲取類中所有的public修飾的Field
Field[] fields = studentClass.getFields();
System.out.println(fields.length); // 測試陣列中只有1個元素
// 取出這個Field
Field f = fields[0];
// 取出這個Field它的名字
String fieldName = f.getName();
System.out.println(fieldName);
// 獲取所有的Field
Field[] fs = studentClass.getDeclaredFields();
System.out.println(fs.length); // 4
System.out.println("==================================");
// 遍歷
for(Field field : fs){
// 獲取屬性的修飾符列表
int i = field.getModifiers(); // 返回的修飾符是一個數字,每個數字是修飾符的代號!!!
System.out.println(i);
// 可以將這個“代號”數字轉換成“字串”嗎?
String modifierString = Modifier.toString(i);
System.out.println(modifierString);
// 獲取屬性的型別
Class fieldType = field.getType();
//String fName = fieldType.getName();
String fName = fieldType.getSimpleName();
System.out.println(fName);
// 獲取屬性的名字
System.out.println(field.getName());
}
}
}
Student實體類:
package com.example.java.bean;
// 反射屬性Field
public class Student {
// Field翻譯為欄位,其實就是屬性/成員
// 4個Field,分別採用了不同的訪問控制權限修飾符
private String name; // Field物件
protected int age; // Field物件
boolean sex;
public int no;
public static final double MATH_PI = 3.1415926;
}
ReflectTest06——通過反射機制,反編譯一個類的屬性Field
package com.example.java.reflect;
//通過反射機制,反編譯一個類的屬性Field(瞭解一下)
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectTest06 {
public static void main(String[] args) throws Exception{
// 建立這個是為了拼接字串。
StringBuilder s = new StringBuilder();
//Class studentClass = Class.forName("com.example.java.bean.Student");
Class studentClass = Class.forName("java.lang.Thread");
s.append(Modifier.toString(studentClass.getModifiers()) + " class " + studentClass.getSimpleName() + " {\n");
Field[] fields = studentClass.getDeclaredFields();
for(Field field : fields){
s.append("\t");
s.append(Modifier.toString(field.getModifiers()));
s.append(" ");
s.append(field.getType().getSimpleName());
s.append(" ");
s.append(field.getName());
s.append(";\n");
}
s.append("}");
System.out.println(s);
}
}
ReflectTest07——通過反射機制設定和訪問一個java物件的屬性
package com.example.java.reflect;
import com.example.java.bean.Student;
import java.lang.reflect.Field;
/*
必須掌握:
怎麼通過反射機制訪問一個java物件的屬性?
給屬性賦值set
獲取屬性的值get
*/
public class ReflectTest07 {
public static void main(String[] args) throws Exception{
// 我們不使用反射機制,怎麼去訪問一個物件的屬性呢?
Student s = new Student();
// 給屬性賦值
s.no = 1111; //三要素:給s物件的no屬性賦值1111
//要素1:物件s
//要素2:no屬性
//要素3:1111
// 讀屬性值
// 兩個要素:獲取s物件的no屬性的值。
System.out.println(s.no);
// 使用反射機制,怎麼去訪問一個物件的屬性。(set get)
Class studentClass = Class.forName("com.bjpowernode.java.bean.Student");
Object obj = studentClass.newInstance(); // obj就是Student物件。(底層呼叫無引數構造方法)
// 獲取no屬性(根據屬性的名稱來獲取Field)
Field noFiled = studentClass.getDeclaredField("no");
// 給obj物件(Student物件)的no屬性賦值
/*
雖然使用了反射機制,但是三要素還是缺一不可:
要素1:obj物件
要素2:no屬性
要素3:2222值
注意:反射機制讓程式碼複雜了,但是為了一個“靈活”,這也是值得的。
*/
noFiled.set(obj, 22222); // 給obj物件的no屬性賦值2222
// 讀取屬性的值
// 兩個要素:獲取obj物件的no屬性的值。
System.out.println(noFiled.get(obj));
// 可以訪問私有的屬性嗎?
Field nameField = studentClass.getDeclaredField("name");
// 打破封裝(反射機制的缺點:打破封裝,可能會給不法分子留下機會!!!)
// 這樣設定完之後,在外部也是可以訪問private的。
nameField.setAccessible(true);
// 給name屬性賦值
nameField.set(obj, "jackson");
// 獲取name屬性的值
System.out.println(nameField.get(obj));
}
}
ArgsTest——可變長度引數
package com.bjpowernode.java.reflect;
/*
可變長度引數
int... args 這就是可變長度引數
語法是:型別... (注意:一定是3個點。)
1、可變長度引數要求的引數個數是:0~N個。
2、可變長度引數在引數列表中必須在最後一個位置上,而且可變長度引數只能有1個。
3、可變長度引數可以當做一個數組來看待
*/
public class ArgsTest {
public static void main(String[] args) {
m();
m(10);
m(10, 20);
// 編譯報錯
//m("abc");
m2(100);
m2(200, "abc");
m2(200, "abc", "def");
m2(200, "abc", "def", "xyz");
m3("ab", "de", "kk", "ff");
String[] strs = {"a","b","c"};
// 也可以傳1個數組
m3(strs);
// 直接傳1個數組
m3(new String[]{"我","是","中","國", "人"}); //沒必要
m3("我","是","中","國", "人");
}
public static void m(int... args){
System.out.println("m方法執行了!");
}
//public static void m2(int... args2, String... args1){}
// 必須在最後,只能有1個。
public static void m2(int a, String... args1){
}
public static void m3(String... args){
//args有length屬性,說明args是一個數組!
// 可以將可變長度引數當做一個數組來看。
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
}
}
ReflectTest08——反射Method
package com.bjpowernode.java.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
作為了解內容(不需要掌握):
反射Method
*/
public class ReflectTest08 {
public static void main(String[] args) throws Exception{
// 獲取類了
Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
// 獲取所有的Method(包括私有的!)
Method[] methods = userServiceClass.getDeclaredMethods();
//System.out.println(methods.length); // 2
// 遍歷Method
for(Method method : methods){
// 獲取修飾符列表
System.out.println(Modifier.toString(method.getModifiers()));
// 獲取方法的返回值型別
System.out.println(method.getReturnType().getSimpleName());
// 獲取方法名
System.out.println(method.getName());
// 方法的修飾符列表(一個方法的引數可能會有多個。)
Class[] parameterTypes = method.getParameterTypes();
for(Class parameterType : parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
}
}
UserService
package com.bjpowernode.java.service;
/**
* 使用者業務類
*/
public class UserService {
/**
* 登入方法
* @param name 使用者名稱
* @param password 密碼
* @return true表示登入成功,false表示登入失敗!
*/
public boolean login(String name,String password){
if("admin".equals(name) && "123".equals(password)){
return true;
}
return false;
}
// 可能還有一個同名login方法
// java中怎麼區分一個方法,依靠方法名和引數列表。
public void login(int i){
}
/**
* 退出系統的方法
*/
public void logout(){
System.out.println("系統已經安全退出!");
}
}
ReflectTest09——反編譯一個類的方法
package com.bjpowernode.java.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
瞭解一下,不需要掌握(反編譯一個類的方法。)
*/
public class ReflectTest09 {
public static void main(String[] args) throws Exception{
StringBuilder s = new StringBuilder();
//Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
Class userServiceClass = Class.forName("java.lang.String");
s.append(Modifier.toString(userServiceClass.getModifiers()) + " class "+userServiceClass.getSimpleName()+" {\n");
Method[] methods = userServiceClass.getDeclaredMethods();
for(Method method : methods){
//public boolean login(String name,String password){}
s.append("\t");
s.append(Modifier.toString(method.getModifiers()));
s.append(" ");
s.append(method.getReturnType().getSimpleName());
s.append(" ");
s.append(method.getName());
s.append("(");
// 引數列表
Class[] parameterTypes = method.getParameterTypes();
for(Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
// 刪除指定下標位置上的字元
s.deleteCharAt(s.length() - 1);
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
ReflectTest10——通過反射機制怎麼呼叫一個物件的方法
package com.bjpowernode.java.reflect;
import com.bjpowernode.java.service.UserService;
import java.lang.reflect.Method;
/*
重點:必須掌握,通過反射機制怎麼呼叫一個物件的方法?
五顆星*****
反射機制,讓程式碼很具有通用性,可變化的內容都是寫到配置檔案當中,
將來修改配置檔案之後,建立的物件不一樣了,呼叫的方法也不同了,
但是java程式碼不需要做任何改動。這就是反射機制的魅力。
*/
public class ReflectTest10 {
public static void main(String[] args) throws Exception{
// 不使用反射機制,怎麼呼叫方法
// 建立物件
UserService userService = new UserService();
// 呼叫方法
/*
要素分析:
要素1:物件userService
要素2:login方法名
要素3:實參列表
要素4:返回值
*/
boolean loginSuccess = userService.login("admin","123");
//System.out.println(loginSuccess);
System.out.println(loginSuccess ? "登入成功" : "登入失敗");
// 使用反射機制來呼叫一個物件的方法該怎麼做?
Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
// 建立物件
Object obj = userServiceClass.newInstance();
// 獲取Method
Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
//Method loginMethod = userServiceClass.getDeclaredMethod("login", int.class);
// 呼叫方法
// 呼叫方法有幾個要素? 也需要4要素。
// 反射機制中最最最最最重要的一個方法,必須記住。
/*
四要素:
loginMethod方法
obj物件
"admin","123" 實參
retValue 返回值
*/
Object retValue = loginMethod.invoke(obj, "admin","123123");
System.out.println(retValue);
}
}
ReflectTest11——反編譯一個類的Constructor構造方法
package com.bjpowernode.java.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
/*
反編譯一個類的Constructor構造方法。
*/
public class ReflectTest11 {
public static void main(String[] args) throws Exception{
StringBuilder s = new StringBuilder();
Class vipClass = Class.forName("java.lang.String");
s.append(Modifier.toString(vipClass.getModifiers()));
s.append(" class ");
s.append(vipClass.getSimpleName());
s.append("{\n");
// 拼接構造方法
Constructor[] constructors = vipClass.getDeclaredConstructors();
for(Constructor constructor : constructors){
//public Vip(int no, String name, String birth, boolean sex) {
s.append("\t");
s.append(Modifier.toString(constructor.getModifiers()));
s.append(" ");
s.append(vipClass.getSimpleName());
s.append("(");
// 拼接引數
Class[] parameterTypes = constructor.getParameterTypes();
for(Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
// 刪除最後下標位置上的字元
if(parameterTypes.length > 0){
s.deleteCharAt(s.length() - 1);
}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
ReflectTest12——通過反射機制呼叫構造方法例項化java物件
package com.bjpowernode.java.reflect;
import com.bjpowernode.java.bean.Vip;
import java.lang.reflect.Constructor;
/*
比上一個例子(ReflectTest11)重要一些!!!
通過反射機制呼叫構造方法例項化java物件。(這個不是重點)
*/
public class ReflectTest12 {
public static void main(String[] args) throws Exception{
// 不使用反射機制怎麼建立物件
Vip v1 = new Vip();
Vip v2 = new Vip(110, "zhangsan", "2001-10-11", true);
// 使用反射機制怎麼建立物件呢?
Class c = Class.forName("com.bjpowernode.java.bean.Vip");
// 呼叫無引數構造方法
Object obj = c.newInstance();
System.out.println(obj);
// 呼叫有引數的構造方法怎麼辦?
// 第一步:先獲取到這個有引數的構造方法
Constructor con = c.getDeclaredConstructor(int.class, String.class, String.class,boolean.class);
// 第二步:呼叫構造方法new物件
Object newObj = con.newInstance(110, "jackson", "1990-10-11", true);
System.out.println(newObj);
// 獲取無引數構造方法
Constructor con2 = c.getDeclaredConstructor();
Object newObj2 = con2.newInstance();
System.out.println(newObj2);
}
}
ReflectTest13——給你一個類,怎麼獲取這個類的父類,已經實現了哪些介面?
package com.bjpowernode.java.reflect;
/*
重點:給你一個類,怎麼獲取這個類的父類,已經實現了哪些介面?
*/
public class ReflectTest13 {
public static void main(String[] args) throws Exception{
// String舉例
Class stringClass = Class.forName("java.lang.String");
// 獲取String的父類
Class superClass = stringClass.getSuperclass();
System.out.println(superClass.getName());
// 獲取String類實現的所有介面(一個類可以實現多個介面。)
Class[] interfaces = stringClass.getInterfaces();
for(Class in : interfaces){
System.out.println(in.getName());
}
}
}