[TOC]
# 類的加載器
當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化。
* 加載
就是指將class文件讀入內存,并為之創建一個Class對象。
任何類被使用時系統都會建立一個Class對象
* 連接
驗證 是否有正確的內部結構,并和其他類協調一致
準備 負責為類的靜態成員分配內存,并設置默認初始化值
解析 將類的二進制數據中的符號引用替換為直接引用
* 初始化
## 類的初始化時機
1. 創建類的實例
2. 類的靜態變量,或者為靜態變量賦值
3. 類的靜態方法
4. 使用反射方式來強制創建某個類或接口對應的java.lang.Class對象
5. 初始化某個類的子類
6. 直接使用java.exe命令來運行某個主類
## 類加載器
* 負責將.class文件加載到內在中,并為之生成對應的Class對象。
* 雖然我們不需要關心類加載機制,但是了解這個機制我們就能更好的理解程序的運行
## 類加載器的組成
* Bootstrap ClassLoader 根類加載器
也被稱為引導類加載器,負責Java核心類的加載
比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中
* Extension ClassLoader 擴展類加載器
負責JRE的擴展目錄中jar包的加載。
在JDK中JRE的lib目錄下ext目錄
* System ClassLoader 系統類加載器
負責在JVM啟動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑

# 反射
## class類
Class類沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的
獲取Class對象的三種方式
**方式一: 通過Object類中的getObject()方法**
~~~
Person p = new Person();
Class c = p.getClass();
~~~
**方式二: 通過 類名.class 獲取到字節碼文件對象**
(任意數據類型都具備一個class靜態屬性,看上去要比第一種方式簡單)。
~~~
Class c2 = Person.class;
~~~
**方式三: 通過Class類中的方法**
(將類名作為字符串傳遞給Class類中的靜態方法forName即可)。
~~~
Class c3 = Class.forName("com.jdxia.Person");
~~~
* 注意:第三種和前兩種的區別
前兩種你必須明確Person類型.
后面是指定這種類型的字符串就行.這種擴展更強.我不需要知道你的類.我只提供字符串,按照配置文件加載就可以了
~~~
Person person = new Person();
Class c1 = person.getClass();
Class c2 = Person.class;
Class c3 = Class.forName("study.Person");
~~~
## 反射獲取構造方法
在反射機制中,把類中的成員(構造方法、成員方法、成員變量)都封裝成了對應的類進行表示。其中,構造方法使用類Constructor表示。可通過Class類中提供的方法獲取構造方法:
* 返回一個構造方法
- public Constructor<T> getConstructor(Class<?>... parameterTypes) 獲取public修飾, 指定參數類型所對應的構造方法
- public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 獲取指定參數類型所對應的構造方法(包含私有的)
* 返回多個構造方法
- public Constructor<?>[] getConstructors() 獲取所有的public 修飾的構造方法
- public Constructor<?>[] getDeclaredConstructors() 獲取所有的構造方法(包含私有的)
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取所有的構造方法
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//私有構造也能獲取
System.out.println(constructor);
}
/**
* 獲取一個構造方法
* public Person()
*/
Constructor constructor = c.getConstructor(null);
System.out.println(constructor);
//public Person(String name, int a)
Constructor constructor1 = c.getDeclaredConstructor(String.class,int.class);
System.out.println(constructor1);
//private Person(String name)
Constructor constructor2 = c.getDeclaredConstructor(String.class);
System.out.println(constructor2);
~~~
## 反射獲取構造方法創建對象
獲取構造方法,步驟如下:
1. 獲取到Class對象
2. 獲取指定的構造方法
3. 通過構造方法類Constructor中的方法,創建對象
public T newInstance(Object... initargs)
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取構造方法
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
//通過構造方法類中的Constructor的方法創建對象
Object object = constructor.newInstance("jdxia",1);
System.out.println(object);
~~~
## 反射獲取私有構造方法創建對象
AccessibleObject 類是 Field、Method 和 Constructor 對象的父類。它提供了將反射的對象標記為在使用時取消默認 Java 語言訪問控制檢查的能力。
對于公共成員、默認(打包)訪問成員、受保護成員和私有成員,在分別使用 Field、Method 或 Constructor 對象來設置或獲取字段、調用方法,或者創建和初始化類的新實例的時候,會執行訪問檢查。常用方法如下:
* public void setAccessible(boolean flag) throws SecurityException
參數值為 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。參數值為 false 則指示反射的對象應該實施 Java 語言訪問檢查。
獲取私有構造方法,步驟如下:
1. 獲取到Class對象
2. 獲取指定的構造方法
3. 暴力訪問, 通過setAccessible(boolean flag)方法
4. 通過構造方法類Constructor中的方法,創建對象
public T newInstance(Object... initargs)
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取構造方法
Constructor constructor = c.getDeclaredConstructor(String.class);
//暴力反射,取消java語言訪問檢查
constructor.setAccessible(true);
Object object = constructor.newInstance("jdxia");
System.out.println(object);
~~~
## 反射獲取成員變量
在反射機制中,把類中的成員變量使用類Field表示。可通過Class類中提供的方法獲取成員變量:
* 返回一個成員變量
- public Field getField(String name) 獲取指定的 public修飾的變量
- public Field getDeclaredField(String name) 獲取指定的任意變量
* 返回多個成員變量
- public Field[] getFields() 獲取所有public 修飾的變量
- public Field[] getDeclaredFields() 獲取所有的 變量 (包含私有)
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取成員變量
//多個變量
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//一個變量
Field name = c.getField("name");
System.out.println(name);
//私有的
Field a = c.getDeclaredField("a");
System.out.println(a);
~~~
## 反射獲取指定的成員變量,進行賦值與取值
獲取成員變量,步驟如下:
1. 獲取Class對象
2. 獲取構造方法
3. 通過構造方法,創建對象
4. 獲取指定的成員變量(私有成員變量,通過setAccessible(boolean flag)方法暴力訪問)
5. 通過方法,給指定對象的指定成員變量賦值或者獲取值
* public void set(Object obj, Object value)
在指定對象obj中,將此 Field 對象表示的成員變量設置為指定的新值
* public Object get(Object obj)
返回指定對象obj中,此 Field 對象表示的成員變量的值
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取構造方法
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
//通過構造方法創建對象
Object object = constructor.newInstance("jdxia", 1);
//獲取指定的成員變量
Field name = c.getDeclaredField("name");
Field a = c.getDeclaredField("a");
//取消語言訪問檢查
a.setAccessible(true);
//通過方法,給指定對象的指定成員變量賦值或者取值
System.out.println("name = "+name.get(object));
System.out.println("a = "+a.get(object));
//賦值
name.set(object, "x");
a.set(object, 2);
System.out.println("name = "+name.get(object));
System.out.println("a = "+a.get(object));
~~~
## 反射獲取成員方法
在反射機制中,把類中的成員方法使用類Method表示。可通過Class類中提供的方法獲取成員方法:
* 返回獲取一個方法:
- public Method getMethod(String name, Class<?>... parameterTypes)
獲取public 修飾的方法
- public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
獲取任意的方法,包含私有的
參數1: name 要查找的方法名稱; 參數2: parameterTypes 該方法的參數類型
* 返回獲取多個方法:
- public Method[] getMethods() 獲取本類與父類中所有public 修飾的方法
- public Method[] getDeclaredMethods() 獲取本類中所有的方法(包含私有的)
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取多個方法
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
//獲取一個方法
//private void param(String param)
Method method = c.getDeclaredMethod("param",String.class);
System.out.println(method);
~~~
## 反射調用指定的方法
獲取成員方法,步驟如下:
1. 獲取Class對象
2. 獲取構造方法
3. 通過構造方法,創建對象
4. 獲取指定的方法
5. 執行找到的方法
* public Object invoke(Object obj, Object... args)
執行指定對象obj中,當前Method對象所代表的方法,方法要傳入的參數通過args指定。
~~~
//獲取Class對象
Class c = Class.forName("study.Person");
//獲取構造方法
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
//通過構造方法創建對象
Object obj = constructor.newInstance("jdxia",1);
//獲取一個方法
//private void param(String param)
Method method = c.getDeclaredMethod("param",String.class);
//取消語法檢查
method.setAccessible(true);
Object result = method.invoke(obj,"傳遞的參數");
//獲取函數返回值
System.out.println(result);
~~~
## 泛型擦除
思考,將已存在的ArrayList<Integer>集合中添加一個字符串數據,如何實現呢?
我來告訴大家,其實程序編譯后產生的.class文件中是沒有泛型約束的,這種現象我們稱為泛型的擦除。那么,我們可以通過反射技術,來完成向有泛型約束的集合中,添加任意類型的元素
~~~
ArrayList<Integer> list = new ArrayList<Integer>();
//添加元素到集合
list.add(new Integer(30));
list.add(new Integer("12345"));
list.add(123);
//list.add("哈哈");//因為有泛型類型的約束
System.out.println(list);
//通過反射技術,實現添加任意類型的元素
//1, 獲取字節碼文件對象
//Class c = list.getClass();
//Class c = ArrayList.class;
Class c = Class.forName("java.util.ArrayList");
//2, 找到add()方法
// public boolean add(E e)
Method addMethod = c.getMethod("add", Object.class);
//3, 執行add()方法
addMethod.invoke(list, "哈哈");// list.add("哈哈");
System.out.println(list);
~~~
## 反射配置文件
* 通過反射配置文件,運行配置文件中指定類的對應方法
讀取Peoperties.txt文件中的數據,通過反射技術,來完成Person對象的創建
Peoperties.txt文件內容如下:
~~~
className=study.Person
methodName=method5
~~~
讀取配置文件,調用指定類中的對應方法
~~~
// 通過Properties集合從文件中讀取數據
Properties prop = new Properties();
// 讀取文件中的數據到集合中
prop.load(new FileInputStream("properties.txt"));
// 獲取鍵所對應的值
String className = prop.getProperty("className");
System.out.println(className);
// 1,獲取Person.class 字節碼文件對象
Class c = Class.forName(className);
// 2,獲取構造方法
// public Person(String name, int age, String address)
Constructor con = c.getConstructor(String.class, int.class, String.class);
// 3,創建對象
Object obj = con.newInstance("小明", 20, "中國");
System.out.println(obj);
// 4,獲取指定的方法
// private void method5(){}
String methodName = prop.getProperty("methodName");
Method m5 = c.getDeclaredMethod(methodName, null);
// 5,開啟暴力訪問
m5.setAccessible(true);
// 6,執行找到的方法
m5.invoke(obj, null);
~~~
- 基礎
- 編譯和安裝
- scanner類(鍵盤錄入)
- Random類(隨機數)
- 數組
- 方法
- 類
- ArrayList集合
- char與int
- eclipse
- IDEA
- 變量與常量
- 常用API
- String,StringBuffer,StringBuilder
- 正則,Date,DateFormat,Calendar
- 包裝類,System,Math,Arrays,BigInteger,BigDecimal
- 集合,迭代器,增強for,泛型
- List,set,判斷集合唯一
- map,Entry,HashMap,Collections
- 異常
- IO
- File
- 遞歸
- 字節流
- 字符流
- IO流分類
- 轉換流
- 緩沖流
- 流的操作規律
- properties
- 序列化流與反序列化流
- 打印流
- commons-IO
- IO流總結
- 多線程
- 線程池
- 線程安全
- 線程同步
- 死鎖
- lock接口
- ThreadLoad
- 等待喚醒機制
- 線程狀態
- jdbc
- DBUtils
- 連接池DBCP
- c3p0連接池
- 網絡編程
- 多線程socket上傳圖片
- 反射
- xml
- 設計模式
- 裝飾器模式
- web service
- tomcat
- Servlet
- response
- request
- session和cookie
- JSP
- EL
- JSTL
- 事務
- 監聽器Listener
- 過濾器Filter
- json
- linux安裝軟件
- 反射詳解
- 類加載器和注解
- 動態代理
- jedis
- Hibernate
- 簡介
- 創建映射文件
- Hibernate核心配置文件
- 事務和增刪改查
- HibernateUtils
- 持久化對象的三種狀態
- 檢索方式
- query
- Criteria
- SQLQuery
- 持久化類
- 主鍵生成策略
- 緩存
- 事務管理
- 關系映射
- 注解
- 優化
- struts2
- 搭建
- 配置詳解
- Action
- 結果跳轉方式
- 訪問ServletAPI方式
- 如何獲得參數
- OGNL表達式
- valueStack 值棧
- Interceptor攔截器
- spring
- 導包
- IOC和DI
- Bean獲取與實例化
- Bean屬性注入
- spring注解
- 注解分層
- junit整合
- aop
- 動態代理實現
- cglib代理實現
- aop名詞
- spring的aop
- aop-xml詳解
- aop-注解詳解
- 代理方式選擇
- jdbcTemplate
- spring事務管理
- 回滾注意
- 事務傳播屬性
- MyBatis
- MyBatis簡介
- 入門程序
- 與jdbc hibernate不同
- 原始Dao開發
- Mapper動態代理方式
- SqlMapConfig.xml配置文件
- 輸入參數pojo包裝類
- resultMap
- 動態sql
- 一對一關聯
- 一對多
- 整合spring
- 逆向工程
- maven
- maven簡介
- 倉庫
- maven目錄結構
- maven常用命令
- 生命周期
- eclipse中maven插件
- 入門程序
- 整合struct
- 依賴范圍
- 添加插件
- idea配置
- jar包沖突
- 分模塊開發
- 構建可執行的jar包(包含依賴jar包)
- springMVC
- 處理流程
- java面試
- java版本升級
- java1-8版本變更
- java9新特性
- 鎖
- java資料
- idea
- jdk版本切換
- log4j
- 入門實例
- 基本使用方法
- Web中使用Log4j
- spring中使用log4j
- java代碼優化