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();//枚举值‘女’用此方法描述
	}
}




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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值