PowerPoint 簡報

Download Report

Transcript PowerPoint 簡報

Reflection & Generics in JDK1.5
侯捷 / J.J. Hou
資訊教育 / 專欄執筆 / 大學教師
[email protected], http://www.jjhou.com
Generics
講題提要.Generics
自JDK1.3起,Generics 技術以各種外掛方式
進入Java。JDK1.5正式內建此一技術,對
Java 及其 Library 帶來全面的影響與改寫。
本講題追蹤該技術全面進入 JDK1.5 的狀
況。
2004 Java2 專業技術大會
Reflection
講題提要.Reflection
Reflection 為 Java 帶入靜態語言難以企及的
動態應用,廣為人知者便是Componentbased programming(例如Javabean)開發環境,
deSerialization, 以及RMI(Remote Method Invocation)。本
講題說明 Reflection 基本觀念及 APIs 運
用。
2004 Java2 專業技術大會
Generics
同質(homogenous)容器與異質(heterogenous) 容器
同質容器:元素型別必須相同。
C++ STL 的容器都是同質容器。
list<int> myList;
myList.push_back(3);
編譯器建立 int版-list
元素型別是Object
異質容器:元素型別可以不同。
Java Collections 都是異質容器。
LinkedList myList = new LinkedList();
myList.add(new Double(4.4));
myList.add(new String("jjhou"));
2004 Java2 專業技術大會
Generics
同質容器 in Java
Java 借鑑 C++ 語彙符號 "< >",建立同質容
器,是謂 Generics in Java:
LinkedList<Integer> myList =
new LinkedList<Integer>();
myList.add(new Integer(4));
myList.add(new Integer(7));
myList.add(new String("hello")); //Error!
2004 Java2 專業技術大會
Generics
同質容器與多型(Polymorphism)應用
Java Collections 原就充份運用多型:
相當於LinkedList
LinkedList<Object> myList
= new LinkedList<Object>();
Object
5
11
55
Stroke
Rect
Circle
18
22
66
w:Integer
ia:ArrayList
<Integer>
l:Integer
t:Integer
w:Integer
h:Integer
x:Integer
y:Integer
r:Integer
2b
33
77
18
2c
18
2c
2004 Java2 專業技術大會
44
Rect
Stroke
Circle
Generics
同質容器與多型(Polymorphism)應用
為更好地運用多型,可這麼寫:
LinkedList<Shape> myList
= new LinkedList<Shape>();
Object
Shape
Stroke
w:Integer
ia:ArrayList
<Integer>
Rect
l:Integer
t:Integer
w:Integer
h:Integer
5
11
55
18
22
66
2b
33
77
Circle
18
x:Integer
y:Integer
r:Integer
2c
18
2c
2004 Java2 專業技術大會
44
Rect
Stroke
Circle
Generics
加入 Generics 之前
Java 為保持語言的簡單性,強迫程式員
在使用 Collections 時必須記住所擁有的元
素型別;取出元素並進一步處理前,
必須先轉型,從 Object 轉為實際型
別。
LinkedList myList = new LinkedList();
myList.add(new Integer(0));
myList.add(new Integer(1));
Integer tempi = (Integer)myList.iterator().next();
2004 Java2 專業技術大會
Generics
加入 Generics 之後
如果以generic types擴充 Java 語言,就能以
更直接的方式表現 collection 的相關資
訊,於是編譯器可追蹤記錄實際的元
素型別,您也就不再需要轉型。有助
於程式的開發與除錯。
LinkedList<Integer> iList = new LinkedList<Integer>();
iList.add(new Integer(0));
iList.add(new Integer(1));
Integer tempi = iList.iterator().next();
2004 Java2 專業技術大會
Generics
Java/C++泛型技術的根本差異
C++
list
template <typename T,...>
class list { ... };
膨脹法
#include <list>
list<int> li;
list<string> ls;
list<double> ld;
class list;
// int版本
class list;
// string版本
class list;
// double版本
.exe
list<int> li;
list<string> ls;
list<double> ld;
Java
java.util.LinkedList.java
public class LinkedList<E>
{ ... };
擦拭法
import java.util.*
LinkedList<Integer> ...;
LinkedList<String> ...;
LinkedList<Double> ...;
2004 Java2 專業技術大會
public class LinkedList
{ ... };
.class
import java.util.*
LinkedList ...;
LinkedList ...;
LinkedList ...;
.class
Generics
Generics Java技術發展歷程
GJ安裝後的路徑
●
JDK1.3 + GJ (a Generic Java language extension)
以預處理器(%GJClasses%\gjc.Main)+翻新的Collections
(%GJClasses%\*.class)提供GP。
● JDK1.4+JSR14 (Adding Generics to Java Language)
以編譯器套件(%JSR14DISTR%\javac.jar)+翻新的Collections
(%JSR14DISTR%\collect.jar)提供GP。
●
JDK1.5
JSR14安裝後的路徑
內建所有必要的GP服務。Java Library全面翻新。
2004 Java2 專業技術大會
Generics
學習與觀察Java Generics
運用Generic Classes
例如 java.util (collections)
● 運用Generic Algorithms (methods)
例如 methods in java.util.Collection
● 撰寫Generic Classes
● 撰寫Generic Algorithms (methods)
●
2004 Java2 專業技術大會
Generics
在JDK1.5中運用
Generic Classes/Algorithms
ArrayList<String> strList =
new ArrayList<String>();
strList.add("zero");
strList.add("one");
strList.add("two");
strList.add("five");
System.out.println(strList);
// [zero, one, two, five]
String str = Collections.max(strList);
Collections.sort(strList);
static methods
2004 Java2 專業技術大會
Generics
Boxing & UnBoxing 的影響
容器元素必須是 object(不可為純數值)
LinkedList<Integer> iList =
new LinkedList<Integer>();
iList.add(new Integer(0));
iList.add(new Integer(1));
iList.add(new Integer(5));
iList.add(new Integer(2));
LinkedList<Integer> iList =
new LinkedList<Integer>();
iList.add(0);
//boxing
iList.add(1);
iList.add(5);
iList.add(2);
int i = iList.get(2); //un-boxing
2004 Java2 專業技術大會
Generics
觀摩 JDK1.5, java.util.Map
public interface Map<K,V> {
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> t);
interface Entry<K,V> { … }
...
}
2004 Java2 專業技術大會
Generics
觀摩 JDK1.4, java.util.Map
public interface Map {
Object get(Object key);
Object put(Object key, Object value);
Object remove(Object key);
void putAll(Map t);
interface Entry { … }
...
}
2004 Java2 專業技術大會
Generics
觀摩 JDK1.5, java.util.ArrayList
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable,
java.io.Serializable
{
private transient E[] elementData;
private int size;
public ArrayList(Collection<? extends E> c) {
size = c.size();
// Allow 10% room for growth
elementData = (E[])new Object[
(int)Math.min((size*110L)/100,
Integer.MAX_VALUE)];
c.toArray(elementData);
}
...
2004 Java2 專業技術大會
Generics
觀摩 JDK1.4, java.util.ArrayList
public class ArrayList
extends AbstractList
implements List, RandomAccess, Cloneable,
java.io.Serializable
{
private transient Object elementData[];
private int size;
public ArrayList(Collection c) {
size = c.size();
// Allow 10% room for growth
elementData = new Object[
(int)Math.min((size*110L)/100,
Integer.MAX_VALUE)];
c.toArray(elementData);
}
...
2004 Java2 專業技術大會
Generics
在JDK1.5中撰寫Generic Classes
LinkedList<Shape> sList = new LinkedList<Shape>();
sList.add(new Stroke<Integer,Integer>(…));
sList.add(new Rect<Integer>(…));
sList.add(new Circle<Integer>(…));
Object
LinkedList<Shape> sList
= new LinkedList<Shape>();
Shape
draw()
len()
compareTo()
W,T
Stroke
w:T
a:ArrayList<T>
T
Rect
l:T
t:T
w:T
h:T
T
5
11
55
18
22
66
2b
33
77
Circle
18
x:T
y:T
r:T
2c
18
2c
2004 Java2 專業技術大會
Circle<Integer>
44
Rect<Integer>
Stroke<Integer,Integer>
Generics
在JDK1.5中撰寫Generic Classes
類似設計是 public final class Integer
extends Number implements Comparable<Integer>
為了可用於 max()
public abstract class Shape
implements Comparable<Shape>{
public abstract void draw();
典型的Template Method
public abstract double len();
public int compareTo(Shape o) {
只要 class 名稱加上 <>
即成為 generic class
return (this.len() < o.len() ?
-1 : (this.len() == o.len() ? 0 : 1));
}
public class Stroke<W,T>
}
extends Shape
implements Serializable {
W width;
實際計算長度時,
恐怕會遭遇麻煩 !
ArrayList<T> a;
public double len() { ... }
public void draw() { ... }
}2004 Java2 專業技術大會
Generics
在 JDK1.5 中撰寫 Generic Classes
只要 class 名稱之後加上 <>,即成為 generic class
類似的設計是 Class<T>
public class Rect<T>
extends Shape
implements Serializable {
T l,t,w,h;
public void draw() { ... }
public double len() { ... }
}
public class Circle<T>
extends Shape
implements Serializable {
T x,y,r;
public double len() { ... }
public void draw() { ... }
實際計算長度時,
恐怕會遭遇麻煩 !
}
2004 Java2 專業技術大會
Generics
在 JDK1.5 中撰寫 Generic Algorithms
只要 method 名稱之前加上 <>,
即成為 generic method
形式 (1)
// in someone class
public static <T>
T gMethod (List<T> list) { ... }
"bounded type parameter"
"受到更多約束" 的型別參數
形式 (2) public static <T extends Comparable<T>>
T gMethod (List<T> list) { ... }
JDK 1.5允許「不被method真正用到」
的型別參數以符號 '?' 表示
public static
形式 (3) {
return list;
}
List<?> gMethod (List<?> list)
// (本例)原封不動地傳回
2004 Java2 專業技術大會
Generics
觀摩 JDK1.4, java.util.Collections.max()
#001
#002
#003
#004
#005
#006
#007
#008
#009
#010
#011
#012
#013
#014
#015
#016
#017
public class Collections {
...
public static
//這裡刻意空一行,以利與JDK1.5源碼比較
Object max(Collection coll) {
Iterator i = coll.iterator();
Comparable candidate = (Comparable)(i.next());
while(i.hasNext()) {
Comparable next = (Comparable)(i.next());
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
...
} // of Collections
2004 Java2 專業技術大會
Generics
觀摩 JDK1.5, java.util.Collections.max()
#001 public class Collections {
#002 ...
#003
public static
#004
<T extends Object & Comparable<? super T>>
#005
T max(Collection<? extends T> coll) {
#006
Iterator<? extends T> i = coll.iterator();
#007
T candidate = i.next();
#008
#009
while(i.hasNext()) {
#010
T next = i.next();
#011
if (next.compareTo(candidate) > 0)
#012
candidate = next;
#013
}
#014
return candidate;
#015
}
#016
...
#017 } // of Collections
2004 Java2 專業技術大會
Generics
觀摩 JDK1.5, java.util.Collections.max()
3
4
5
<T extends Object & Comparable<? super T>>
T max(Collection<? extends T> coll) {
6
1
2
1. max() 將接收一個 Collection object
2. 該 Collection object 所含元素必須是 T-derived object
3. T 必須繼承自Object(這倒不必明說。Java必定如此)
4. T 必須實作 Comparable
5. Comparable 所比較的型別必須是 supertype of T
6. max() 傳回 T object
2004 Java2 專業技術大會
Reflection
所謂 Introspection (內省, 內觀, 反省)
看透("look inside")classes 的能力,我們稱之
為 introspection。或說 "the ability of the
program to examine itself"
Java有兩個作法可以進行 introspection:
(1) Static Introspection : .class file inspection
(2) Dynamic Introspection : Reflection API
2004 Java2 專業技術大會
Reflection
所謂 Reflection
Reflection 是 Java 被視為動態(或準動態)
語言的關鍵,允許程式於執行期透過
Reflection APIs 取得任何已知名稱之 class 的
內部資訊,包括 package、type parameters、
superclass、implemented interfaces、inner
classes, outer class, fields、constructors、
methods、modifiers,並可於執行期生成
instances、變更 fields 內容或喚起 methods。
2004 Java2 專業技術大會
Reflection
所謂 Reflection
對於每一個class,JRE都會維護一
個對應的不可改動的(immutable)
Class object,其中內含該class資
訊. Reflection APIs 便是從中取得
資訊
dynamic loading
by class loader
(a ClassLoader object)
virtual machine environment
Test class definition
(Class object for Test class)
Test.class
disk
2004 Java2 專業技術大會
Reflection
Reflection APIs
有了Reflection API,我們可以:
•決定(判斷)某個 object 所屬的 class.
•取得 class 的 modifiers, fields, methods, constructors, 和
superclasses 的相關資訊.
•找出 interface 中的 constants 和 method declarations.
•為一個執行期才得知名稱的 class 產生實體(物件).
•取得及設定 object's field 值, 即使執行前對它一無所知.
•喚起(invoke)object' method,即使執行期才得知它.
•產生一個新的 array, 其大小和元素型別 (component type) 在
執行之前未知。並可更動 array 的元素.
2004 Java2 專業技術大會
Reflection
Reflection APIs
Core Reflection API 容納兩類應用。第一類應用需要找出並使用某個 object
的 run-time class 的所有 public members。這些應用要求能夠於執行期存取
該 object 的所有 public fields, methods, constructors。例如 Java Beans 提供的
services,以及 lightweight tools 如 object inspectors。這些應用程式統是使用
Class 所提供的 methods: getField, getMethod, getConstructor, getFields,
getMethods, getConstructors 來獲得 classes Field, Method, Constructor 的
instances。
第二類應用很精巧,需要找出並使用被某個 class 宣告的 members。它們需
要能夠於執行期存取「由 class file 供應之 class 實作層級」。例如
development tools 如 interpreters, inspectors, 以及 class browsers, 以及 run-time
services 如 Java Object Serialization。這些應用使用 Class 所提供的 methods:
getDeclaredField, getDeclaredMethod, getDeclaredConstructor,
getDeclaredFields, getDeclaredMethods, getDeclaredConstructors 來獲得
classes Field, Method, Constructor 的 instances。
2004 Java2 專業技術大會
Reflection
Reflection APIs
Reflection API 由 java.lang.Class 和
java.lang.reflect classes: (1)Field, (2)Method,
(3)Constructor, (4)Array, (5)Modifier 組成。
前三者表現 classes / interfaces 的相應 (corresponding)
成員。Array 提供 methods 用來建立, 存取, 改
動 arrays。Modifier 提供 methods 對 modifiers (
如 static, public) 解碼(解釋)。
2004 Java2 專業技術大會
Reflection
Object class
java.lang.Object
java.lang.Class
Object class 是所有 Java classes 的 root。
public class Object {
public final native Class<? extends Object> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
public final void wait() throws InterruptedException;
protected void finalize() throws Throwable { }
}
2004 Java2 專業技術大會
Reflection
Class class
java.lang.Object
java.lang.Class
Class instance 所表現的,是執行中的 Java 程式內的 classes 和 interfaces。
enum, annotation, array, primitive Java types (boolean, byte, char, short, int, long,
float, double), 以及關鍵字 void 也都可被表現為 Class objects.
Class 並沒有 public constructor,其 objects 係當 classes 被載入或 class loader
的 defineClass() 被呼叫時,由 Java Virtual Machine 自動建構。
以下使用 Class object 列印某個 object 的 class 名稱:
void printClassName(Object obj) {
System.out.println("The class of " + obj + " is " + obj.getClass().getName());
}
也可對已知型別(或 void),根據其 class literal 取得 Class object,例如:
System.out.println("The name of class Foo is: "+Foo.class.getName());
2004 Java2 專業技術大會
Reflection
Class class
Class 並沒有 public constructor。其 objects 係當 classes 被載入
(loadClass(...))或 class loader 的 defineClass(...) 被呼叫時,由 Java
Virtual Machine 自動建構。因此,我可以(修改源碼後)測得某個
class 被載入,卻無法測得其對應之 Class object 的誕生。
public final
class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
private Class() {}
...
public String toString() {
return ( isInterface() ? "interface " :
(isPrimitive() ? "" : "class "))
+ getName();
}
2004 Java2 專業技術大會
Reflection
Class class
獲得 java.lang.Class objects 的各種辦法
From getClass().
String str = "abc";
Class c1 = str.getClass();
From the method Class.getSuperclass()
Button b = new Button();
Class c1 = b.getClass();
Class c2 = c1.getSuperclass();
BTW getSuperclass() returns null for the class Object.
From the static method Class.forName()
Class c1 = Class.forName ("java.lang.String");
Class c2 = Class.forName ("java.awt.Button");
Class c3 = Class.forName
("java.util.LinkedList$Entry");
Class c4 = Class.forName ("I");
Class c5 = Class.forName ("[I");
2004 Java2 專業技術大會
From the .class syntax
Class c1 = String.class;
Class c2 = java.awt.Button.class;
Class c3 = Main.InnerClass.class;
Class c4 = int.class;
Class c5 = int[].class;
From the primitive wrapper classes
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Character.TYPE;
Class c4 = Short.TYPE;
Class c5 = Integer.TYPE;
Class c6 = Long.TYPE;
Class c7 = Float.TYPE;
Class c8 = Double.TYPE;
Class c9 = Void.TYPE;
Reflection
ClassLoader class
所謂 class loader 是個 object,負責載入 classes。ClassLoader 是個 abstract class。給予它 class
名稱,class loader 便應該嘗試定位 (locate) 或生成 (generate) 某些資料,用以構成一個 class
definition。典型策略是將該名稱轉換為檔名,然後讀入對應的 "class file"。
每個 Class object 都內含一個 getClassLoader(), reference to「定義該 Class object」的那個
ClassLoader。
ClassLoader class 運用 delegation model 來搜尋 classes 和 resources。其每一個 instance 都有一
個 associated parent class loader。一旦請求搜尋一個 class 或 resource,ClassLoader instance 便
會將工作委託 (delegate) 給其 parent class loader,在企圖找到 class 或 resource 本身之前。
Virtual machine 的內建 class loader 稱為 bootstrap class loader,它本身沒有 parent,但也許用
做一個 ClassLoader instance 的 parent。
通常,Java virtual machine 以一種 platform-dependent 方式從 local file system 載入 classes。例
如在 UNIX 系統上,virtual machine 從環境變數 CLASSPATH 所定義的目錄中載入 classes 。
然而某些 classes 最初或許並非來自檔案,而是來自其他資源,像是網絡,或是被應用程式所
建構。method defineClass(String, byte[], int, int) 會轉換an array of bytes 成為一個 Class
instance。這種新定義出來的 class,可使用 Class.newInstance() 產生 instances。
2004 Java2 專業技術大會
Reflection
Class 涵蓋範圍(局部)
package java.util;
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Queue<E>,
Cloneable, java.io.Serializable
{
private static class Entry<E> { … }
1
Class methods
Package getPackage()
2
String getName()
3
4
5
6
public LinkedList() { … }
7
public LinkedList(Collection<? extends E> c) { … }
public E getFirst() { … }
public E getLast() { … }
8
private transient Entry<E> header = …;
private transient int size = 0;
9
}
2004 Java2 專業技術大會
TypeVariable<Class>[]
getTypeParameters()
Class getSuperClass()
Class[] getInterfaces()
Class[] getDeclaredClasses()
Class getDeclaringClass()
Consructor[]
getDeclaredConstructors()
Method[]
getDeclaredMethods()
Field[]
getDeclaredFields()
but 無法取得 import lib...
Reflection
小工具 tName()
static String tName(String nm, Hashtable ht) {
String yy;
nm (fully qualified name)
String arr;
yy (class name part)
java.lang.Integer
if (nm.charAt(0) != '[') {
int i = nm.lastIndexOf(".");
if (i == -1)
return nm; // primitive type, ignore it.
else {
yy = nm.substring(i+1);
if (ht != null)
ht.put(nm, yy);
return yy;
}
}
...
2004 Java2 專業技術大會
lastIndexOf(".")
key
Integer
value
java.lang.Integer
這樣是一個 Hashtable 元素
Reflection
取得 package
1
Package getPackage()
package java.util;
Class c = null;
c = Class.forName(args[0]);
Package p;
p = c.getPackage();
if (p != null)
System.out.println("package "+p.getName()+";");
package java.util;
2004 Java2 專業技術大會
Reflection
取得完整的 import list
Constructor cn[];
Method mm[];
Field ff[];
(1)取得所有fields,將其type記錄於hashtable
ff = c.getDeclaredFields();
for (int i = 0; i < ff.length; i++)
x = tName(ff[i].getType().getName(), classRef);
(2)取得所有ctors,將其parameters type
cn = c.getDeclaredConstructors();
for (int i = 0; i < cn.length; i++) { 記錄於hashtable
Class cx[] = cn[i].getParameterTypes();
for (int j = 0; j < cx.length; j++)
x = tName(cx[j].getName(), classRef);
}
(3)取得所有methods,將其return/parameters type
mm = c.getDeclaredMethods();
記錄於hashtable
for (int i = 0; i < mm.length; i++) {
x = tName(mm[i].getReturnType().getName(), classRef);
Class cx[] = mm[i].getParameterTypes();
for (int j = 0; j < cx.length; j++)
x = tName(cx[j].getName(), classRef);
}
classRef.remove(c.getName()); (4)從hashtable中移除自己
2004 Java2 專業技術大會
Reflection
取得完整的 import list
import java.lang.Object;
import java.util.Collection;
import java.util.Set;
import java.util.ListIterator;
import java.lang.Object;
import java.util.LinkedList$Entry;
import java.util.Collection;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
2004 Java2 專業技術大會
Reflection
取得 class name 及 modifier
2
String getName()
public class LinkedList<E>
public final class Class
public class LinkedList
public abstract interface Map
c = Class.forName(args[0]);
int mod = c.getModifiers();
System.out.print(Modifier.toString(mod)); //整個modifier
if (Modifier.isInterface(mod))
System.out.print(" ");
//"interface" 已含於modifier
else
System.out.print(" class ");
//關鍵字 "class"
System.out.print(tName(c.getName(), null)); //class名稱
2004 Java2 專業技術大會
Reflection
取得 Type Parameters
package java.util
public class LinkedList<E>
3
TypeVariable<Class>[]
getTypeParameters()
TypeVariable<Class>[] tv;
tv = c.getTypeParameters(); //warning: unchecked conversion
for (int i = 0; i < tv.length; i++) {
x = tName(tv[i].getName(), null); //例如 E,K,V...
if (i == 0)
//第一個
System.out.print("<" + x);
else
//非第一個
System.out.print("," + x);
if (i == tv.length-1) //最後一個
System.out.println(">");
public class LinkedList<E>
}
public abstract interface Map<K,V>
2004 Java2 專業技術大會
Reflection
取得 Super Class
Class getSuperClass()
public class LinkedList<E>
extends AbstractSequentialList<E>
4
Class supClass;
supClass = c.getSuperclass();
if (supClass != null)
//如果有super class
System.out.print(" extends" +
tName(supClass.getName(),classRef));
public class LinkedList<E>
extends AbstractSequentialList,
implements List, Queue, Cloneable, Serializable, {
2004 Java2 專業技術大會
Reflection
取得 Implemented Interfaces
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Queue<E>,
Cloneable, java.io.Serializable
5
Class[] getInterfaces()
public class LinkedList<E>
extends AbstractSequentialList,
implements List, Queue, Cloneable, Serializable, {
Class cc[];
Class ctmp;
//找出所有被實現的interfaces
JDK1.5, for loop 新語法
cc = c.getInterfaces();
if (cc.length != 0)
System.out.print(", \r\n" + " implements ");
for (Class cite : cc)
System.out.print(tName(cite.getName(), null)+", ");
2004 Java2 專業技術大會
Reflection
取得 DeclaredClasses (inner classes)
和 DeclaringClass (outer class)
public class LinkedList<E> ...
{
private static class Entry<E> { … }
6
Class[] getDeclaredClasses()
Class getDeclaringClass()
class name: LinkedList$Entry
LinkedList$Entry
LinkedList$ListItr
//找出inner classes
Map$Entry
cc = c.getDeclaredClasses();
for (Class cite : cc)
System.out.println(tName(cite.getName(), null));
ctmp = c.getDeclaringClass(); //找出outer classes
if (ctmp != null)
System.out.println(ctmp.getName());
2004 Java2 專業技術大會
Reflection
取得 Declared Constructors (1)
public class LinkedList<E> ...
{
7
public LinkedList() { … }
public LinkedList(Collection<? extends E> c) { … }
2004 Java2 專業技術大會
Consructor[]
getDeclaredConstructors()
Reflection
取得 Declared Constructors (2)
public java.util.LinkedList(Collection)
G: public java.util.LinkedList(java.util.Collection<? extends E>)
public java.util.LinkedList()
G: public java.util.LinkedList()
Constructor cn[];
cn = c.getDeclaredConstructors();
for (int i = 0; i < cn.length; i++) {
int md = cn[i].getModifiers();
System.out.print(" " + Modifier.toString(md) + " " +
cn[i].getName());
Class cx[] = cn[i].getParameterTypes();
System.out.print("(");
for (int j = 0; j < cx.length; j++) {
System.out.print(tName(cx[j].getName(), null));
if (j < (cx.length - 1)) System.out.print(", ");
}
System.out.print(")");
System.out.println("G: " + cn[i].toGenericString());
}
2004 Java2 專業技術大會
Reflection
取得 Declared Methods (1)
public class LinkedList<E> ...
{
public E getFirst() { … }
public E getLast() { … }
8
2004 Java2 專業技術大會
Method[]
getDeclaredMethods()
Reflection
取得 Declared Methods (2)
public Object get(int)
G: public E java.util.LinkedList.get(int)
public int size()
G: public int java.util.LinkedList.size()
Method mm[];
mm = c.getDeclaredMethods();
for (int i = 0; i < mm.length; i++) {
int md = mm[i].getModifiers();
System.out.print("
"+Modifier.toString(md)+" "+
tName(mm[i].getReturnType().getName(), null)+" "+
mm[i].getName());
Class cx[] = mm[i].getParameterTypes();
System.out.print("(");
for (int j = 0; j < cx.length; j++) {
System.out.print(tName(cx[j].getName(), null));
if (j < (cx.length - 1)) System.out.print(", ");
}
System.out.print(")");
System.out.println("G: " + mm[i].toGenericString());
}
2004 Java2 專業技術大會
Reflection
取得 Declared Fields (1)
public class LinkedList<E> ...
{
private transient Entry<E> header = …;
private transient int size = 0;
}
2004 Java2 專業技術大會
9
Field[]
getDeclaredFields()
Reflection
取得 Declared Fields (2)
private transient LinkedList$Entry header;
G: private transient java.util.LinkedList.java.util.LinkedList$Entry<E> java.util.LinkedList.header
private transient int size;
G: private transient int java.util.LinkedList.size
Field ff[];
ff = c.getDeclaredFields();
for (int i = 0; i < ff.length; i++) {
int md = ff[i].getModifiers();
System.out.println("
"+Modifier.toString(md)+" "+
tName(ff[i].getType().getName(), null) +" "+
ff[i].getName()+";");
System.out.println("G: " + ff[i].toGenericString());
}
2004 Java2 專業技術大會
Reflection
動態生成 object
(class name於執行期才得知)
1. 建構時 no argument
Class c = Class.forName("DynTest");
Object obj = null;
obj = c.newInstance(); //不帶引數
System.out.println(obj);
2. 建構時 with arguments
Class c = Class.forName("DynTest");
Class[] pTypes = new Class[] { double.class, int.class };
Constructor ctor = c.getConstructor(pTypes);
//指定parameter list,便可獲得特定之ctor
Object obj = null;
Object[] arg = new Object[] {3.14159, 125}; //引數
obj = ctor.newInstance(arg);
System.out.println(obj);
2004 Java2 專業技術大會
Reflection
取得/設定 object's fields 內容
(field's name於執行期才得知)
1. 首先產生 "field 所屬 class" 的一個
Class object c。
2. 呼叫 c.getField(_) 製造出一個 Field
object f。必須餵以 field name。
3. 視需要呼叫 (Type)f.get(obj) 或
f.set(obj, newValue)。呼叫時必須餵以
calling obj(和 newValue)。
2004 Java2 專業技術大會
Reflection
取得/設定 object's fields 內容
(field's name於執行期才得知)
public class Test {
public double d;
Test.class
public static void main(String args[])
{
1 Class c = Class.forName("Test");
2 Field f = c.getField("d");
Test obj = new Test();
System.out.println("d= " + (Double)f.get(obj));
3 f.set(obj, 12.34);
System.out.println("d= " + obj.d);
}
}
2004 Java2 專業技術大會
喚起 object's methods
(method's name於執行期才得知)
1. 首先產生 "method 所屬 class" 的一個
Class object c。
2. 呼叫 c.getMethod(_,_) 製造出一個
Method object m。必須餵以 signature
(method name & parameters list) 。
3. 呼叫 m.invoke(_,_),必須餵以一個
calling object 和一個 arguments list.
2004 Java2 專業技術大會
喚起 object's methods (例1)
Test.class
public int add(int a, int b)
{
return a + b;
Test obj = new Test();
}
obj.add(37, 47)
public static void main(String args[])
{
1 Class c = Class.forName("Test");
Class ptypes[] = new Class[2];
ptypes[0] = Integer.TYPE;
ptypes[1] = Integer.TYPE;
知道signature就可做出Method object
2 Method m = c.getMethod("add",ptypes);
Test obj = new Test();
add(int a, int b)
Object args[] = new Object[2];
arg[0] = new Integer(37);
arg[1] = new Integer(47);
3 Object r = m.invoke(obj, arg);
呼叫 Method::invoke(x,x),
Integer rval = (Integer)r;
給予 calling object 和
System.out.println(rval.intValue());
argument list. (Object[ ]),
}
獲得 Object.
2004 Java2 專業技術大會
喚起 object's methods (例2)
Test.class
public String func(String s, Hashtable ht)
{
System.out.println("func invoked"); return Test
s; obj = new Test();
}
obj.tName("Hello", null)
public static void main(String args[])
{
1 Class c = Class.forName("Test");
Class ptypes[] = new Class[2];
ptypes[0] = Class.forName("java.lang.String");
知道signature就可
做出Method object
ptypes[1] = Class.forName("java.util.Hashtable");
2 Method m = c.getMethod("func",ptypes);
Test obj = new Test();
tName(String s, Hashtable ht)
Object args[] = new Object[2];
arg[0] = new String("Hello,world");
arg[1] = null;
3 Object r = m.invoke(obj, arg);
呼叫 Method::invoke(x,x),
Integer rval = (String)r;
給予 calling object 和
System.out.println(rval);
argument list. (Object[ ]),
}
獲得 Object.
2004 Java2 專業技術大會
本例使用之 Reflection APIs
Class class:
forName
getName
getDeclaredFields
getDeclaredMethods
getDeclaredConstructors
getDeclaredClasses
getDeclaringClass
getModifiers
getSuperClass
getGenericInterfaces
getGenericSuperclass
getInterfaces
getPackage
isArray
isEnum
isPrimitive
isSynthetic
isAnnotation
isInterface
getTypeParameters
newInstance
Method class:
getName
getParameterTypes
getReturnType
getModifiers
toGenericString
invoke
Field class:
getName
getType
getModifiers
getxxx
setxxx
toGenericString
Modifier class:
IsInterface
Isxxx
toString
Type class:
Constructor class:
[empty]
getName
getParameterTypes
getModifiers
toGenericString
Package class:
getName
TypeVariable class:
getName
getGenericDeclaration
2004 Java2 專業技術大會
Java Library源碼修改經驗
c:\jdk150\src\java\lang\Class.java
↑這是待改源碼(備份為宜)。修改後編譯獲得*.class。
c:\jdk150\jre\lib\rt.jar
↑這是Java Library classes(過程中不受影響)
c:\somewhere\Test.java
↑這是測試程式
c:\jdk150\jre\lib\endorsed
↑這是新增目錄,classloader 將優先從這兒讀取.jar。將*.class
搬移到e:\java\lang,壓縮為foo.jar(或.zip。任意命名。需夾
帶路徑例如java\lang),再將foo.jar 搬至endorsed目錄下,於
是測試程式便可正確用到修改後的classes
2004 Java2 專業技術大會
Java Library源碼修改經驗
rem "rejava.bat" usage :
rem (1) enter the directory which you want to rewrite java source.
rem (2) backup the original java source "x.java" to "x.java.ori".
rem (3) modify java source.
rem (4) rejava path filename (no extension name)
rem
ex: rejava javax\swing\text GapContent
jj-java.jar
jj-javax.jar
del c:\jdk150\jre\lib\endorsed\jj-javax.jar
del c:\jdk150\jre\lib\endorsed\jj-java.jar
javac %2.java
move *.class e:\%1
e:
cd e:\
jar cvfM c:\jdk150\jre\lib\endorsed\jj-javax.jar javax
jar cvfM c:\jdk150\jre\lib\endorsed\jj-java.jar java
dir e:\%1
dir c:\jdk150\jre\lib\endorsed
c:
把修改後的.java 編譯為.class,
壓縮為 xxx.jar(需帶路徑例如 java\lang)並
搬移到endorsed,
即可被class loader優先讀取。
2004 Java2 專業技術大會
更多資訊
"Java泛型技術之發展"
http://www.jjhou.com/javatwo-2002.htm
本講題三個範例程式
http://www.jjhou.com/javatwo-2004-reflection-and-generics-in-jdk15-sample.zip
《Java Reflection in Action》, by Ira R. Forman and Nate
Forman
Manning Publications Co.
http://www.manning.com/catalog/view.php?book=forman
"Take an in-depth look at the Java Reflection API"
-- Learn about the new Java 1.1 tools for finding out information about classes
http://www.javaworld.com/javaworld/jw-09-1997/jw-09-indepth.html
"Take a look inside Java classes"
-- Learn to deduce properties2004
ofJava2
a Java
class from inside a Java program
專業技術大會
2004 Java2 專業技術大會