Java註解與反射

Java註解與反射

Java.Annotationjava

Java.Comment程序員

Java.Reflection編程

第一章: 註解

1.1 什麼是註解?

◆ Annotation是從JDK5.0開始引入的新技術c#

◆ Annotation的做用:數組

不是程序自己,能夠對程序做出解釋(這一點和註釋(comment沒什麼區別)安全

能夠被其餘程序(好比編譯器等)讀取 (這一點的咱們能夠利用,動態的寫程序)ide

◆ Annotation的格式:函數

註解是以@註釋名"在代碼中存在的,還能夠添加一些參數值,例如:@SuppressWarnings(value="unchecked")性能

◆ Annotation在哪裏使用?測試

能夠附加在package, class, method, field等上面,至關於給他們添加了額外的輔助信息,咱們能夠經過反射機制編程實現對這些元數據的訪問

1.2 內置註解

  1. @Override:定義在java.lang. Override中,此註釋只適用於修辭方法,表示一個方法聲明打算重寫超類中的另外一個方法聲明

  2. @Deprecated:定義在java.lang. Deprecated中,此註釋能夠用於修辭方法,屬性,類,表示不鼓勵程序員使用這樣的元素,一般是由於它很危險或者存在更好的選擇

  3. @SuppressWarnings:定義在java.lang SuppressWarnings中用來抑制編譯時的警告信息

與前兩個註釋有所不一樣你須要添加一個參數才能正確使用,這些參數都是已經定義好了的,
咱們選擇性的使用就行了

@SuppressWarnings("all")   
@SuppressWarnings("unchecked")                                                                              
@SuppressWarnings(value={"unchecked", "deprecation"})
等等

測試代碼:

public class Test01 extends Object {
    /**
     * 重寫的註解
     * @return
     */
    @Override
    public String toString() {
        return "Test01{}";
    }

    /**
     * 聲明過時操做
     * 註解來聲明過時的不建議使用的方法
     */
    @Deprecated
    public static void test() {
        System.out.println("Deprecated");
    }

    /**
     * 壓制警告,若是使用了不安全的操做,程序在編譯時必定會出現安全警告
     * 這時可使用@SuppressWarnings壓制全部出現的警告信息
     */
    @SuppressWarnings("all")
    public void test02() {
        List list = new ArrayList<>();
    }
    
}

1.3 元註解

◆元註解的做用就是負責註解其餘註解,java定義了4個標準的meta- -annotation類型他們被用來提供對其餘 annotation類型做說明.

◆這些類型和它們所支持的類在java.lang. annotation包中能夠找到(@Target,@Retention,
@Documented, @Inherited

@Target:用於描述註解的使用範圍(即被描述的註解能夠用在什麼地方)

@Retention:表示須要在什麼級別保存該註釋信息,用於描述註解的生命週期
(SOURCE< CLASS< RUNTIME)

@Document:說明該註解將被包含在 javadoc中

@Inherited:說明子類能夠繼承父類中的該註解

1.@Target

@Target(ElementType.METHOD)

ElementType 裏面出現的類型

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,
    TYPE_PARAMETER,
    TYPE_USE
}

2.Retention

參數RetentionPolicy,一個枚舉類型,

runtime >> class >> source,就是咱們在定義的時候,定義在運行狀態的話,最高狀態,也能夠在其餘兩個狀態起效果

//2.表示咱們的註解在什麼地方還有效
//runtime > class > source
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,
    CLASS,
    RUNTIME
}

3.@Documented

表示是否將咱們的註解生成在JAVAdoc中

4.@Inherited

子類能夠繼承父類的註解

1.4自定義註解

使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation接口

分析:

  1. @ interface用來聲明一個註解,格式 public@ interface註解名{定義內容}
  2. 其中的每個方法其實是聲明瞭一個配置參數.
  3. 方法的名稱就是參數的名稱
  4. 返回值類型就是參數的類型(返回值只能是基本類型,Class, String,enum)
  5. 能夠經過 default來聲明參數的默認值創新好課程
  6. 若是隻有一個參數成員,通常參數名爲 value
  7. 註解元素必需要有值,咱們定義註解元素時,常用空字符串0做爲默認值

註解參數的配置,只有一個參數的時候

/**
 * @author jiayadong
 */
@interface MyAnnotation3{
    String value();
}

使用的時候,咱們能夠不使用參數名字,直接輸入字符串

@MyAnnotation3("hello")
    public void fun() {
        
    }

多個參數的時候,咱們使用註解的時候,輸入參數的時候,能夠不按參數順序輸入.

@interface MyAnnotation{
//    註解的參數:參數類型+參數名();
    String name() default "";
    int age() default 0;
    int id() default -1;    //若是默認值爲-1,表明不存在

    String[] school() default {"中山大學","北京大學"};

}
@MyAnnotation(age = 12)
    public void test() {}

第二章:反射

靜態語言VS動態語言

動態語言
是一類在運行時能夠改變其結構的語言例如新的函數、對象、甚至代碼能夠被引進,已有的函數能夠被刪除或是其餘結構上的變化。通俗點說就是在運行時代 碼能夠根據某些條件改變自身結構
主要動態語言: Object--c、c#、 JavaScript、PHP、 Python等

靜態語言

Java不是動態語言,但Java能夠稱之爲「動態語言」。即java有必定的動態性, 咱們能夠利用反射機制得到相似動態語言的特性。java的動態性讓編程的時候更加靈活!

2.1 JAVA反射機制概述

Reflection(反射)是Java被視爲動態語言的關鍵,反射機制容許程序在執行期藉助於 Reflection API取得任何類的內部信息,並能直接操做任意對象的內部屬性及方法

Class c=Class forName("java.lang.String");

加載完類以後,在堆內存的方法區中就產生了一個 Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結構信息,咱們能夠經過這個對象看到類的結構,這個對象就像一面鏡子,透過這個鏡子看到類的結構,因此 咱們形象的稱之爲:反射
image-20201008194718908

2.2.1 Java反射機制提供的功能

  1. 在運行時判斷任意一個對象所屬的類
  2. 在運行時構造任意一個類的對象
  3. 在運行時判斷任意一個類所具備的成員變量和方法>在運行時獲取泛型信息
  4. 在運行時調用任意一個對象的成員變量和方法
  5. 在運行時處理註解
  6. 生成動態代理

2.2.2 Java反射優勢和缺點

優勢

能夠實現動態建立對象和編譯,體現出很大的靈活性

缺點

對性能有影響。使用反射基本上是一種解釋操做,咱們能夠告訴JVM,咱們但願
作什麼而且它知足咱們的要求。這類操做老是慢於直接執行相同的操做

2.2.3 反射相關的主要的API

java.lang.Class:表明一個類
java.lang.reflect.Method:表明類的方法
java.lang.reflect.Field:表明類的成員變量
java.lang.reflect.Constructor:表明類的構造器

在 Object類中定義瞭如下的方法,此方法將被全部子類繼承

public final Class getClass()

以上的方法返回值的類型是一個Class類,此類是Java反射的源頭,實際上所謂反射從程序的運行結果來看也很好理解,即:能夠經過對象反射求出類的名稱。

image-20201008210604223

2.2理解Class類並獲取Class實例

2.2.1 獲取Class類的幾種方式

對象照鏡子後能夠獲得的信息:某個類的屬性方法和構造器、某個類到底實現了哪些接口 對於每一個類而言,JRE都爲其保留一個不變的 Class類型的對象。一個 Class對象包含了特 定某個結(class/interface/enum/annotation/primitive type/void []的有關信息

  1. Class自己也是一個類
  2. Class 對象只能由系統創建對象
  3. 一個加載的類在JVM中只會有一個Class實例
  4. 一個Class對象對應的是一個加載到JVM中的一個.class文件
  5. 每一個類的實例都會記得本身是由哪一個Class實例所生成
  6. 經過Class能夠完整地獲得一個類中的全部被加載的結構
  7. Class類是Reflection的根源,針對任何你想動態加載、運行的類,惟有先得到相應的Class對象
方法名 功能說明
static ClassforName(String nam) 返回指定類名name的Class對象
Object newInstance() 調用缺省構造函數,返回Class對象的一個實例
getName() 返回Class對象所表的實體(類.接口,數組類或void)的名稱
Class getSuperClass() 返回當前Class對象的父類的Class對象
Class[] getInterface() 返回當前Class對象的接口
ClassLoader getClassLoader() getClassLoader()
返回類的類加載器。
Constructor<?>[] getConstructors()
返回包含一個數組 Constructor對象反射由此表示的類的全部公共構造 類對象。
方法[] getMethods()
返回包含一個數組 方法對象反射由此表示的類或接口的全部公共方法 類對象,包括那些由類或接口和那些從超類和超接口繼承的聲明。
Field[] getFields()
返回包含一個數組 Field對象反射由此表示的類或接口的全部可訪問的公共字段 類對象。

a)若已知具體的類,經過類的class屬性獲取,該方法最爲安全可靠,程序性能最高。

 

b)已知某個類的實例,調用該實例的 getClass()方法獲取lass對象

 

c)已知一個類的全類名,且該類在類路徑下,可經過 Classfor類的靜態方法 Name(獲取可能拋出 ClassNotFound Exception)

d)內置基本數據類型能夠直接用類名.Type

e)還能夠利用ClassLoader咱們以後講解

測試類:測試獲取Class類的幾種方式

package com.rango.reflection;

/**
 * @program: 註解和反射01
 * @description: 測試Class類的建立方式有哪些
 * @author: JiaYadong
 * @create: 2020-10-08 21:53
 **/
public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("這我的是: "+person.name);
//        方式一:經過對象得到
        Class c1 = person.getClass();
        System.out.println("getClass得到的:"+c1.hashCode());
//        方式二:forName得到
        Class c2 = Class.forName("com.rango.reflection.Student");
        System.out.println("Class.forName"+c2.hashCode());
//        方式三:類.class 得到
        Class c3 = Student.class;
        System.out.println("類.class"+c3.hashCode());
//         方式四: 基本內置類型的包裝類都有一個Type屬性
        Class c4 = Integer.TYPE;
        System.out.println(c4.getName());
//        得到父類類型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);
    }
}
class Person {
    String name;

    public Person() {
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

class Student extends Person {
    public Student() {
        this.name="學生";
    }
}

class Teacher extends  Person{
    public Teacher() {
        this.name="老師";
    }
}

2.3類的加載與ClassLoader

2.4建立運行時類的對象

2.5獲取運行時類的完整結構

2.6 調用運行時類的指定結構

能夠實現動態建立對象和編譯,體現出很大的靈活性

缺點 >對性能有影響。使用反射基本上是一種解釋操做,咱們能夠告訴JVM,咱們但願 作什麼而且它知足咱們的要求。這類操做老是慢於直接執行相同的操做

相關文章
相關標籤/搜索