基礎(chǔ)
package com.hbut.demo01;
import java.lang.annotation.*;
public class test01 {
}
//定義一個(gè)注解
//Target表示我們的注解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention 表示我們的注解用在什么地方有效
//runtime>classs>sources
@Retention(value = RetentionPolicy.RUNTIME)
//Documented表示是否我們的注解生成JAVAdoc中
@Documented
//Inherited 子類可以繼承父類的注解
@interface MyAnnotation{
}
自定義注解
package com.hbut.demo01;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class test01 {
//注解可以顯示賦值凌埂,如果沒有賦值陨瘩,我們就必須給注解賦值
@MyAnnotation1(age = 18,name = "wcw")
public void test1(){
}
@MyAnnotation2("") //只有一個(gè)參數(shù)時(shí)刃宵,使用value()痕届,可以省去命名
public void test2(){
}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation1{
//注解的參數(shù):參數(shù)類型 + 參數(shù)名()韧献;
String name();
int age();
int id() default -1; //如果默認(rèn)值為-1,代表不存在
String[] schools() default {"清華大學(xué)","北京大學(xué)"};
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
String value();
}
反射
動(dòng)態(tài)語言是一類在運(yùn)行時(shí)可以改變其結(jié)構(gòu)的語言研叫,Java不是動(dòng)態(tài)語言锤窑,但Java可以稱之為“準(zhǔn)動(dòng)態(tài)語言”,因?yàn)镴ava具有反射機(jī)制嚷炉。
- 反射機(jī)制允許程序在執(zhí)行期間借助于Reflection API取得任何類的內(nèi)部信息渊啰,并能夠直接操作任意對(duì)象的內(nèi)部屬性及方法
- 加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個(gè)Class類型的對(duì)象(一個(gè)類只有一個(gè)Class對(duì)象)申屹,這個(gè)對(duì)象就包含了完整的類的結(jié)構(gòu)信息绘证。我們可以通過這個(gè)對(duì)象看到類的結(jié)構(gòu)。
正常方式:引入需要的“包類”名稱-->通過new實(shí)例化-->取得實(shí)例化對(duì)象
反射方式: 實(shí)例化對(duì)象-->getClass()方法-->得到完整的“包類”名稱
簡(jiǎn)單的來說:
1.通過new關(guān)鍵字創(chuàng)建對(duì)象操作對(duì)象哗讥,在編譯時(shí)就已經(jīng)確定嚷那。
2.通過反射可以在程序運(yùn)行過程中動(dòng)態(tài)的操作對(duì)象,可以獲得編譯期無法獲得的信息杆煞,動(dòng)態(tài)操作最大限度發(fā)揮了java擴(kuò)展性
得到Class類的幾種方式
- 方式一:通過對(duì)象獲得
- 方式二:forname獲得 alt+enter 拋出異常
- 方式三: 通過類名.class獲得
- 基本內(nèi)置類型的包裝都有一個(gè)Type屬性
package com.hbut.demo01;
//測(cè)試class類的創(chuàng)建方式有哪些
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("this is" + person.name);
//方式一:通過對(duì)象獲得
Class c1 = person.getClass();
System.out.println(c1);
//方式二:forname獲得 alt+enter 拋出異常
Class c2 = Class.forName("com.hbut.demo01.Student");
System.out.println(c2.hashCode());
//方式三: 通過類名.class獲得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//基本內(nèi)置類型的包裝都有一個(gè)Type屬性
Class c4 = Integer.TYPE;
System.out.println(c4);
//獲得父類類型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
public String name;
//alt+insert創(chuàng)建有參無參構(gòu)造器
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
this.name = "學(xué)生";
}
}
class Teacher extends Person{
public Teacher() {
this.name = "老師";
}
}
所有類型的的Class對(duì)象
類加載內(nèi)存分析
以上是準(zhǔn)備階段:
- 加載: 將class文件字節(jié)碼內(nèi)容加載到內(nèi)存中魏宽,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換成方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)腐泻,然后生成一個(gè)代表這個(gè)類的java.lang.class對(duì)象
- 鏈接 :驗(yàn)證、準(zhǔn)備(正式為類變量(static)分配內(nèi)存并設(shè)置類變量默認(rèn)初始值的階段队询,這些內(nèi)存都將在方法去中進(jìn)行分配派桩,例如初始將m賦值為0)、解析
- 初始化: 執(zhí)行類構(gòu)造器<clinit>()方法蚌斩,將類變量的賦值動(dòng)作很靜態(tài)代碼塊中的語句合并(m = 300,m = 100合并)
分析類初始化
一般new一個(gè)類的對(duì)象和反射調(diào)用會(huì)發(fā)生類的初始化
package com.hbut.demo01;
public class Test04 {
static {
System.out.println("Main加載");
}
public static void main(String[] args) throws ClassNotFoundException {
//主動(dòng)引用
//Son son = new Son();
//反射也會(huì)產(chǎn)生主動(dòng)引用
//Class.forName("com.hbut.demo01.Son");
//子類直接調(diào)用父類靜態(tài)方法不會(huì)加載子類
//System.out.println(Son.b);
//數(shù)組定義類引用也不會(huì)出發(fā)類的初始化 Son[] array = new Son[5];
}
}
class Father{
static int b =10;
static {
System.out.println("父類加載");
}
}
class Son extends Father{
static int a =9;
static {
System.out.println("子類加載");
}
}
類加載器
獲取運(yùn)行時(shí)類的完整結(jié)構(gòu)
動(dòng)態(tài)創(chuàng)建對(duì)象執(zhí)行方法
[圖片上傳失敗...(image-414ea6-1582088834062)]
[圖片上傳失敗...(image-22649f-1582088834062)]
package com.hbut.demo01;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class demo02 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//獲取Class對(duì)象
Class c1 = Class.forName("com.hbut.demo01.User");
//構(gòu)造一個(gè)對(duì)象
User user = (User) c1.newInstance(); //本質(zhì)上是調(diào)用了類的無參構(gòu)造器
System.out.println(user);
//通過構(gòu)造器創(chuàng)建對(duì)象
Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
User user2 = (User)constructor.newInstance("wcw",16103,23);
System.out.println(user2);
//通過反射調(diào)用普通方法
User user3 = (User)c1.newInstance();
//通過反射獲取一個(gè)方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke:激活的意思
//(對(duì)象铆惑,"方法的值")
setName.invoke(user3,"王成武");
System.out.println(user3.getName());
//通過反射操作屬性
System.out.println("*****************");
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有屬性,我們需要關(guān)閉程序的安全檢測(cè)凳寺,屬性或者方法的setAccessible(True)
name.setAccessible(true); //
name.set(user4,"王成武");
System.out.println(user4.getName());
}
}