註解
1. 註解概述
1.1 註解解釋
註釋:
解釋代碼,給程序員看
註解:
Java語言中的類、方法、變量、參數和包等都可以被標註。和Javadoc不同,Java標註可以通過反射獲取標註內容。在編譯器生成類文件時,標註可以被嵌入到字節碼中。Java虛擬機可以保留標註內容,在運行時可以獲取到標註內容。 當然它也支持自定義Java標註
JDK1.5之後的特徵
用於說明程序
一般在框架中使用
格式:
@AnnotationName
文檔註釋:
@param @return @Exeception 從根本上是一個註釋,不存在代碼編譯,不會生成對應的.class字節碼問題,只是提供給JavaDoc API文件生成工具。作爲標記生成對應的文檔。
註解是有一部分參與編譯
@Override並不是沒編譯就有效果了,是因爲不管是Eclipse還是IDEA都可以預編譯Java代碼生成對應的.class文件的
1.2 註解作用
生成文檔:
代碼中生成對應的JavaDoc API文檔
@param @return
【IDEA JavaDoc工具使用參數】
Other Command Line Arguments : -encoding utf-8 -charset utf-8
解決中文亂碼,因爲IDEA默認編碼集爲UTF-8 Windows GKB
代碼檢查:
繼承重寫,或者說接口遵從之後的實現中,存在@Override
代碼數據獲取: [小框架]
通過反射獲取指定註解中的一些內容,例如 配置,數據,操作,驗證。。。
1.3 Java中預定義的一些註解
@Override:
重寫/實現方法的情況下,檢查方法聲明是否和父類或者接口中的方法聲明一致。強制格式檢查。
@Deprecated
標註當前方法已過時,例如 Data日期類內的一些方法
@SuppressWarnings("all")
壓制警告,可以用於一些代碼中存在明確無異常的情況下,壓制一些警告
2. Java中自定義註解
2.1 Java中自定義註解的方式
格式:
public @interface AnnotationName {
屬性列表;
}
Annotation註解是可以編譯得到對應的.class字節碼文件,驗證了註解是可以參與編譯過程的
通過反編譯工具可以得到一下內容
【Annotation本質】
public interface MyAnnotation1 extends java.lang.annotation.Annotation {
}
MyAnnotation1
本質是一個interface,同時java.lang.annotation.Annotation 子接口
package com.qfedu.a_annotation.MyAnnotation;
public @interface MyAnnotation1 {
}
2.2 Annotation註解屬性【難點】
屬性:
開發書寫代碼使用註解的方式中,數據使用方式更加偏向於屬性概念。
使用
1. 在書寫代碼中使用
@MyAnnotation(id=1, name="騷磊", age=16)
2. 利用反射時,會涉及到getXXX方法
通過屬性名獲取對應值的概念來完成的
【但是實際上是利用abstract方法來完成屬性概念的】
屬性使用的格式[實際按照方法格式操作]
1. 屬性的值數據類型和對應具體數據 ==> 返回值類型和返回的數據
屬性類型支持:
a. 基本數據類型
b. String類型
c. 其他的註解類型
d. 枚舉類型
枚舉就是一個帶有名字的常量,爲了更好的域閱讀性和操作
e. 以上類型對相應的數組
屬性值要求
a. 定義屬性時可以使用default關鍵字,加上默認值,該屬性在使用的過程中是
沒有強制要求屬性值,如果沒有賦予屬性值,採用對應的默認值操作,如果賦
值,使用對應值
b. 如果註解中有且只有一個value屬性,或者說註解中除value屬性之外,都有
默認值,不管是類,方法,成員變量,包使用當前註解是可以直接在括號內加入
對應數據類型數值、
c. 如果屬性是數組類型, {}大括號保存,並且不同的內容,使用,隔開
2. 屬性的鍵名字 ==> 方法的名字
2.3 元註解
給予註解的解釋,用於約束註解的一些操作問題
@Retention -
標識這個註解怎麼保存,是隻在代碼中,還是編入class文件中,或者是在運行時可以通過反射訪問。
RetentionPolicy.RUNTIME:當前註解會編譯生成對應的.class字節碼文件,並且可以加
載到JVM中,參與代碼執行
RetentionPolicy.CLASS:
別糾結,記下就好:
RetentionPolicy.SOURCE:註解將被編譯器丟棄(該類型的註解信息只會保留在源碼裏,源碼經過編譯後,註解信息會被丟棄,不會保留在編譯好的class文件裏)
@Override
對應屬性RetentionPolicy.SOURCE
在代碼編譯過程中,檢查方法格式是否正確,不參與代碼運行和解析。
@Documented
標記這些註解是否包含在用戶文檔中。
是否可以通過JavaDoc工具,生成對應的API文檔
@Target
標記這個註解應該是哪種 Java 成員。
屬性:
ElementType
TYPE: 當前註解可以用於類聲明
METHOD: 當前註解可以用於方法聲明位置
FIELD:當前註解可以用於成員變量聲明位置
@Inherited
標記這個註解是繼承於哪個註解類(默認 註解並沒有繼承於任何子類)
【重點】
@Target目標
可以作用範圍 類,方法,成員變量...
@Retention
RetentionPolicy.RUNTIME 常用
2.4 使用反射獲取註解中的內容【用途】
driverClass=com.mysql.jdbc.Driver
user=root
password=123456
url=jdbc:mysql://localhost:3306/db_name
# 配置文件保存到properties文件中,使用文件中內容讀取配置獲取屬性
# properties Properties System.getProperties();
# Properties ==> driverClass ==> com.mysql.jdbc.Driver ==> 完整的包名.類名
# Class.forName
package com.qfedu.a_annotation.reflect;
import com.qfedu.a_annotation.Person;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;
public class ReflectFile {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Properties properties = new Properties();
properties.load(new FileInputStream("./src/1.properties"));
String className = properties.getProperty("className");
String id = properties.getProperty("id");
String name = properties.getProperty("name");
System.out.println(className);
Class<?> aClass = Class.forName(className);
Person person = (Person) aClass.getConstructor().newInstance();
System.out.println(person);
Field declaredField = aClass.getDeclaredField("id");
declaredField.setAccessible(true);
declaredField.set(person, Integer.parseInt(id));
Field declaredField2 = aClass.getDeclaredField("name");
declaredField2.setAccessible(true);
declaredField2.set(person, name);
System.out.println(person);
}
}
package com.qfedu.a_annotation.reflect;
import com.qfedu.a_annotation.MyAnnotation.MyAnnotation5;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@MyAnnotation5(className = "com.qfedu.a_annotation.Person",
id = 2,
name = "騷磊")
public class ReflectAnnotatiaon {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<ReflectAnnotatiaon> cls = ReflectAnnotatiaon.class;
MyAnnotation5 annotation = cls.getAnnotation(MyAnnotation5.class);
String s = annotation.className();
int id = annotation.id();
String name = annotation.name();
System.out.println(s);
System.out.println(id);
System.out.println(name);
Class<?> aClass = Class.forName(s);
Constructor<?> constructor = aClass.getConstructor(Integer.class, String.class);
Object o = constructor.newInstance(id, name);
System.out.println(o);
}
}
2.5 使用註解測試代碼運行【用途】
package com.qfedu.a_annotation.checkMethod;
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 Check {
}
package com.qfedu.a_annotation.checkMethod;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ClassAnnotation(className = "com.qfedu.a_annotation.checkMethod.Utils")
public class TestProject {
public static void main(String[] args)
throws IOException, InvocationTargetException,
IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InstantiationException {
Class<TestProject> cls = TestProject.class;
ClassAnnotation annotation = cls.getAnnotation(ClassAnnotation.class);
String s = annotation.className();
Class<?> aClass = Class.forName(s);
Object tools = aClass.getConstructor().newInstance();
Method[] declaredMethods = aClass.getDeclaredMethods();
int count = 0;
long l = System.currentTimeMillis();
BufferedWriter br = new BufferedWriter(new FileWriter("./src/log.txt"));
for (Method declaredMethod : declaredMethods) {
declaredMethod.setAccessible(true);
if (declaredMethod.isAnnotationPresent(Check.class)) {
try {
declaredMethod.invoke(tools);
} catch (Exception e) {
count += 1;
br.write("方法:" + declaredMethod.getName());
br.newLine();
br.write("異常類型:" + e.getCause().getClass().getSimpleName());
br.newLine();
br.write("異常信息:" + e.getCause().getMessage());
br.newLine();
br.write("-----------------------------------------------------------------");
br.newLine();
}
}
}
long l1 = System.currentTimeMillis();
br.write("出現錯誤的次數:" + count);
br.newLine();
br.write("總耗時:" + (l1 - l));
br.newLine();
br.close();
}
}
3. 註解使用總結
1. 註解以後大多數情況下,都是使用過程,而不是自定義,會使用到框架中預處理好的註解。
2. 註解是給誰用的?
a. 編譯器
b. 解析代碼使用
c. JVM運行代碼使用
3. 註解是一個標籤,有時候是做標記的,有時候標籤是有屬性的。