JAVA SE-註解
一個專心致志思索的人並不是在虛度光陰。雖然有些勞動是有形的,但也有一種勞動是無形的。 —— 雨果
什麼是註解?註解有什麼用?
- 註解就是 @xxx 這樣的東西就是註解.
- 註釋:給程序員看的.
- 註解:給程序看。
- 使用註解的目的: 其實將來使用註解目的就是爲了代替傳統配置文件.
@Override
public class Demo1 implements Person {
@Override
//向編譯器描述,該方法是被重寫的.
//幫你檢查,被註解修飾方法是否是被重寫的,如果不是編譯報錯!
//@Override 1.5版本只接受繼承性質的重寫. 1.6版本也接受實現接口性質的重寫
public void eat() {
}
//@Override
public void eat2() {
}
}
@Deprecated
public class Demo2 {
@Deprecated
//該註解告訴編譯器,被修飾的方法是過時方法
public static void show(){
System.out.println("hello world!");
}
public static void main(String[] args) {
Demo2.show();
}
}
@SuppressWarnings
public class Demo3 {
//@SuppressWarnings({"null","rawtypes", "unchecked"})
@SuppressWarnings("all")
//告訴編譯器,不要檢查什麼錯誤!
//如果填寫all,那麼什麼錯誤都不檢查.
public static void main(String[] args) {
String str = null;
str.substring(0);
//@SuppressWarnings("unused")
String str2 = null;
List list = new ArrayList();
list.add("abc");
}
}
如何自定義一個註解?
public @interface MyAnnotation {
//聲明屬性=> 抽象方法
//聲明一個名爲name的屬性 類型是String
String value();
//如果註解中,必填屬性只有一個. 這個屬性的名字是"value".那麼在賦值時不需要加屬性的鍵.
}
分析一下註解的本質:
將其.class文件找到,反編譯.
@interface MyAnnoation{}
反編譯後的結果
interface MyAnnotation extends Annotation
{
}
結論:註解本質上就是一個接口。它擴展了java.lang.annotation.Annotation接口;
在java中所有註解都是Annotation接口的子接口。
註解也是jdk1.5的一個新特性.
註解的屬性
註解的成員
註解本質上就是一個接口,那麼它也可以有屬性和方法。
但是接口中的屬性是 static final的,在註解中註解沒有什麼意義。
在開發中註解中經常存在的是方法。而在註解中叫做註解的屬性.
註解的屬性的類型:
1.基本類型
2.String
3.枚舉類型
4.註解類型
5.Class類型
6.以上類型的一維數組類型
public @interface MyAnnotation2 {
//註解的屬性都支持那些類型?
// 八大基本數據類型
// String
// Array
// Enum枚舉
//可以使用default關鍵字,添加屬性的默認值
byte a() default 10;
short b();
int c();
long d();
float e();
double f();
char g();
boolean h();
String i();
String[] j();
ElementType k();
}
關於註解的屬性聲明後的使用:
1.如果一個註解有屬性,那麼在使用註解時,要對屬性進行賦值操作.
例如:@MyAnnotation3(st = "aaa")
2.如果一個註解的屬性有多個,都需要賦值,使用","分開屬性.
@MyAnnotation3(st = "aaa",i=10)
3.也可以給屬性賦默認值
double d() default 1.23;
如果屬性有默認值,在使用註解時,就可以不用爲屬性賦值。
4.如果屬性是數組類型
1.可以直接使用 屬性名={值1,值2,。。。}方式,例如
@MyAnnotation3(st = "aaa",i=10,sts={"a","b"})
2.如果數組的值只有一個也可以寫成下面方式
@MyAnnotation3(st = "aaa",i=10,sts="a")
注意sts屬性它是數組類型,也就是說,只有一個值時,可以省略"{}"
5.對於屬性名稱 value的操作.
1.如果屬性名稱叫value,那麼在使用時,可以省略屬性名稱
@MyAnnotation3("hello")
2.如果有多個屬性,都需要賦值,其中一個叫value,這時,必須寫屬性名稱
@MyAnnotation3(value="hello",i=10)
3.如果屬性名稱叫value,它的類型是數組類型.
1.只有這個value屬性
可以直接賦值,不能寫屬性名稱,但是,如果只有一個值
@MyAnnotation3({"abc"})或 @MyAnnotation3("abc")
但是如果有多個值
@MyAnnotation3({"abc","def"})
2.如果有多個屬性,屬性名稱叫value
所有屬性都需要賦值,那麼必須寫屬性名稱.
關於元註解
元註解是指註解的註解。包括 @Retention @Target @Document @Inherited
四種。
//元註解 (4個)
//修飾註解的註解
// @Retention 註解是給誰看的=> 永遠選擇RUNTIME
//RetentionPolicy.SOURCE 註解會保留到編譯期 (給編譯器看)
//RetentionPolicy.CLASS 註解會保留到加載期(給類加載器)
//RetentionPolicy.RUNTIME 註解會保留到運行期(給虛擬機看)
//
@Retention(RetentionPolicy.RUNTIME)
//@Target 註解支持加在什麼位置
@Target(ElementType.TYPE) //接口、類、枚舉、註解
@Target(ElementType.FIELD) //字段、枚舉的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法參數
@Target(ElementType.CONSTRUCTOR) //構造函數
@Target(ElementType.LOCAL_VARIABLE)//局部變量
@Target(ElementType.ANNOTATION_TYPE)//註解
@Target(ElementType.PACKAGE) ///包
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD,ElementType.TYPE})
//@Inherited描述 註解可否被繼承
@Inherited
//@Documented 描述註解是否用於生成java文檔
@Documented
public @interface MyAnnotation3 {
}
註解與銀行取款的實例
首先自定義一個註解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BankInfo {
double value();
}
實現的銀行業務類
public class BankService {
@BankInfo(20000)
public static void zz(String name1,String name2,double money) throws Exception{
// 在使用註解的方法中獲得註解上填寫的屬性值.
//1 獲得註解所在的反射對象
Method m = BankService.class.getMethod("zz",String.class,String.class,double.class);
//2 判斷方法是否被@BankInfo 所修飾
if(m.isAnnotationPresent(BankInfo.class)){
//被修飾
//3 獲得註解的屬性值
BankInfo info = m.getAnnotation(BankInfo.class);
double maxmoney = info.value();
if(money>maxmoney){
throw new RuntimeException("單次轉賬不能超過"+maxmoney+"元!");
}
System.out.println(name1+"給"+name2+"轉了"+money+"元!");
}else{
//沒被註解修飾
throw new RuntimeException("系統異常,不能轉賬!");
}
}
public static void main(String[] args) throws Exception {
zz("tom", "jerry", 10000);
}
}
下一個事例:JDBCUtils
在以往的實例當中,我們選擇以配置文件的方式來控制參數,現在我們可以用註解來完成相關參數的配置工作。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//加到類上
public @interface JDBCInfo {
//驅動名稱
String driver();
//url地址
String url();
//用戶名
String name();
//密碼
String password();
}
重寫JDBC的工具類
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
@JDBCInfo(driver = "com.mysql.jdbc.Driver", name = "root", password = "1234", url = "jdbc:mysql://localhost:3306/day05")
public class JDBCUtils {
private static String driver;
private static String url;
private static String user;
private static String password;
static{
try {
//獲得註解中配置的屬性
//1 獲得註解所在的反射對象
Class clazz = JDBCUtils.class;
//2 獲得註解的實現類
JDBCInfo info = (JDBCInfo) clazz.getAnnotation(JDBCInfo.class);
//3 獲得4個屬性值
driver = info.driver();
url=info.url();
user=info.name();
password=info.password();
//1 註冊驅動
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//1 獲得連接
public static Connection getConnection(){
Connection conn = null;
try {
//2 獲得連接
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("創建連接失敗!");
}
return conn;
}
//2 釋放資源
//1> 參數可能爲空
//2> 調用close方法要拋出異常,確保即使出現異常也能繼續關閉
//3>關閉順序,需要從小到大
public static void close(Connection conn , Statement st , ResultSet rs){
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(st!=null){
st.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
System.out.println(getConnection());
}
}