天天看點

Annotataion詳解及自定義注解1 Annotation是什麼2 JDK内置的注解3 自定義注解文法4 元注解5 自定義注解完成建立表

注解的了解和使用

  • 1 Annotation是什麼
  • 2 JDK内置的注解
    • 2.1 @Override
    • 2.2 @Deprecated
    • 2.3 @SuppressWarnings
  • 3 自定義注解文法
  • 4 元注解
    • 4.1 @Target
    • 4.2 @Retention
    • 4.3 @Documented
    • 4.4 @Inherited
  • 5 自定義注解完成建立表
    • 5.1 @Table注解
    • 5.2 @Column注解
    • 5.3 User實體類
    • 5.4反射讀取類資訊

1 Annotation是什麼

  注解:被稱為注解類型、注釋類型

  作用:标注的作用,标記的作用,标記給其他機制做參考的。其他的機制可以參考這個标記,有了這個标記該怎麼做,沒有這個标記應該怎麼做。

2 JDK内置的注解

2.1 @Override

  這個注解專門用來标注方法,被标注的 方法必須是重寫父類的方法,該方法有這個标記後,編譯器開始檢測該方法,當該方法不是重寫父類的方法,編譯器會報錯。

  隻能用來标注方法,不能标注其它元素。隻在編譯階段起作用,和運作期無關。在方法上使用@Override注解:該注解隻被保留在java源代碼當中,位元組碼當中沒有這個代碼。

  以下是Override源碼:

/**
 *訓示方法聲明旨在重寫父類型中的方法聲明。如果用注釋方法需要此批注類型編譯器來生成錯誤除非至少滿足以下條件之一:
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * 該方法不重寫或實作在超級類型。
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * </li></ul>
 *
 * @author  Peter von der Ah&eacute;
 * @author  Joshua Bloch
 * @jls 9.6.1.4 @Override
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
           

2.2 @Deprecated

   該注解标注的元素已過時。這是一種提醒機制。帶有這個注解的元素表示已過時了,有更好的替代方案。并且這個注解會生成到幫助文檔當中。這個已過時注解是給開發人員參考的。

   @Deprecated注解源碼

/**
 * A program element annotated &#64;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
 * @since 1.5
 * @jls 9.6.3.6 @Deprecated
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
           

2.3 @SuppressWarnings

   用來忽略警告的沒有什麼實際作用

@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> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional 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.
     * @return the set of warnings to be suppressed
     */
     // 注解的屬性(當然該屬性同時又可以當做方法用。)
	// 該屬性的名字叫做:value
	// 該屬性的資料類型是:String[] 
    String[] value();
}
           
注意:
有一條規則:
	當一個“注解類型”中有屬性的時候,在使用該注解的時候,屬性必須指派。不指派,編譯器報錯。
怎麼給注解的屬性指派?
	@注釋類型名(屬性名=屬性值,屬性名=屬性值,屬性名=屬性值....)
	@SuppressWarnings(value={"all"})
	當數組中隻有一個元素的時候,大括号可以省略。當屬性名是value的時候,屬性名可以省略。
	@SuppressWarnings("all")
           

3 自定義注解文法

自定義注解文法格式:
public @interface 注釋類型名{
			屬性1;
			屬性2;
			// 每一個屬性怎麼定義?
			屬性的類型 屬性名();
			// 例如:
			String value();
}
           
注解當中的屬性類型隻能是:
		byte,short,int,long,float,double,boolean,char
		Byte,Short,Integer,Long,Float,Double,Boolean,Character
		String、枚舉類型以及以上類型的所有數組形式。
在自定義注解的時候,需要使用其它的注解标注這個注解,專門負責标注注解的注解被稱為元注解(meta-annotation),元注解有:
	java.lang.annotation包下:
		@Target
		@Retention
		@Documented
		@Inherited
	以上4個元注解是專門用來标注其它注解類型的。
           

4 元注解

4.1 @Target

   這個注解主要的作用是:指定被标注的注解隻能出現的位置。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
           

   可以看出@Target注解的取值是ElementType枚舉的取值

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
           

4.2 @Retention

   保持性政策,這個注解主要的作用是:指定被标注的注解的儲存位置。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}
           
RetentionPolicy.SOURCE	表示注解被儲存到java源檔案
RetentionPolicy.CLASS	表示注解被儲存到class檔案,但不會被反射機制讀取到。
RetentionPolicy.RUNTIME 表示注解被儲存到class檔案,并且可以被反射機制讀取到。
           

4.3 @Documented

   這個元注解标注的注解可以生成到幫助文檔當中。

4.4 @Inherited

   這個元注解标注的注解支援繼承。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

           

繼承如下:

@Inherited
	public @interface MyAnnotation{
	
	}
	@MyAnnotation
	public class A{

	}
	public class B extends A{
	
	}
           

5 自定義注解完成建立表

5.1 @Table注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	/**
	 * 表名
	 * @return
	 */
	String name();
}
           

5.2 @Column注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	/**
	 * 字段名
	 * @return
	 */
	String name();
	/**
	 * 字段的資料類型
	 * @return
	 */
	String type();
	/**
	 * 字段長度
	 * @return
	 */
	int length() default 10;  // 給屬性預設指派10
	/**
	 * 字段限制
	 * @return
	 */
	String constraint();
}
           

5.3 User實體類

// java程式解析User.class,并完成自動建表
@Table(name = "tbl_user2")
public class User {
	
	@Column(name = "id", type = "int", constraint = "primary key")
	private int id;
	
	@Column(name = "name", type = "varchar", length = 255, constraint = "not null")
	private String name;
	
	// 帶有這個注解的表示參加自動建表功能。
	@Column(name = "password", type = "varchar", length = 255, constraint = "not null")
	private String password;
	
	// 沒有這個Column注解的則表示不參加自動建表功能。
	private String email;

}
           

5.4反射讀取類資訊

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class ReflectReadAnnotation {
	public static void main(String[] args) throws Exception{
		
		StringBuilder sql = new StringBuilder();
		sql.append("create table ");
		// 讀取注解
		// 擷取類
		Class userClass = Class.forName("com.bjpowernode.javase.annotation3.User");
		
		// 擷取類上面的注解
		String tableName = null;
		if(userClass.isAnnotationPresent(Table.class)){ // 這個條件成立則表示該類上有Table注解。
			Table table = (Table)userClass.getAnnotation(Table.class);
			tableName = table.name();
			sql.append(tableName);
		}
		
		sql.append("(");
		
		// 擷取所有的Field
		Field[] fields = userClass.getDeclaredFields();
		for(Field field : fields){
			if(field.isAnnotationPresent(Column.class)){ // 這個條件成立說明該屬性上有Column注解。
				Column column = field.getAnnotation(Column.class);
				sql.append(column.name());
				sql.append(" ");
				sql.append(column.type());
				sql.append("(");
				sql.append(column.length());
				sql.append(")");
				sql.append(" ");
				sql.append(column.constraint());
				sql.append(",");
			}
		}
		
		String createSql = sql.substring(0, sql.length() - 1) + ")";
		System.out.println(createSql);
		
		createTable(createSql, tableName);
	}

	private static void createTable(String createSql, String tableName) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection
					("jdbc:mysql://localhost:3306/test_database, "root", "root");
			String sql1 = "drop table if exists " + tableName;
			ps = conn.prepareStatement(sql1);
			ps.execute();
			
			ps = conn.prepareStatement(createSql);
			ps.execute();
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			if(ps != null){
				try {
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if(conn != null){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}