動態語言
是一類在執行時可以改變其結構的語言:例如新的函數、物件、甚至程式碼可以被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在執行時程式碼可以根據某些條件改變自身結構
主要動態語言:Object-C、C#、JavaScript、PHP、Python、Erlang
反射
Reflection(反射)是被視爲動態語言的關鍵,反射機制 機製允許程式在執行期藉助於Reflection API取得任何類的內部資訊,並能直接操作任意物件的內部屬性及方法
載入完類之後,在堆記憶體的方法區中就產生了一個Class型別的物件(一個類只有一個Class物件),這個物件就包含了完整的類的結構資訊,我們可以通過這個物件看到類的結構。
這個物件就像一面鏡子,透過這個鏡子看到類的結構,所以,我們形象的稱之爲:反射
四種方法獲取Class類的範例:
//匯入的包有:import org.junit.Test;
public class ReflectionTest1 {
@Test
public void test1() throws ClassNotFoundException {
//方式一:呼叫執行時類的屬性:.class
Class clazz1 = String.class;
System.out.println(clazz1);//class java.lang.String
//方式二:通過執行時類的物件,呼叫getClass()
String s1 = new String();
Class clazz2 = s1.getClass();
System.out.println(clazz2);//class java.lang.String
//方式三:呼叫Class的靜態方法:forName(String classPath)
Class clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3);//class java.lang.String
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
//方式四:使用類的載入器:ClassLoader (瞭解)
ClassLoader classLoader = ReflectionTest1.class.getClassLoader();
Class clazz4 = classLoader.loadClass("java.lang.String");
System.out.println(clazz4);//class java.lang.String
System.out.println(clazz1 == clazz4);//true
}
}
除了類以外,介面、陣列、列舉、註解基本數據型別、void也可以作爲Class類的範例
當程式主動使用某個類時,如果該類還未被載入到記憶體中,則系統會通過如下三個步驟來對該類進行初始化
類載入器的作用:將class檔案位元組碼內容載入到記憶體中,並將這些靜態數據轉換成方法區的執行時數據結構,然後在堆中生成一個代表這個類的java.lang.Class物件,作爲方法區中類數據的存取入口
JVM 規範定義瞭如下型別的類的載入器:
//匯入的包有:import org.junit.Test;
public class ClassLoaderTest {
@Test
public void test1(){
//對於自定義類:使用系統類載入器進行載入
ClassLoader classLoader1 = ClassLoaderTest.class.getClassLoader();
//呼叫系統載入器的getParent():獲取擴充套件類載入器
System.out.println(classLoader1);//sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader classLoader2 = classLoader1.getParent();
//呼叫擴充套件類載入器的getParent():無法獲取引導類載入器
//引導類載入器主要負責載入Java的核心類庫,無法載入自定義類
System.out.println(classLoader2);//sun.misc.Launcher$ExtClassLoader@a09ee92
ClassLoader classLoader3 = classLoader2.getParent();
System.out.println(classLoader3);//null
}
}
通過反射,建立執行時類的物件
//匯入的包有:import org.junit.Test;
public class ClassLoaderTest {
@Test
public void test2() throws IllegalAccessException, InstantiationException {
Class<String> clazz = String.class;
/*
* newInstance():呼叫此方法,建立對應的執行時類的物件,其內部呼叫了執行時類的空參構造器
*
* 要想此方法正常的建立執行時類的物件,要求
* 1.執行時類必須提供空參的構造器
* 2.空參的構造器的存取許可權足夠,通常設定爲public
*/
//由於建立Class類的物件時,規定了泛型,所以此處自動轉換型別
String obj = clazz.newInstance();
System.out.println(obj);
}
}
當我們建立好Class物件後,可以獲得其所有屬性
//匯入的包有:import org.junit.Test;import java.lang.reflect.Field;import java.lang.reflect.Modifier;
public class Test1 {
@Test
public void test1(){
Class clazz = String.class;
//獲取屬性結構
//getFields():獲取當前執行時類及其父類別中宣告爲public存取許可權的屬性
Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}
//getDeclaredFields():獲取當前執行時類中宣告的所有屬性,不包含父類別中宣告的屬性
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
}
@Test
public void test2(){
Class clazz = String.class;
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
//1.獲取許可權修飾符
int modifier = f.getModifiers();
System.out.println(Modifier.toString(modifier));
//2.獲取數據型別
Class type = f.getType();
System.out.println(type.getName());
//3.獲取變數名
String fName = f.getName();
System.out.println(fName);
}
}
}
當我們建立好Class物件後,可以獲得其所有方法
//匯入的包有:import org.junit.Test;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;
public class Test1 {
@Test
public void test3(){
Class clazz = String.class;
//getMethods():獲取當前執行時類一起所有父類別中宣告爲public許可權的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m);
}
//getDeclaredMethods():獲取當前執行時類中宣告的所有方法,不包含父類別中宣告的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
System.out.println(m);
}
}
}
我們也可以獲取方法的許可權修飾符,返回值型別,方法名,參數,註解,異常,由於使用不多,這裏不展開敘述
當我們建立好Class物件後,可以獲得其構造器
//匯入的包有:import org.junit.Test;import java.lang.reflect.Constructor;
public class Test1 {
@Test
public void test4(){
//getConstructors():獲取當前執行時類中宣告爲public的構造器
Class clazz = String.class;
Constructor[] constructors = clazz.getConstructors();
for(Constructor c : constructors){
System.out.println(c);
}
//getDeclaredConstructors():獲取當前執行時類中宣告的所有構造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for(Constructor c : declaredConstructors){
System.out.println(c);
}
}
}
還可以獲得執行時類的父類別及其父類別的泛型、介面、所在包、註解,這裏不在一一演示
//匯入的包有:import org.junit.Test;import java.lang.reflect.Field;
//現在假設有一Person類,具有一般類所具有的屬性,方法,構造器
public class ReflectionTest2 {
@Test
public void test1() throws Exception {
Class clazz = Person.class;
//建立執行時類的物件
Person p = (Person) clazz.newInstance();
//1.getDeclaredField(String name):獲取執行時類中指定變數名的屬性
Field name = clazz.getDeclaredField("name");
//還有一種方式獲取執行時類中的指定變數,但一般不使用,因爲只能獲得Public屬性
//Field name = clazz.getFueld("name")
//2.保證當前屬性時可存取的
name.setAccessible(true);
//3.獲取、設定指定物件的此屬性
name.set(p,"Tom");
//4.輸出當前屬性的值
System.out.println(name.get(p));
}
}
//匯入的包有:import org.junit.Test;import java.lang.reflect.Method;
//現在假設有一Person類,具有一般類所具有的屬性,方法,構造器
public class ReflectionTest2 {
@Test
public void test2() throws Exception {
Class clazz = Person.class;
//建立執行時類的物件
Person p = (Person) clazz.newInstance();
/*
1.獲取某個指定方法
getDeclaredMethod():參數1:指明獲取方法的名稱,參數2:指明獲取的方法的形參列表
*/
Method show = clazz.getDeclaredMethod("show", String.class);
//2.保證當前方法是可存取的
show.setAccessible(true);
/*
3.呼叫方法的invoke():參數1:方法的呼叫者,參數2:給方法形參賦值的實參
invoke()的返回值即爲對應類中呼叫的方法的返回值
若呼叫執行時類的靜態方法,則傳入的參數1爲Person.class
*/
Object returnValue = show.invoke(p, "China");
}
}
還可以呼叫執行時類的指定構造器,但是用非常少,這裏不再演示
代理設計模式的原理:
代理模式分爲靜態和動態:
interface ClothFactory{
void produceCloth();
}
//代理類
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;//用被代理物件進行範例化
public ProxyClothFactory(ClothFactory factory){
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工廠做準備工作");
factory.produceCloth();
System.out.println("代理工廠做後續工作");
}
}
//被代理類
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工廠生產一批運動服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
//建立被代理類的物件
NikeClothFactory nike = new NikeClothFactory();
//建立代理類的物件
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
/*代理工廠做準備工作
Nike工廠生產一批運動服
代理工廠做後續工作*/