第十四章-類型信息(2)

四、反射

      Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

      Class類與java.lang.reflect類庫一起對反射的概念進行了支持,該類庫包含了Field、Method、Constructor等類,每個類都實現了Member接口,該接口代表一個特定的成員(變量,方法或者構造器)。

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Test
{
	public int i;
	float j;
	
	public Testa(){}
	
	private Testa(String str){}
	
	public void fun(){}
}


public class ReflectTest
{
	//打印數組的方法
	public static void print(String name, Object[] array)
	{
		System.out.println("-----" + name + "------");
		for(Object obj : array)
		{
			System.out.println(obj);
		}
		System.out.println("---------------------------");
	}
	
	public static void main(String[] args)
	{
		Class<Test> c = Test.class;
		
		//獲得所有聲明的方法、變量和構造器
		Method[] declaredMethods = c.getDeclaredMethods();
		Field[] declaredFields = c.getDeclaredFields();
		Constructor[] declareConstructors = c.getDeclaredConstructors();
		
		//獲得所有public的方法、變量和構造器
		Method[] publicMethods = c.getMethods();
		Field[] publicFields = c.getFields();
		Constructor[] publicConstructors = c.getConstructors();
		
		print("declared methods", declaredMethods);
		print("declared fields", declaredFields);
		print("declared constructors", declareConstructors);
		
		print("public methods", publicMethods);
		print("public fields", publicFields);
		print("public constructors", publicConstructors);
	}
}

 

輸出

-----declared methods------
public static void Test.main(java.lang.String[])
---------------------------
-----declared fields------
---------------------------
-----declared constructors------
public Test()
---------------------------
-----public methods------
public static void Test.main(java.lang.String[])
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
---------------------------
-----public fields------
---------------------------
-----public constructors------
public Test()
---------------------------

 

五、動態代理

      代理是基本的設計模式之一,它是爲了提供額外的或不同的操作,而插入的用來代替“實際”對象的對象。而Java的動態代理比代理的思想更向前邁進了一步,因爲它可以動態地創建代理並動態地處理對所代理方法的調用。在動態代理上所做的所有調用都會被重定向到單一的調用處理器上,它的工作是揭示調用的類型並確定相應的對策。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface AbstractSubject
{
	public void fun1();

	public void fun2();
}

class RealSubject implements AbstractSubject
{
	public void fun1()
	{
		System.out.println("fun1 invoked!");
	}

	public void fun2()
	{
		System.out.println("fun2 invoked!");
	}
}

/**
 * 代理的調用處理器
 */
class DynamicProxyHandler implements InvocationHandler
{
	private AbstractSubject proxied;

	//傳入需要被代理的對象
	public DynamicProxyHandler(AbstractSubject proxied)
	{
		this.proxied = proxied;
	}

	//將方法的調用重定向到被代理的對象,同時增加額外操作
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable
	{
		System.out.print("From Proxy : ");
		return method.invoke(proxied, args);
	}
}

public class DynamicProxy
{
	public static void main(String[] args)
	{
		RealSubject subject = new RealSubject();
		DynamicProxyHandler proxyHandler = new DynamicProxyHandler(subject);

		//使用Proxy類的newProxyinstance方法生成代理對象
		//需要傳入被代理對象的類加載器,實現的接口和對應的調用處理器
		AbstractSubject proxy = (AbstractSubject) Proxy.newProxyInstance(subject
				.getClass().getClassLoader(), subject.getClass().getInterfaces(),
				proxyHandler);
		
		//直接調用
		subject.fun1();
		subject.fun2();
		
		//代理調用
		proxy.fun1();
		proxy.fun2();
	}
}

 

輸出

fun1 invoked!
fun2 invoked!
From Proxy : fun1 invoked!
From Proxy : fun2 invoked!

 

六、空對象

      在Java中,當使用內置的null表示缺少對象或者空對象時,在每次使用引用的時候都必須測試其是否爲null,否則有可能拋出NullPointerException。這個時候引入“空對象”的思想將會很有用,“空對象”代表這樣一些類和對象,它們並無意義,但是能代替null來表示空的對象,從而避免使用null。有了“空對象”,我們很很多情況下能把它們當作正常類來處理,只是使用這些“空對象”時會產生代表“空”的效果。

import java.util.ArrayList;

/*
 * 代表“空”的標誌接口
 */
interface Null{}

/*
 * 代表一個具體的人
 */
class Person
{
	public final String name;
	public final String gender;
	
	public Person(String name, String gender)
	{
		this.name = name;
		this.gender = gender;
	}
	
	public String toString()
	{
		return "name:" + name + ", gender:" + gender;
	}
}

/*
 * 代表“沒有人”的空對象
 * 使用單例模式,因爲NullPerson一一致的,是通用的
 */
class NullPerson extends Person implements Null
{
	private static NullPerson nullPerson = new NullPerson();
	
	private NullPerson()
	{
		super("NONE", "NONE");
	}
	
	public static NullPerson getNullPerson()
	{
		return nullPerson;
	}
}

/*
 * 代表職位的類,包含職位名稱和對應的人
 */
class Position
{
	private String position;
	private Person person;
	
	public Position(String position, Person person)
	{
		this.position = position;
		this.person = person;
	}
	
	public String toString()
	{
		return position + " --- " + person;
	}
}

public class NullTest
{
	public static void main(String[] args)
	{
		//代表某公司職位信息的List
		ArrayList<Position> companyPosition = new ArrayList<Position>();
		
		//往List中加入職位,當某個職位空缺時,該職位的人用“空對象”表示
		companyPosition.add(new Position("CEO", new Person("Ben", "male")));
		companyPosition.add(new Position("Software Engineer", new Person("George", "male")));
		companyPosition.add(new Position("Hardware Engineer", NullPerson.getNullPerson()));
		companyPosition.add(new Position("Dedigner", new Person("Tracy", "female")));
		
		//可以把所有元素當作正常的Person處理而不用擔心因爲null帶來的異常或類型檢測
		for(Position p : companyPosition)
		{
			System.out.println(p);
		}
	}
}

 輸出:

CEO --- name:Ben, gender:male
Software Engineer --- name:George, gender:male
Hardware Engineer --- name:NONE, gender:NONE
Dedigner --- name:Tracy, gender:female
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章