java注解的反射_Java注解与反射
概要
本文主要是總結(jié)Java注解與反射的相關(guān)知識(shí),加深自己對(duì)Java類動(dòng)態(tài)語(yǔ)言的理解,同時(shí)為日后學(xué)習(xí)Spring打下基礎(chǔ)。
注解:
什么是注解
Annotation的作用
不是程序本身,但是可以對(duì)程序作出解釋。
可以被其他程序(比如:編譯器等)讀取。
Annotation的格式:
注解是以“@注釋名”在代碼中存在的,還可以添加一些參數(shù)值,例如:@SuppressWarnings(value="unchecked")。
Annotation使用范圍:
附加在package、class、method、field等上面,相當(dāng)于給他們添加了額外的輔助信息,然后通過(guò)反射機(jī)制編程實(shí)現(xiàn)對(duì)這些元數(shù)據(jù)的訪問(wèn)。
內(nèi)置注解
Override:
定義在java.lang.Override中,此注釋只適用于修辭方法,表示一個(gè)方法聲明打算重寫超類中的另一個(gè)方法聲明。
Deprecated:
定義在java.lang.Deprecated中,此注釋可以用于修辭方法、屬性、類,表示不鼓勵(lì)程序員使用這樣的元素,通常是因?yàn)樗芪kU(xiǎn)或者有更好的選擇。
SuppressWarnings:
定義在java.lang.SuppressWarnings中,用來(lái)抑制編譯時(shí)警告信息,與前兩個(gè)注釋不同,此注解需要添加一個(gè)參數(shù)才可正常使用:
?SuppressWarnings("all")
?SuppressWarnings("unchecked")
?SuppressWarnings(value={"deprecation","unchecked"})
?......
元注解
元注解的作用就是負(fù)責(zé)注解其他注解,Java定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型,他們被用來(lái)提供對(duì)其他annotaion類型作說(shuō)明。
這些類型和他們所支持的類在java.lang.annotation包可以找到:
?@Target:用于描述注解的使用范圍(即被描述的注解可以用在什么地方)
?@Retention:表示需要在什么級(jí)別保存該注釋信息,用于描述注解的生命周期(SOURCE
?@Document:說(shuō)明該注解將被包含在javadoc中。
?@Inherited:說(shuō)明子類可以繼承父類中的該注解。
自定義注解
使用@interface自定義注解,格式:public @interface 注解名{定義內(nèi)容}。
自定義注解內(nèi)部的參數(shù)格式:參數(shù)類型+參數(shù)名();若只有一個(gè)參數(shù)成員,參數(shù)名默認(rèn)為value。
注解的元素必須要有值,我們定義注解元素時(shí),一般默認(rèn)使用空字符串,0作為默認(rèn)值。
//注解可以顯式賦值,如果沒有默認(rèn)值,則必須賦值
@myAnnotation(id = 3)
public class testAnnotation {
@myAnnotation(id = 5,school = {"THU","CMU"})
public void test(){
}
}
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface myAnnotation{
//注解的參數(shù):參數(shù)類型+參數(shù)名()
String name() default "";
int id();
int age() default 0;
String[] school() default {"HDU"};
}
反射:
什么是反射
Reflection是Java被視為動(dòng)態(tài)語(yǔ)言的關(guān)鍵,反射機(jī)制允許程序在執(zhí)行期間借助于Reflection API取得任何類的內(nèi)部信息,并能直接操作任意對(duì)象的內(nèi)部屬性及方法。
Java在加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個(gè)Class類型的對(duì)象(一個(gè)類只有一個(gè)Class對(duì)象),這個(gè)對(duì)象就包含了完整的類的結(jié)構(gòu)信息。我們通過(guò)這個(gè)對(duì)象可以看到類的結(jié)構(gòu),這種過(guò)程稱為反射。
正常方式:引入需要的“包類”名稱?通過(guò)new實(shí)例化?取得實(shí)例化對(duì)象
反射方式:實(shí)例化對(duì)象?getClass()方法?取得完整的“包類”名稱
反射相關(guān)的API
java.lang.Class:代表一個(gè)類
java.lang.reflect.Method:代表類的方法
java.lang.reflect.Field:代表類的成員變量
java.lang.reflect.Constructor:代表類的構(gòu)造器
public class test{
public static void main(String[] args) throws ClassNotFoundException {
//通過(guò)反射獲得類的Class對(duì)象
Class> c1 = Class.forName("JavaDoc.User");
Class> c2 = Class.forName("JavaDoc.User");
Class> c3 = Class.forName("JavaDoc.User");
//一個(gè)類在內(nèi)存中只有一個(gè)Class對(duì)象
//一個(gè)類被加載后,類的整個(gè)結(jié)構(gòu)都會(huì)被封裝在Class對(duì)象中
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
}
}
//實(shí)體類 pojo ,Entity
class User{...}
//輸出結(jié)果:hashCode相同
1846274136
1846274136
1846274136
獲得Class類的方式
若已知具體的類,通過(guò)類的class屬性獲取。
若已知某個(gè)類的實(shí)例化對(duì)象,調(diào)用該實(shí)例的getClass()方法獲取Class對(duì)象。
若已知一個(gè)類的全類名,且該類在類路徑下,可以通過(guò)Class類的靜態(tài)方法forName()方法獲取。
public class test02{
public static void main(String[] args) throws ClassNotFoundException {
Student student = new Student();
//通過(guò)forName獲得
Class c1 = Class.forName("JavaDoc.Student");
//通過(guò)對(duì)象獲得
Class c2 = student.getClass();
//通過(guò)類名.class獲得
Class c3 = Student.class;
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
//獲得父類類型
System.out.println(c1.getSuperclass().hashCode());
}
}
//實(shí)體類 pojo ,Entity
class Person{...}
class Student extends Person{...}
Java內(nèi)存分析
Java內(nèi)存區(qū)域
功能
堆
存放new的對(duì)象和數(shù)組,可以被所有的線程共享,不會(huì)存放別的對(duì)象引用
棧
存放基本類型變量(包含具體數(shù)值)和引用對(duì)象的變量(包含具體地址)
方法區(qū)
可以被所有線程共享,包含了所有class和static變量
這里只是淺顯列出,詳細(xì)分析需要參考Java的JVM。
Class類初始化
類的主動(dòng)引用一定會(huì)發(fā)生類的初始化
當(dāng)虛擬機(jī)啟動(dòng)時(shí),先初始化main方法所在的類。
調(diào)用類的靜態(tài)成員(除了final常量)和靜態(tài)方法會(huì)發(fā)生初始化。
使用java.lang.reflect包反射調(diào)用會(huì)發(fā)生初始化。
類的被動(dòng)引用不會(huì)發(fā)生類的初始化
當(dāng)訪問(wèn)一個(gè)靜態(tài)域時(shí),只有真正聲明這個(gè)域的類才會(huì)被初始化。如當(dāng)通過(guò)子類引用父類的靜態(tài)變量,不會(huì)導(dǎo)致子類初始化。
通過(guò)數(shù)組定義類的引用,不會(huì)觸發(fā)此類的初始化。
引用常量不會(huì)觸發(fā)此類的初始化。
public class test03{
static {
System.out.println("Main類被加載");
}
public static void main(String[] args){
//主動(dòng)引用
Son son = new Son();
//final不會(huì)初始化父類和子類
System.out.println(Son.M);
}
}
class Father{
static int b = 3;
static {
System.out.println("父類被加載");
}
}
class Son extends Father{
static {
System.out.println("子類被加載");
m = 200;
}
static int m = 100;
static final int M = 1;
}
//輸出結(jié)果
Main類被加載
父類被加載
子類被加載
100
類加載器
類加載器作用是用來(lái)把類裝載進(jìn)內(nèi)存,JVM規(guī)范定義了如下類型的類加載器:
系統(tǒng)類加載器:
負(fù)責(zé)java -classpath或- D,導(dǎo)入java.class.path所指定的目錄下的類與jar包裝入工作,是最常用的加載器。
擴(kuò)展類加載器:
負(fù)責(zé)jre/lib/ext目錄下的jar包裝入工作庫(kù)。
引導(dǎo)類加載器:
采取C++編寫,是JVM自帶的類加載器,負(fù)責(zé)Java平臺(tái)的核心庫(kù),用來(lái)裝載核心類庫(kù),無(wú)法直接獲取。
類加載器采取雙親委派機(jī)制,自底向上檢查類是否已經(jīng)裝載,自頂向下嘗試加載類。
自定義類加載器?System Classloader?Extension Classloader?Bootstrap Classloader
public class test04{
public static void main(String[] args){
//獲取系統(tǒng)類加載器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//獲取系統(tǒng)類加載器的父類加載器 --> 擴(kuò)展類加載器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//獲取擴(kuò)展類加載器的父類加載器 --> 根加載器(c/c++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
//獲取可加載的系統(tǒng)類加載器
System.out.println(System.getProperty("java.class.path"));
}
}
類的運(yùn)行時(shí)結(jié)構(gòu)
getName()
getFields()
getMethods()
getConstructors()
......
public class test05{
public static void main(String[] args) throws ClassNotFoundException {
Class> c1 = Class.forName("JavaDoc.User");
//getFields只能獲取public類型信息
System.out.println("===getFields====");
Field[] field = c1.getFields();
for (Field field1 : field) {
System.out.println(field1);
}
//getDeclaredFields可獲取所有信息
System.out.println("===getDeclaredFields====");
field = c1.getDeclaredFields();
for (Field field1 : field) {
System.out.println(field1);
}
}
}
class User{
public double score;
private String name;
private int id;
private int age;
}
//輸出結(jié)果
===getFields====
public double JavaDoc.User.score
===getDeclaredFields====
public double JavaDoc.User.score
private java.lang.String JavaDoc.User.name
private int JavaDoc.User.id
private int JavaDoc.User.age
動(dòng)態(tài)創(chuàng)建對(duì)象執(zhí)行方法
創(chuàng)建類的對(duì)象:
調(diào)用Class對(duì)象的newInstance()方法
類必須有一個(gè)無(wú)參構(gòu)造器。
類的構(gòu)造器訪問(wèn)權(quán)限需要足夠。
創(chuàng)建步驟:
通過(guò)Class類中的getDeclaredConstructor()取得本類的指定形參類型的構(gòu)造器。
向構(gòu)造器的形參中傳遞一個(gè)對(duì)象數(shù)組進(jìn)去,里面包含了構(gòu)造器中所需的各個(gè)參數(shù)。
通過(guò)Constructor實(shí)例化對(duì)象。
public class test06{
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class> c1 = Class.forName("JavaDoc.User");
//newInstance默認(rèn)調(diào)用無(wú)參構(gòu)造
User user = (User) c1.newInstance();
System.out.println(user);
//通過(guò)構(gòu)造器聲明含參構(gòu)造重新調(diào)用newInstance
Constructor> constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("zhangsan", 001, 20);
System.out.println(user2);
//通過(guò)反射機(jī)制調(diào)用User類中的方法
Method setName = c1.getDeclaredMethod("setId", int.class);
setName.invoke(user,001);
System.out.println(user.getId());
//通過(guò)關(guān)閉程序權(quán)限檢測(cè),操作程序的私有屬性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);
name.set(user4,"zhangsan2");
System.out.println(user4.getName());
}
}
class User{
...
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
...
}
反射操作注解
public class test07{
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class> c1 = Class.forName("JavaDoc.User");
//通過(guò)反射獲得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//獲得注解內(nèi)部value值
Table table = c1.getAnnotation(Table.class);
System.out.println(table.value());
//獲取內(nèi)部指定字段的注解信息
Field f1 = c1.getDeclaredField("name");
fieldStudent field = f1.getAnnotation(fieldStudent.class);
System.out.println(field.columnName());
System.out.println(field.type());
System.out.println(field.length());
}
}
@Table(value = "db_User")
class User{
@fieldStudent(columnName = "db_name",type = "varchar",length = 3)
private String name;
@fieldStudent(columnName = "db_id",type = "int",length = 10)
private int id;
@fieldStudent(columnName = "db_age",type = "int",length = 10)
private int age;
}
//類名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//屬性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface fieldStudent{
String columnName();
String type();
int length();
}
//程序輸出
@JavaDoc.Table(value=db_User)
db_User
db_name
varchar
3
總結(jié)
以上是生活随笔為你收集整理的java注解的反射_Java注解与反射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: iOS 14 自带的应用被删除,如何恢复
- 下一篇: java 8 排序反转_Java 8 排