## 反射機制概念
JAVA反射機制是在運行狀態中,對于任意一個實體類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制。
主要是指程序可以訪問,檢測和修改它本身狀態或行為的一種能力,并能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。在java中,只要給定類的名字,那么就可以通過反射機制來獲得類的所有信息。
反射是Java中一種強大的工具,能夠使我們很方便的創建靈活的代碼,這些代碼可以再運行時裝配,無需在組件之間進行源代碼鏈接。但是反射使用不當會成本很高!
類中有什么信息,利用反射機制就能可以獲得什么信息,不過前提是得知道類的名字。所有類的對象其實都是Class的實例。
## 反射機制的作用
- 在運行時判斷任意一個對象所屬的類;
- 在運行時構造任意一個類的對象;
- 在運行時判斷任意一個類所具有的成員變量和方法;
- 在運行時調用任意一個對象的方法;
- 生成動態代理。
## 反射機制的優點與缺點
首先要搞清楚為什么要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態的概念。
- 靜態編譯:在編譯時確定類型,綁定對象,即通過。
- 動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以降低類之間的藕合性。
#### 反射機制的優點
可以實現動態創建對象和編譯,體現出很大的靈活性(特別是在J2EE的開發中它的靈活性就表現的十分明顯)。通過反射機制我們可以獲得類的各種內容,進行了反編譯。對于JAVA這種先編譯再運行的語言來說,反射機制可以使代碼更加靈活,更加容易實現面向對象。
比如,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編譯后,發布了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟件肯定是沒有多少人用的。采用靜態的話,需要把整個程序重新編譯一次才可以實現功能的更新,而采用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實現該功能。
#### 反射機制的缺點
對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它 滿足我們的要求。這類操作總是慢于只直接執行相同的操作。
## 反射機制的示例
```java
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Car {
private String brand;
private String color;
private int maxSpeed;
public Car() {
}
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public void introduce() {
System.out.println("brand:" + brand + "; color:" + color + "; maxspeed:" + maxSpeed);
}
}
public class hello {
public static void main(String[] args) {
// 通過類加載器加載Car類對象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = null;
try {
clazz = loader.loadClass("Car");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 獲取類的默認構造器并通過它實例化Car
Constructor<?> cons = null;
Car car = null;
try {
cons = clazz.getDeclaredConstructor((Class[]) null);
car = (Car) cons.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// 通過反射方法設置屬性
Method setBrand = null;
try {
setBrand = clazz.getMethod("setBrand", String.class);
setBrand.invoke(car, "紅旗CA72");
Method setColor = clazz.getMethod("setColor", String.class);
setColor.invoke(car, "黑色");
Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
setMaxSpeed.invoke(car, 200);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
```
## 類的生命周期

#### 加載
我們編寫一個java的源文件,經過編譯后生成一個后綴名為.class的文件,這結合四字節碼文件,java虛擬機就識別這種文件,java的生命周期就是class文件從加載到消亡的過程。
關于加載,其實,就是將源文件的class文件找到類的信息將其加載到方法區中,然后在堆區中實例化一個java.lang.Class對象,作為方法區中這個類的信息的入口。但是這一功能是在JVM之外實現的,主要的原因是方便讓應用程序自己決定如何獲取這個類,在不同的虛擬機實現的方式不一定相同,hotspot虛擬機是采用需要時在加載的方式,也有其他是先預先加載的。
#### 連接
一般會跟加載階段和初始化階段交叉進行,過程由三部分組成:驗證、準備和解析三步:
- 驗證:確定該類是否符合java語言的規范,有沒有屬性和行為的重復,繼承是否合理,總之,就是保證jvm能夠執行
- 準備:主要做的就是為由static修飾的成員變量分配內存,并設置默認的初始值
默認初始值如下:
1. 八種基本數據類型默認的初始值是0
2. 引用類型默認的初始值是null
3. 有static final修飾的會直接賦值,例如:static final int x=10;則默認就是10.
- 解析:這一階段的任務就是把常量池中的符號引用轉換為直接引用,說白了就是jvm會將所有的類或接口名、字段名、方法名轉換為具體的內存地址。
#### 初始化
這個階段就是將靜態變量(類變量)賦值的過程,即只有static修飾的才能被初始化,執行的順序就是:
父類靜態域或著靜態代碼塊,然后是子類靜態域或者子類靜態代碼塊
#### 使用
在類的使用過程中依然存在三步:對象實例化、垃圾收集、對象終結:
- 對象實例化
就是執行類中構造函數的內容,如果該類存在父類JVM會通過顯示或者隱示的方式先執行父類的構造函數,在堆內存中為父類的實例變量開辟空間,并賦予默認的初始值,然后在根據構造函數的代碼內容將真正的值賦予實例變量本身,然后,引用變量獲取對象的首地址,通過操作對象來調用實例變量和方法
- 垃圾收集
當對象不再被引用的時候,就會被虛擬機標上特別的垃圾記號,在堆中等待GC回收
- 對象的終結
對象被GC回收后,對象就不再存在,對象的生命也就走到了盡頭
#### 類卸載
即類的生命周期走到了最后一步,程序中不再有該類的引用,該類也就會被JVM執行垃圾回收,從此生命結束…