jdk1.5新特性

http://docs.oracle.com/javase/

http://docs.oracle.com/javase/1.5.0/docs/guide/language/index.html


Generics
Enhanced for Loop
Autoboxing/Unboxing
Typesafe Enums
Varargs
Static Import
Metadata (Annotations)


一、Generics

一點感悟:泛型類就是模板類,泛型方法就是模板方法;如果使用泛型,代碼在編譯時沒有警告和報錯,運行時不會出現ClassCastException;

幾個術語:

generic class:泛型類

generic method:泛型方法

type parameters :類型參數或類型變量(Pair<T>中T就是類型參數)

parameterized type:參數化類型 (Pair<String>整個),泛型類和泛型接口

wildcard type: 通配符類型

類型變量的限定或邊界

raw type:原始類型

erased:擦除

supertype bound:超類型限定

1.泛型類

public class Pair<T>
{
//構造器名不需要加泛型
public Pair(){first = null;second = null;}
public Pair(T first,T second){this.first = first;this.second = second}
public T getFirst(){return first;}
public T getSecond(){return second;}

public void setFirst(T newValue){ first = new Value;}
public void setSecond(T newValue){second=newValue;}

private T first;
private T second;
}


注意點:

a. 泛型類可以有多個類型變量,如Pair<T,U>,用逗號分隔多個類型變量

b.類型變量使用大寫形式,且比較短。使用變量E表示集合的元素類型,使用K表示key,使用V表示value。T和其臨近的U、S表示“任意類型”

c.類和接口中的類型形參,只有在定義類、接口時纔可以使用類型形參,當使用類、接口時應爲類型參數傳入實際的類型;

eg:

public interface BaseDao<T> {}

public class BaseDaoImpl<T> implements BaseDao<T> {

public interface CustomerDao extends BaseDao<Customer> {}

public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao {}


2.泛型方法:

public static <E> void swap(E[] a,int i, int j){
E temp = a[i];
a[i] = a[i];
a[j] = temp;
}

注意點:

a.類型變量放在修飾符的後面,返回值的前面;

b.泛型方法可以定義在普通類中,也可以定義在泛型類中;

c.當調用一個泛型方法時,在方法名前,對象或類“.”引用之後的尖括號中放入具體類型;不過大部分時候可以省略,編譯器可根據傳入方法的參數判斷類型;

d.當方法的一個或多個參數之間存在依賴關係,或者方法返回值與參數之間存在依賴關係時,這時候可以使用泛型方法;

3.類型變量的限定:

a.一個類型變量或通配符可以有多個限定,多個限定類型之間用“&”分隔

eg:T extends Comparable & Serializable

b.限定中可以有多個接口,但最多有一個類,且若有類限定時,它必須是限定列表中的第一個

c.爲了提高效率,應該將標籤(tagging)接口(即沒有方法的接口)放在邊界列表的末尾;


4.類型擦除:

虛擬機中沒有泛型,只有普通的類和方法;虛擬機中,所有類型參數都用他們的第一個限定類型替換;沒有限定的類型變量用Object替換。這一過程就是“類型擦除”;

5.泛型的約束和限制:

a.不能用基本類型實例化類型參數;

b.類型查詢只產生原始類型;

eg:if(a instanceof Pair<String>) 等價於 if(a instanceof Pair)

eg2: 

Pair<String> strPair= ...
Pair<Employ> employPair=...
if(strPair.getClass()==employPair.getClass()){//這個條件return true
}


c.不能拋出也不能捕獲泛型類實例,但在異常聲明中可以使用類型變量;

正確例子:

public static <T extends Throwable> void doWork(T t) throws T//OK{
try{
}catch(Throwable realCause){
t.initCause(realCause);
throw t;
}
}



d:不能聲明參數化類型的數組

e:不能實例化類型變量

f:禁止使用帶有類型變量的靜態域和方法

eg:

static T getInstance(); //error

static T instance;//error

g:禁止一個類或類型變量不能同時成爲兩個接口類型(這兩個接口是同一接口的不同參數化)的子類;

h:定義泛型方法時,注意考慮方法擦除後,是否與已有方法重複;

L:S extends T ,但Pare<S>與Pare<T>沒有繼承關係;類型變量之間是否存在繼承關係,與參數化類之間的繼承關係無關;


5.通配符類型

Pair<? extends Employee>

6.通配符的超類型限定

Pair<? super Manager>

帶有超類型限定的通配符可以向泛型對象寫入,帶有子類型限定的通配符可以從泛型對象讀取。

? super Manager這樣的帶有上邊界的類型變量可以作爲方法參數,但不能作爲方法的返回值;

7.無限定通配符

Pair<?>:問號表示未知的任意類型,Pair<?>只可以作爲方法參數使用,不可以用來extends和implements;

Pair<?>只能調Pair的get方法;

List<?>中的元素爲Object類型;

8.通配符不是類型變量,不可以作爲返回值類型:? t= p.getFirst();//Error

9.Class類是泛型的,String.classs實際是一個Class<String>類的對象;

10.泛型的反射:

Type接口(表達泛型類型)

Class類 implements Type(具體類型)

TypeVariable接口(類型變量:T extends Comparable<? super T>)extends type

WildcardType接口(通配符:? super T)extends type

ParameterizedType接口(泛型類和泛型接口:Comparable<? super T>)extends type

GenericArrayType接口(泛型數組:T[])extends type

=========================

metadata annotation

=========================

Metadata (Annotations)
術語:
APT:annotation processing tool  訪問和處理annotation的工具
annotation:註解
meta annotation元註解:@Target和@Retention是元註解,用在註解的定義中
marked annotation標識註解:
single value annotation單值註解:

一、最常見的三個Annotation:
1.@Override:

檢查該方法是否覆蓋了某一個超類方法


package java.lang;
import java.lang.annotation.*;
/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a superclass.  If a method is annotated with
 * this annotation type but does not override a superclass method,
 * compilers are required to generate an error message.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}




說明:
@Override這個註解的作用是告訴編譯器檢查這個方法,
並從父類中查找是否包含一個被該方法重寫的方法,否則編譯器報錯;

這個Annotation的作用是爲了避免重寫父類方法時,沒有正確覆蓋,但編譯期並不拋錯這種情況;

2.@Deprecated:
標記爲已過時

package java.lang;
import java.lang.annotation.*;

/**
 * A program element annotated @Deprecated is one that programmers
 * are discouraged from using, typically because it is dangerous,
 * or because a better alternative exists.  Compilers warn when a
 * deprecated program element is used or overridden in non-deprecated code.
 *
 * @author  Neal Gafter
 * @version 1.5, 11/17/05
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}




說明:
@Deprecated表示某個程序元素(接口、類、方法等)已過時,當其它程序使用已過時的類時,編譯器將會給出警告;

3.@SuppressWarnings:
阻止某個給定類型的警告信息
eg:@SuppressWarnings("unchecked")

package java.lang;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import static java.lang.annotation.ElementType.*;
/**
 * Indicates that the named compiler warnings should be suppressed in the
 * annotated element (and in all program elements contained in the annotated
 * element).  Note that the set of warnings suppressed in a given element is
 * a superset of the warnings suppressed in all containing elements.  For
 * example, if you annotate a class to suppress one warning and annotate a
 * method to suppress another, both warnings will be suppressed in the method.
 *
 * <p>As a matter of style, programmers should always use this annotation
 * on the most deeply nested element where it is effective.  If you want to
 * suppress a warning in a particular method, you should annotate that
 * method rather than its class.
 *
 * @since 1.5
 * @author Josh Bloch
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p>Compiler vendors should document the warning names they support in
     * conjunction with this annotation type. They are encouraged to cooperate
     * to ensure that the same names work across multiple compilers.
     */
    String[] value();
}



說明:
@SuppressWarnings指示被annotation標識的程序元素(以及在該程序元素中的所有子元素)取消顯示指定的編譯器警告;
@SuppressWarnings會一直作用於該程序元素的所有子元素;例如使用@SuppressWarnings標識一個類來取消顯示某個編譯器警告,
同時又標識該類裏某個方法取消顯示另一個編譯器警告,那麼將在此方法中同時取消顯示這兩個編譯器警告;

通常,如果集合沒有使用泛型,編譯器會警告,這時可以用@SuppressWarnings;
二、自定義Annotation:

語法:
[修飾符] @interface [註解名稱]{
  [java類型] elementName();
  [java類型] elementName() default value;
}


使用時@AnnotationName(name1=value1,name2=value2,name3={arrayValue1,arrayValue2,...}...)

註解元素的類型:
基本類型、String、Class(具有一個可供選擇的類型參數,如Class<?>或Class<? extends MyClass>)、enum、註解、
由上述類型組成的數組;

下面的註解都位於java.lang.annotation包中;

1.@Target :

package java.lang.annotation;
/**
 * Indicates the kinds of program element to which an annotation type
 * is applicable.  If a Target meta-annotation is not present on an
 * annotation type declaration, the declared type may be used on any
 * program element.  If such a meta-annotation is present, the compiler
 * will enforce the specified usage restriction.
 *
 * For example, this meta-annotation indicates that the declared type is
 * itself a meta-annotation type.  It can only be used on annotation type
 * declarations:
 * <pre>
 *    @Target(ElementType.ANNOTATION_TYPE)
 *    public @interface MetaAnnotationType {
 *        ... 
 *    }
 * </pre>
 * This meta-annotation indicates that the declared type is intended solely
 * for use as a member type in complex annotation type declarations.  It
 * cannot be used to annotate anything directly:
 * <pre>
 *    @Target({}) 
 *    public @interface MemberType {
 *        ...
 *    }
 * </pre>
 * It is a compile-time error for a single ElementType constant to
 * appear more than once in a Target annotation.  For example, the
 * following meta-annotation is illegal:
 * <pre>
 *    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
 *    public @interface Bogus {
 *        ...
 *    }
 * </pre>
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}



說明:
1.@Target元註解可以應用於一個註解,以限制該註解可以應用到哪些項上;

@Target註解的元素類型:
ElementType.ANNOTATION_TYPE:在註解這種類型上使用,Annotation type declaration;
ElementType.PACKAGE:在包上使用,Package declaration
ElementType.LOCAL_VARIABLE:在局部變量上使用,Local variable declaration
ElementType.CONSTRUCTOR:在構造器上使用,Constructor declaration
ElementType.PARAMETER:在方法或構造器參數上使用,Parameter declaration
ElementType.METHOD:在方法上使用,Method declaration
ElementType.FIELD:在成員變量上使用,Field declaration (includes enum constants)
ElementType.TYPE:在類、接口、註解類、枚舉類上使用,Class, interface (including annotation type), or enum declaration 

一條沒有@Target的限制的註解可以應用於任何項上。
編譯器只檢查你是否將一條註解應用到了某個允許的的項上。

2.@Retention:

/**
 * Indicates how long annotations with the annotated type are to
 * be retained.  If no Retention annotation is present on
 * an annotation type declaration, the retention policy defaults to
 * <tt>RetentionPolicy.CLASS</tt>.
 *
 * <p>A Target meta-annotation has effect only if the meta-annotated
 * type is use directly for annotation.  It has no effect if the meta-annotated
 * type is used as a member type in another annotation type.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}



說明:
@Retention元註解用於指定一條註解應該保留多長時間。其默認值是RetentionPolicy.CLASS;
@Retention的保留策略:
RetentionPolicy.SOURCE:
     Annotations are to be discarded by the compiler.
     不被編譯器保留,源碼級別,未被包含在類文件中,無法反射訪問
RetentionPolicy.CLASS:
     Annotations are to be recorded in the class file by the compiler
     but need not be retained by the VM at run time.  This is the default
     behavior.
     保留到編譯期,類文件級別,編譯器會將他們置於類文件中
RetentionPolicy.RUNTIME:
     Annotations are to be recorded in the class file by the compiler and
     retained by the VM at run time, so they may be read reflectively.  
     保留到運行期,編譯器會將他們置於類文件中,並且虛擬機會將它們載入

3.enum ElementType:

public enum ElementType {   
    TYPE,   
    FIELD,   
    METHOD,   
    PARAMETER,   
    CONSTRUCTOR,   
    LOCAL_VARIABLE,   
    ANNOTATION_TYPE,  
    PACKAGE
}



4.enum RetentionPolicy:
public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}



5.@Documented

/**
 * Indicates that annotations with a type are to be documented by javadoc
 * and similar tools by default.  This type should be used to annotate the 
 * declarations of types whose annotations affect the use of annotated
 * elements by their clients.  If a type declaration is annotated with
 * Documented, its annotations become part of the public API
 * of the annotated elements.
 *
 * @author  Joshua Bloch
 * @version 1.6, 11/17/05
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}



說明:
@Documented元註解,被@Documented標識的註解,稱爲文檔化註解,當註解到目標上時,生成的文檔中將顯示註解信息;
即:被元註解@Documented修飾的Annotation類將被javadoc工具提取成文檔;

6.@Inherited:

只能應用於對類的註解,
如果一個類具有繼承註解,那麼這個類的所有子類都自動具有該註解;

/**
 * Indicates that an annotation type is automatically inherited.  If
 * an Inherited meta-annotation is present on an annotation type
 * declaration, and the user queries the annotation type on a class
 * declaration, and the class declaration has no annotation for this type,
 * then the class's superclass will automatically be queried for the
 * annotation type.  This process will be repeated until an annotation for this
 * type is found, or the top of the class hierarchy (Object)
 * is reached.  If no superclass has an annotation for this type, then
 * the query will indicate that the class in question has no such annotation.
 *
 * <p>Note that this meta-annotation type has no effect if the annotated
 * type is used to annotate anything other than a class.  Note also
 * that this meta-annotation only causes annotations to be inherited
 * from superclasses; annotations on implemented interfaces have no
 * effect.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}



三、註解的用途:
自動生成包含程序額外信息的“附文件”。
附屬文件的自動生成,例如部署描述符或者bean信息類;
測試、日誌、事務語義等代碼的自動生成;

四、注意點:
1.註解不會改變對編寫的程序的編譯方式。java編譯器對於包含註解和不包含註解的代碼會生成相同的虛擬機指令;
2.註解當做修飾符來使用,
3.Javadoc註解出現在/**..*/定界符的內部,而註解是代碼的一部分;
4.註解可用在方法、類、包、接口、成員變量、局部變量、構造器、枚舉類上;
5.註解可以放在修飾符所在的任意位置,但通常放在最前面並且置於上一行處;
6.@interface前只能有兩種修飾符,public或不加(即default),還有abstract
7.@interface隱式的實現了接口java.lang.annotation.Annotation;這個接口含有方法:equals、hashCode()、toString、 Class<? extends Annotation> annotationType(),java.lang.annotation.Annotation是正規接口,開發者不能擴展此接口;
8.註解接口中的元素的順序無關緊要;
9.如果使用註解時,某個元素的值並未指定,那麼就是用聲明的默認值;
10.簡化的形式:
如果沒有指定元素,要麼是因爲註解中沒有任何元素,要麼是因爲所有元素都是用默認值,那麼你就不需要使用括號了;這樣的註解叫“marked annotation”
11.單值註解:如果註解中只有一個元素,且元素名字是value;那麼在使用時,你可以不寫元素名和等號;
12.註解接口的元素聲明實際上就是方法的聲明,一個註解接口的方法可以沒有任何參數,沒有任何throws語句,並且他們也不能是泛型的;
13.一個註解元素不能設置爲null,默認值也不能設置爲null,但可以設置默認值爲Void.class
14.註解中可以修飾:
包、類(包括enum)、接口(包含註解接口)、方法、構造器、實例成員(包含enum常量)、本地變量、參數變量


對本地變量的註解只能在源碼級別上進行處理;
15.元註解:用於描述註解接口的行爲屬性;
16.要用反射處理的註解,應該定義爲@Retention(RetentionPolicy.RUNTIME)
17.@Retention(RetentionPolicy.SOURCE)表示:被修飾的註解僅在class文件中保留,運行時不能通過反射來讀取該註解的信息;

eg:
public @interface ActionListenerFor{
  String value();
}


使用時,@ActionListenerFor("redButton")

五、註解的解析:
1.運行時註解的解析:

接口:AnnotatedElement-->表示註解可標識的目標元素
其實現類有:
Class:類定義;
Contructor:構造器定義;
Field:類的成員變量的定義;
Method:類的方法的定義;
Package:類的包的定義;

public interface AnnotatedElement {
  //判斷該程序元素上是否包含指定的註釋,存在返回true,否則false
  boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
  //返回該程序元素上存在的、指定類型的註釋,如果該類型的註釋不存在,則返回null;
  <T extends Annotation> T getAnnotation(Class<T> annotationClass);
  //返回該程序元素上存在的所有註釋
  Annotation[] getAnnotations();
  
  Annotation[] getDeclaredAnnotations();
}



獲得某個類的某個方法的所有註解:
Annotation[] anns = Class.forName("XXXClass").getMethod("XXXMethod").getAnnotations();

2.源碼級註解的處理:
使用APT解析;
利用jdk下的tools.jar,它包含4個包:
com.sun.mirror.apt.*:和APT交互的接口
com.sun.mirror.declaration.*:包含各種封裝類成員、類方法、類聲明的接口;
com.sun.mirror.type.*:包含各種封裝源代碼中程序元素的接口

com.sun.mirror.util.*:提供了用於處理類型和聲明的一些工具;


也可利用doclet API(即Javadoc API),也位於tools.jar中

eg:

源碼級annotation:

package com.gavin.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface CodeTag {
	String authorName();
	String lastModificationDate();
	String bugfixes() default "";
}

應用此註解:

package com.gavin.annotation;
@CodeTag(authorName="gavin",lastModificationDate="Aug 16, 2003")
public class Test3 {
	@CodeTag(authorName="sophia",lastModificationDate="May 16, 2003",bugfixes="BUG0001")
	public void setName(){
		System.out.println("setName");
	}
	@CodeTag(authorName="alen",lastModificationDate="Mar 16, 2003",bugfixes="BUG0002")
	public void setCode(){
		System.out.println("setCode");
	}
}

利用doclet api分析Test3文件中的註解:

package com.gavin.annotation;

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doclet;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;

public class SourceTypeMetadataDoclet2 extends Doclet {
	public static boolean start(RootDoc root){
		ClassDoc[] classes = root.classes();
		for(ClassDoc cd : classes){
			showAnnotations(cd);
		}
		return true;
	}

	private static void showAnnotations(ClassDoc cd) {
		process(cd.annotations());
		for(MethodDoc md : cd.methods()){
			process(md.annotations());
		}
	}

	private static void process(AnnotationDesc[] annotations) {
		for(AnnotationDesc ad : annotations){
			AnnotationDesc.ElementValuePair evp[] = ad.elementValues();
			for(AnnotationDesc.ElementValuePair e :evp){
				System.out.println("name:"+e.element()+" ,value="+e.value());
			}
		}
	}
}

利用javadoc命令,運行結果:



3.字節碼級註解的處理

示例:

eg1:點擊面板中不同的按鈕切換不同的顏色:
package com.gavin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionListenerFor {
String source();
}

package com.gavin.annotation;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ButtonFrame extends JFrame{
JPanel panel = null;
JButton blueBtn = null;
JButton redBtn = null;
JButton yellowBtn = null;

public ButtonFrame(){
setTitle("ButtonTest");

panel = new JPanel();
add(panel);
yellowBtn = new JButton("yellow");
blueBtn = new JButton("blue");
redBtn = new JButton("red");

panel.add(yellowBtn);
panel.add(blueBtn);
panel.add(redBtn);

try {
ActionListenerInstaller.processAnnotations(this);
} catch (Exception e) {
e.printStackTrace();
}
}

@ActionListenerFor(source="yellowBtn")
public void yellowBackground(){
panel.setBackground(Color.yellow);
}

@ActionListenerFor(source="blueBtn")
public void blueBackground(){
panel.setBackground(Color.blue);
}

@ActionListenerFor(source="redBtn")
public void redBackground(){
panel.setBackground(Color.red);
}


public static void main(String[] args) {
ButtonFrame frame = new ButtonFrame();
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}








package com.gavin.annotation;


import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/**
 * 解析@ActionListenerFor,實現根據事件源名稱,
 * 自動調用被註解的方法
 */
public class ActionListenerInstaller {


/**
* @param obj 要處理的類的實例,這裏是ButtonFrame的實例this;
* @throws Exception
*/
public static void processAnnotations(Object obj) throws Exception {
Class<?> cl = obj.getClass();
for(Method m : cl.getDeclaredMethods()){
ActionListenerFor a = m.getAnnotation(ActionListenerFor.class);
if(a != null){
String fieldName = a.source();
Field f = cl.getDeclaredField(fieldName);//獲得成員變量
f.setAccessible(true);//避免private不可訪問;
//爲obj中成員變量的實際值或實例,這裏是各個JButton,添加被註解的方法,這裏是setBackground()
addListener(f.get(obj),obj,m);
}
}
}

/**
* 爲事件源添加ActionListener,並在listener中動態調用被註解的方法,
* 相當於實現了actionPerform方法
* @param source 事件源
* @param param 方法的調用者
* @param m 被註解的方法
* @throws Exception
*/
private static void addListener(Object source,final Object param, final Method m) throws Exception {
InvocationHandler handler = new InvocationHandler() {

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return m.invoke(param);
}
};

/* 
Returns an instance of a proxy class for the specified interfaces
 that dispatches method invocations to the specified invocation handler.
                      返回一個給定的接口ActionListener代理類的實例,這個接口將分發mehtod給指定的handler處理
This method is equivalent to: 
      Proxy.getProxyClass(loader, interfaces).
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });                      
*/
Object listener = Proxy.newProxyInstance(null, new Class[]{java.awt.event.ActionListener.class}, handler);
Method adder = source.getClass().getMethod("addActionListener", ActionListener.class);
adder.invoke(source, listener);

}


}


eg2:用註解生成Person.hibernate.xml:

cmd命令:apt -factory HibernateAnnotationFactory Person.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Persistent {
String table();
}


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Property {
String column();
String type();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface IDProperty {
String column();
String type();
String generator();
}

@Persistent(table = "persons_table")
public class Person {
@IDProperty(column="person_id",type="integer",generator="identity")
private int id;
@Property(column="person_name",type="string")
private String name;
@Property(column="person_age",type="integer")
private int age;
    ...
}

package com.gavin.annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
public class HibernateAnnotationFactory implements AnnotationProcessorFactory {
@Override
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> arg0,
AnnotationProcessorEnvironment env) {
return new HibernateAnnotationProcessor(env);
}

@Override
public Collection<String> supportedAnnotationTypes() {
	return Arrays.asList("Property","IDProperty","Persistent");
}

@Override
public Collection<String> supportedOptions() {
	return Arrays.asList(new String[0]);
}

}


package com.gavin.annotation;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.FieldDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;

public class HibernateAnnotationProcessor implements AnnotationProcessor {

private AnnotationProcessorEnvironment env;

public HibernateAnnotationProcessor(AnnotationProcessorEnvironment env){
this.env = env;
}

@Override
public void process() {
for(TypeDeclaration t : env.getSpecifiedTypeDeclarations()){
FileOutputStream fos = null;
String clazzName = t.getSimpleName();
Persistent per  = t.getAnnotation(Persistent.class);
if(per != null){
try {
fos = new FileOutputStream(clazzName + ".hbm.xml");
PrintStream ps = new PrintStream(fos);
ps.println("<?xml version=\"1.0\"?>");
ps.println("<!DOCTYPE hibernate-mapping");
ps.println(" PUBLIC \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"");
ps.println("<hibernate-mapping>");
ps.println("<class name=\""+t);
ps.println("\" table =\"" + per.table() + "\">");
for(FieldDeclaration f : t.getFields()){
IDProperty id = f.getAnnotation(IDProperty.class);
if(id!=null){
ps.println("<id name=\"" + f.getSimpleName() +
"\" column=\"" + id.column() +
"\" type=\"" + id.type() + 
"\">");
ps.println("<generator class=\""+id.generator()+"\"/>");
ps.println(" </id>");
}

Property p = f.getAnnotation(Property.class);
if(p!=null){
ps.println("<property name=\"" + f.getSimpleName() +
"\" column=\"" + id.column() +
"\" type=\"" + id.type() + 
"\"/>");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
}
}
}




==============================

Typesafe Enums

==============================

一、術語:
enum constant:枚舉常量,即枚舉類的實例
enum type:枚舉類或枚舉類的鏡像

二、枚舉的內部實現:

枚舉是指一個經過排序的,被打包成一個單一實體的項列表;

package com.gavin.enums;

public class Sex {
	//屬性爲final類型,屬性不可變的
	private final String name;
	public static final Sex MALE = new Sex("男");
	public static final Sex FEMALE = new Sex("女");
	//構造器爲private
	private Sex(String name){
		this.name = name;
	}
	public static Sex getSex(int index){
		switch(index){
		case 1:
			return MALE;
		case 2:
			return FEMALE;
		default:
			return null;
		}
	}
	public String getName(){
		return name;
	}
}

三、枚舉的優點:
1.可以使程序更加健壯,避免創建對象的隨意性;

四、枚舉與常量(public static final int或其它類型)的比較:
1.常量由於可以運算,類型不安全;
2.沒有命名空間

3.打印輸出的意義不明確

4.枚舉可用於switch語句中;


五、枚舉類與普通類的區別:
枚舉類構造器是私有的;
枚舉類繼承於Enum類而不是Object類
枚舉類的所有實例必須在枚舉類中顯示列出;這些實例系統會自動添加public static final修飾,
枚舉類不可以繼承,但可以實現接口
枚舉類都提供了values()靜態方法,用於遍歷所有枚舉常量
枚舉類的實例只能是枚舉值,而不是隨意的通過new來創建枚舉對象;

六、枚舉的注意點:
1.比較兩個枚舉的值時,永遠不要用equals,而直接使用“==”就可以了;
2.所有的枚舉類都是Enum類的子類;隱式的,自定義枚舉時,不需要顯示繼承;
  它們繼承了Enum類的toString等大多數方法,toString方法能夠返回枚舉常量名;
  toString()的逆方法是valueOf()靜態方法,它根據枚舉常量名和枚舉類的鏡像,返回枚舉類的實例;
  WorkDayEnum w = (WorkDayEnum)Enum.valueOf(WorkDayEnum.class,"Tuesday")
3.枚舉是一個特殊的類,所以可以有構造器、方法、屬性,可以實現接口;
4.每個枚舉類都有一個靜態的values方法,它將返回一個包含全部枚舉值的數組;
  WorkDayEnum[] workdayArray = WorkDayEnum.values();
5.ordinal()方法:int position = WorkDayEnum.Tuesday.ordinal();
6.枚舉類的實例就是各個枚舉常量;
7.枚舉類默認繼承的Enum類,而不是Object類;
8.枚舉類的構造器只能是private,省略了修飾符,默認表示用private修飾;
9.Switch語句裏的表達式可以是枚舉值

10.使用時,通過WorkdayEnum.Tuesday這樣引用;

11.不能標記一個enum爲abstract的,除非每一個常量都有一個類主體,而且這些類主體覆蓋了enum中的抽象方法;

eg:
switch(Sex s){
  case MALE:
  case FEMALE:
}

七、示例:

eg1:

package com.gavin.enums;

public class Sex {
	//屬性爲final類型,屬性不可變的
	private final String name;
	public static final Sex MALE = new Sex("男");
	public static final Sex FEMALE = new Sex("女");
	//構造器爲private
	private Sex(String name){
		this.name = name;
	}
	public static Sex getSex(int index){
		switch(index){
		case 1:
			return MALE;
		case 2:
			return FEMALE;
		default:
			return null;
		}
	}
	public String getName(){
		return name;
	}
}

eg2:

package com.gavin.enums;

public enum Gender {
	MALE,FEMALE;
	public String name;
	
	public static void main(String[] args){
		Gender g = Enum.valueOf(Gender.class, "MALE");
		g.name = "男";
		System.out.println(g + g.name);//MALE男
	}
}

eg3:

package com.gavin.enums;

public enum Gender2 {
	//在枚舉類中列出枚舉值的過程就是調用構造器創建枚舉對象的過程
	MALE("男"),FEMALE("女");
	/*
	 相當於:
	public static final Gender2 MALE = new Gender2("男");
	public static final Gender2 FEMALE = new Gender2("女");
	 */
	private final String name;
	
	private Gender2(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	
	public static void main(String[] args){
		Gender2 g = Enum.valueOf(Gender2.class, "MALE");
		System.out.println(g + g.getName());//MALE男
	}
}

eg4:

package com.gavin.enums;

public enum Gender3 implements Info{
	//在枚舉類中列出枚舉值的過程就是調用構造器創建枚舉對象的過程
	MALE("男"),FEMALE("女");
	/*
	 相當於:
	public static final Gender2 MALE = new Gender2("男");
	public static final Gender2 FEMALE = new Gender2("女");
	 */
	private final String name;
	
	private Gender3(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	
	public static void main(String[] args){
		Gender3 g = Enum.valueOf(Gender3.class, "MALE");
		System.out.println(g + g.getName());//MALE男
		g.info();
		Gender3.FEMALE.info();
	}

	@Override
	public void info() {
		System.out.println("每個枚舉值即枚舉實例都用此方法描述");
	}
}

interface Info{
	void info();
}

eg5:

package com.gavin.enums;

public enum Gender4 implements Info{
	//在枚舉類中列出枚舉值的過程就是調用構造器創建枚舉對象的過程
	MALE("男"){
		@Override
		public void info() {
			System.out.println("枚舉值‘男’用此方法描述");
		}

		@Override
		public boolean canGiveBirth2Child() {
			System.out.println("這個真沒有");
			return false;
		}
	},FEMALE("女"){
		@Override
		public void info() {
			System.out.println("枚舉值‘女’用此方法描述");
		}

		@Override
		public boolean canGiveBirth2Child() {
			System.out.println("這個可以有");
			return true;
		}
	};
	/*
	 相當於:
	public static final Gender2 MALE = new Gender2("男"){
		@Override
		public void info() {
			System.out.println("枚舉值‘男’用此方法描述");
		}
	};
	public static final Gender2 FEMALE = new Gender2("女"){
		@Override
		public void info() {
			System.out.println("枚舉值‘男’用此方法描述");
		}
	};
	 */
	private final String name;
	
	private Gender4(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	//該抽象方法由不同枚舉值提供不同的實現;
	public abstract boolean canGiveBirth2Child();
	
	public static void main(String[] args){
		Gender4 g = Enum.valueOf(Gender4.class, "MALE");
		System.out.println(g + g.getName());//MALE男
		g.info();//枚舉值‘男’用此方法描述
		Gender4.FEMALE.info();//枚舉值‘女’用此方法描述
	}
}




瞌睡了,明天再續...........





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章