Java註解簡介、自定義註解及模擬Junit、模擬hibernate根據實體類建表
註解簡介
註解:JDK1.5的新特性
註解(也被稱爲元數據)爲我們在代碼中添加信息提供了一種形式化的方法,使我們可以在稍後某個時刻非常方便地使用這些數據。
Java SE5 三個內置標準註解
- @Override:方法覆蓋、重寫;
- @Deprecated:過時的;
- @SupperessWornings:關閉不當的編譯器警告信息;
元註解:
-
@Target:表示註解在什麼地方使用,可用ElementType,其值爲:
* constructor:說明該方法用在構造方法上;
* field:說明蓋註解用在屬性上;
* local_variable:局部變量上;
* method:用在方法上;
* package:用在包聲明上;
* parameter:用在參數上;
* type:用在類或接口上; -
@Retention:表示需要在什麼級別保存該註解信息,可能的參數值RetentionPolicy爲:
source:表示該註解會被編譯器丟棄
class:說明該註解會在.class文件中,但會被JVM丟棄
runtime:jvm將在運行期間保留,因此可以通過反射機制來讀取註解信息 -
@Documented:將該註解包含在JavaDoc中。表示此註解會被javadoc工具提取成文檔。
-
@Inherited:允許子類繼承父類中的註解。
自定義註解
- 定義註解
import java.lang.annotation.*;
@Target(ElementType.METHOD) //說明此註解用在方法上
@Retention(RetentionPolicy.RUNTIME) //說明是運行級別
public @interface Info {
int id(); //爲區分接口與類,在後面加上()
String des() default "暫無信息";
}
- 定義目標類
public class TestInfo {
@Info(id=1,des="show方法")
public void show() {
System.out.println("陰雨綿綿。。。");
}
@Info(id=2)
public String getInfo() {
return "欸。。。";
}
public void description(){
System.out.println("真是應景。。。");
}
}
- 定義測試類
public class InfoTracker {
public static void main(String[] args) {
test(TestInfo.class);
}
public static void test(Class<TestInfo> cl) {
Info info = null;
for( Method method : cl.getDeclaredMethods() ){ //循環給定類中的所有方法。也可以給定包路徑,自動掃描該包下的所有類
if( method.isAnnotationPresent( Info.class ) ){
//method.getAnnotations(); //獲取這個方法上的所有註解
//現在我們只想知道是否有我們給定的註解Info
System.out.println( method.getName() + "有Info註解" );
info = method.getAnnotation(Info.class);
System.out.println(info.id() + "-" + info.des());
}else{
System.err.println( method.getName() + "沒有Info註解" );
}
}
}
}
Java註解模擬實現Junit
- 創建註解類
import java.lang.annotation.*;
@Target(value={ElementType.METHOD}) //目標:作用域方法 //兩種寫法
@Retention(RetentionPolicy.RUNTIME) //保留範圍:運行時保留,不會被jvm丟棄
public @interface Beta {
//這個註解類中不需要任何屬性
}
- 編寫測試用例類
public class Test {
@Beta //加上自定義的測試註解
public void test(){
System.out.println("SUCCESS!");
}
@Beta
public void test2(){
System.out.println("成功了!哈哈哈...");
}
@Beta
public void test3(){
System.err.println("嘻嘻嘻...");
}
}
- 編寫註解方法的操作測試類
public class TestBeta {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
Class clazz = Test.class;
Method[] methods = clazz.getMethods();
if(methods != null){
for(Method method : methods){
boolean isAP = method.isAnnotationPresent(Beta.class);
if(isAP){
method.invoke(clazz.newInstance(), null);
}
}
}
}
}
註解模擬Hibernate中根據實體類在數據庫建表的方法
- 創建用來指定表名的註解
import java.lang.annotation.*;
@Target(ElementType.TYPE) //說明作用在類上
@Retention(RetentionPolicy.RUNTIME) //運行時級別
public @interface TableName {
public String name() default "";
}
- 創建用來指定類型的註解
import java.lang.annotation.*;
@Target(ElementType.FIELD) //說明用在屬性上
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
public String type() default "varchar(20)";
public Constraints constraints() default @Constraints;
}
- 創建指定約束的註解
@Target(ElementType.FIELD) //說明在屬性上
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
public boolean primaryKey() default false; //是否爲主鍵
public boolean allowNull() default true; //是否可爲空
public boolean unique() default false; //是否唯一
public boolean identity() default false; //是否自增
}
- 創建實體類
@TableName
public class StuInfo {
@Type(type="int" ,constraints=@Constraints(primaryKey=true,identity=true))
private int usid;
@Type(type="varchar(200)" ,constraints=@Constraints(allowNull=false,unique=true))
private String sname;
@Type(type="int")
private int age;
@Type(constraints=@Constraints(unique=true))
private String tel;
public int getUsid() {
return usid;
}
public void setUsid(int usid) {
this.usid = usid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
}
- 創建測試類
public class TableCreator {
public static void main(String[] args) {
TableCreator tc = new TableCreator();
tc.run();
}
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void run(){
Connection con = null;
Statement stmt = null;
try {
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","數據庫用戶名","密碼");
stmt = con.createStatement();
String sql = this.getSql(StuInfo.class);
System.out.println(sql);
stmt.execute(sql); //執行sql
System.out.println("創建成功");
} catch (Exception e) {
System.err.println("創建失敗");
e.printStackTrace();
}finally {
try {
if(stmt != null){
stmt.close();
}
if( con != null ){
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//建表語句
public String getSql(Class<?> cl){
TableName tn = cl.getAnnotation(TableName.class);
if(tn == null){
return null;
}
String tableName = tn.name();
if( tableName == null || "".equals(tableName) ){
tableName = cl.getSimpleName(); //這裏不要使用getName(),那樣會返回帶有包路徑的字符串值
}
//如果需要考慮性能,建議使用StringBuffer
StringBuffer sbf = new StringBuffer();
sbf.append("create table ").append(tableName).append("(");
//拼接列 -> 獲取這個對象中的所有屬性 -> 判斷屬性上是否有Type註解
Field[] fields = cl.getDeclaredFields();
if(fields == null || fields.length <= 0){
return null;
}
Type type = null;
for( Field field : fields ){
type = field.getAnnotation(Type.class);
if(type != null){
sbf.append( field.getName() ).append(" ").append( type.type() );
//這個列上的約束
if( type.constraints().primaryKey() ){ //如果是主鍵
sbf.append(" primary key");
if( type.constraints().identity() ){//則需要判斷是否自增
sbf.append(" auto_increment");
}
}else{//不是主鍵,判斷是否可爲空,是否唯一
if( !type.constraints().allowNull() ){ //不可爲空
sbf.append(" not null");
}
if( type.constraints().unique() ){ //唯一
sbf.append(" unique");
}
}
sbf.append(",");
}
}
String sql = sbf.toString();
//處理最後一個多餘的逗號,並加上反括號
sql = sql.substring(0,sql.lastIndexOf(",")) + ")";
return sql;
}
}