1. 程式人生 > >java高階特性之反射

java高階特性之反射

獲取父類的泛型

java反射概述

java Reflection,java中的反射(Reflection)被認為是動態語言的關鍵,反射機制允許程式在執行期藉助Reflection API取得任何類的內部資訊。並且能直接操作任意物件的內部屬性和方法。

簡單來說,反射就是載入類,並解剖出類的各個組成部分。

java反射機制提供的功能:

在執行時判斷任意一個物件所屬的類
在執行時構造任意一個類的物件
在執行時判斷任意一個類所具有的成員變數和方法
在執行時呼叫任意一個物件的成員變數和方法 生成動態代理

與java反射相關的類:

java.lang.Class: 一個例項代表了一個執行時類
java.lang.reflect.Method:代表類的方法
java.lang.reflect.Field:代表類的成員變數
java.lang.reflect.Constructor:代表類的構造方法

我們知道java的基類是Object類,其以下方法:

public final Class getClass() 方法返回值的型別是一個Class類,值是當前物件的類(如Person.class),而此時的這個類作為Class類的一個例項。

Class類是Java反射的源頭,實際上所謂反射從程式的執行結果來看也很好理解,即:可以通過物件反射求出類的名稱。

正常情況下例項化物件的過程如下:

通過 類,new例項化物件。

反射機制通過 當前物件,getClass()方法返回當前物件的類。

Class類

通過反射可以得到的資訊:某個類的屬性、方法和構造器、某個類到底實現了哪些介面,方法的返回值型別,等等資訊。

對於每個類而言,JRE 都為其保留一個不變的 Class 型別的物件。一個 Class 物件包含了特定某個類的有關資訊。

1,Class本身也是一個類
2,Class 物件只能由系統建立物件(jvm)
3,一個類在 JVM 中只會有一個Class例項
4,一個Class物件對應的是一個載入到JVM中的一個.class檔案
5,每個類的例項都會記得自己是由哪個 Class 例項所生成
6,通過Class可以完整地得到一個類中的完整結構
理解: * java程式經過javac.exe命令後,會生成一個或多個.class位元組碼檔案.接著使用java.exe命令,呼叫JVM的類的載入器

  • 將位元組碼檔案載入到記憶體中(存放在快取區),一個位元組碼檔案就對應著一個執行時類。這個載入到記憶體中的執行時類本身就充當了Class的一個例項。

  • 一個Class的例項就對應著一個執行時類

  • 執行時類只會在記憶體中載入一次。

Class類的常用方法:

Class 沒有公共構造方法。Class 物件是在載入類時由 Java 虛擬機器以及通過呼叫類載入器中的 defineClass 方法自動構造的。

static Class forName(String name) 返回指定型別name的Class物件,name是包含限定名的類,例如:”java.lang.Object”

Object newInstance();呼叫預設無參構造器,返回Class物件的一個例項

String getName() 返回此Class物件所表示的實體(類、介面、陣列類、基本型別 或void)名稱,

Class getSuperClass()返回當前Class物件的父類的Class物件

Class[] getInterface()獲取當前Class物件的介面

ClassLoader getClassLoader()返回該類的類載入器

Class getSuperClass()返回表示此Class例項的超類的Class 物件

Constructor[] getDeclaredConstructors()返回一個含Constructor物件的陣列 Field[] getDeclaredFields()返回Field物件的一個數組

Method getMethod(String name,Class…paramType) 返回一個Method物件,此物件的形參型別為Class paramType

獲取Class類物件的幾種方法

1)前提:若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程式效能最高

例項:Class clazz = String.class;dd//String的class屬性
2)前提:已知某個類的例項,呼叫該例項的getClass()方法獲取Class物件
例項:Class clazz =new Person().getClass();
3)前提:已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取,可能丟擲ClassNotFoundException例項:Class clazz = Class.forName(“java.lang.String”);
4)其他方式//通過當前類的類載入器

ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“全類名”);
示例分析:

通過Class類的靜態方法forName(“全類名”)獲取其例項

Class clazz = Class.forName(“com.atguigu.exer.Person”);

通過Class物件的getDeclaredMethod(“方法名”,Class型別的形參)方法,獲取Class物件的方法。

Method eat = clazz.getDeclaredMethod(“eat”, String.class);

物件方法呼叫setAccessible()方法設定當前物件( )的可訪問許可權·· eat.setAccessible(true);

通過Class物件建立其型別的物件

Person p1 = (Person)clazz.newInstance();

物件方法呼叫invoke(Object 物件, 實參),並將該方法的返回結果以Object物件的形式返回;

若是靜態方法或者靜態屬性可以使用類名.class的形式代替類的例項。

Object result = eat.invoke(p1, “apple”);

Field nation = clazz.getDeclaredField(“nation”);

nation.setAccessible(true);

nation.set(Person.class, “china”);

Object nationValue = nation.get(Person.class);

System.out.println(nationValue);

Constructor con =

clazz.getDeclaredConstructor(String.class,Integer.class,String.class);

con.setAccessible(true);

Object object = con.newInstance(“tom”,23,”China”);

System.out.println(object);

//注意的情況,int對應的class類為int.class,不能使用Integer.class.

獲取父類的泛型:

Class clazz = Person.class;

Type gen = clazz.getGenericSuperclass();

ParameterizedType gensup = (ParameterizedType) gen;

Type[] type = gensup.getActualTypeArguments();

System.out.println(((Class)type[0]).getName());

類載入的過程:

當程式主動使用某一個類的時候,若該類還沒有載入到記憶體中,則系統會通過如下方式首次載入該類,並進行初始化。

1,將類的class檔案讀入到記憶體中,並自動為之建立一個java.lang.Class類的物件。此過程由類的載入器完成。【類檔案的載入】

2,將類的二進位制資料合併到JRE中。【類資料的連線】

3,JVM負責將類進行初始化。

類載入器的瞭解:

類載入器(ClassLoader)是用來把類(class)裝載進記憶體的。JVM 規範定義了兩種型別的類載入器:啟動類載入器(bootstrap)和使用者自定義載入器(user-defined class loader)。

JVM在執行時會產生3個類載入器組成的初始化載入器層次結構如下:

引導類載入器(Bootstap Classloader):用C++編寫的,是JVM自帶的類裝載器,負責Java平臺核心庫,用來裝載核心類庫。該載入器無法直接獲取。

擴充套件類載入器(Extension ClassLoader):負責jre/lib/ext目錄下的jar包或 –d java.ext.dirs 指定目錄下的jar包裝入工作庫

系統類載入器(System ClassLoader):負責java –classpath 或 –D java.class.path所指的目錄下的類與jar包裝入工作 ,是最常用的載入器。

//1.獲取一個系統類載入器ClassLoader classloader = ClassLoader.getSystemClassLoader();

//2.獲取系統類載入器的父類載入器,即擴充套件類載入器classloader = classloader.getParent();

//3.獲取擴充套件類載入器的父類載入器,即引導類載入器classloader = classloader.getParent();

獲取當前類的載入器(主要通過Class物件的getClassLoader()方法獲取)

ClassLoader classloader =

Class.forName(“com.atguigu.reflection.Customer”).getClassLoader();

關於類載入器的一個主要方法:
getResourceAsStream(String str):獲取當前類路徑下的指定檔案的輸入流
InputStream in = null;
in= this.getClass().getClassLoader().getResourceAsStream(“com\atguigu\reflection.properties”);

Properties pro = new Properties();

pro.load(is);

String user = pro.getProperty(“user”);

String pwd = pro.getProperty(“pwd”);
//properties檔案位於當前包路徑下

通過Class類物件能夠做些什麼?

建立類的物件:呼叫Class物件的newInstance()方法要求

1)類必須有一個無引數的構造器。
2)類的構造器的訪問許可權需要足夠。

難道沒有無參的構造器就不能建立物件了嗎? 在操作的時候明確的呼叫類中的構造方法,並將引數傳遞進去之後,才可以例項化操作。步驟如下:
1)通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參型別的構造器
2)向構造器的形參中傳遞一個物件陣列進去,裡面包含了構造器中所需的各個引數。
3)通過Constructor例項化物件。

示例:

//1.根據全類名獲取對應的Class物件
String name = “atguigu.java.Person”;
Class clazz = null;
clazz = Class.forName(name);

//2.呼叫指定引數結構的構造器,生成Constructor的例項
Constructor con = clazz.getConstructor(String.class,Integer.class);

//3.通過Constructor的例項建立對應類的物件,並初始化類屬性

Person p2 = (Person) con.newInstance(“Peter”,20);System.out.println(p2);

動態代理:

原理: 首先定義一個共同的介面,被代理類實現該介面, 使用一個代理類同樣實現該介面,並將被代理類的物件聚合到代理類中, 然後用該代理物件取代被代理物件. 任何對(被代理)原始物件的呼叫都要通過代理. 代理物件決定是否以及何時將方法呼叫轉到原始物件上。

java實現動態代理的類proxy:

Proxy :專門完成代理的操作類,是所有動態代理類的父類。
通過此類為一個或多個介面動態地生成實現類。 提供用於建立動態代理類和動態代理物件的靜態方法:
Class


//1定義介面

interface ManFunction{

String info(String string);

void fly();

}

//2實現被代理類

class Man implements ManFunction{

@Override

public String info(String str) {

return str;

}

@Override

public void fly() {

System.out.println("i can fly, you can?");

}

}

//3代理類實現 被代理 的介面

class MyHandler implements InvocationHandler{

Object obj;

public MyHandler(Object obj) {

this.obj = obj;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

return method.invoke(obj, args);

}

}

//4建立動態代理類

class ProxyObject {

public static Object getInstanceObject(Object obj){

MyHandler in = new MyHandler(obj);

Object newProxyInstance =
Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), in);

return newProxyInstance;

}

}

在測試類中注意的問題:
1,建立被代理類物件
2,動態代理類建立動態代理,由於生成的動態代理也實現了該介面,故而可以將其轉換為該介面型別,進而呼叫介面中的方法(也就是被代理類的方法)。

反射補充:

在呼叫反射到類的方法中引數是陣列的情況下,例如main(String[] args),由於java1.5版本才有了可變形參,而又要相容java1.4,故而java1.5之後反射到類的方法中有陣列形參時,都會預設將陣列拆開。例如:故而需要將陣列行參用object型別包裝。

在反射到某一個類的main(String [] args)方法,而又要呼叫這個方法。

Method method = clazz.getMethod(“main”,String[].class);

method.invoke(Person .class, new String[] ( “aa” ,”bb”)); 非法引數異常;

method.invoke(null, new Object[] {new String [] {” aa”, “bb”}});

或者

method.invoke(null,(Object ) new String[] {“aa”,”bb”});

反省introspector

javaBean,操作的欄位都稱為屬性

一個get或者set方法就稱為一個屬性。

使用內省introspector API 操作 bean的屬性。

相關推薦

java高階特性反射

獲取父類的泛型 java反射概述 java Reflection,java中的反射(Reflection)被認為是動態語言的關鍵,反射機制允許程式在執行期藉助Reflection API取得任何類的內部資訊。並且能直接操作任意物件的內部屬性和方法。 簡單來

Java高階特性new一個內部類

package three.day.newcharacter; class Outer {public static final int height = 20;public static int weight = 20;private int num = 100;//內建

java高階特性多執行緒

java多執行緒知識點: 1、建立分執行緒的方式 2、單例模式懶漢式執行緒安全問題 3、java執行緒同步 4、java執行緒通訊 5、java的記憶體模型 認識執行緒: 每一個java程式都有一個隱含的主執行緒,即main()方法。 程式–&g

Java高階特性列舉(二)

01.Enum不可以有public或者protected的構造方法,只能是private或friendly(就前面不用修飾符),這樣可以保證客戶程式碼不能新建一個Enum的例項,我們也不需要例項化Enum物件。    Enum定義的列表成員跟介面一樣都是public,sta

java高階特性泛型

泛型擦除 反射機制 自定義泛型類 自定義型別方法 java泛型別相關知識 1 為什麼使用泛型 解決元素儲存時候的安全性問題,同時解決獲取集合元素的時候型別強轉的問題。 提高程式碼的重用率。 例如編寫一個泛型類,而我們不去關心類的具體型別,而用T來

java高階特性IO流

緩衝流 轉換流 物件流 列印流 標準輸入輸出流 隨機訪問流 陣列流 有關flush():所有的處理流的輸出流,最外層流需要重新整理。 javaIO流 1認識File類 File類的物件表示一個檔案或者一個檔案目錄 絕對路徑:包含碟符的檔案完

Java高階特性集合

Java集合框架 一、Java集合框架概述 1、陣列與集合的區別: 1)陣列長度不可變化而且無法儲存具有對映關係的資料;集合類用於儲存數量不確定的資料,以及儲存具有對映關係的資料。 2)陣列元素既可以是基本型別的值,也可以是物件;集合只能儲存物件。 2、Java集合類主要由兩個根介面Collection和M

Java高階特性反射和動態代理

1).反射   通過反射的方式可以獲取class物件中的屬性、方法、建構函式等,一下是例項: 2).動態代理   使用場景:       在之前的程式碼呼叫階段,我們用action呼叫service的方法實現業務即可。     由於之前在service中實現的業務可能不能夠滿足當先客戶的要求,需要我們重

java特性反射

反射的定義 允許程式在執行時進行自我檢查,同時允許在執行時對內部成員進行操作 反射的核心是JVM在執行時才動態載入類或呼叫方法/訪問屬性,它不需要事先(寫程式碼的時候或編譯期)知道執行物件是誰。 Jav

Java高階特性(動態代理和反射

目錄第4天 java高階特性增強今天內容安排:1、掌握多執行緒2、掌握併發包下的佇列3、瞭解JMS4、掌握JVM技術5、掌握反射和動態代理Øjava多執行緒增強通俗來講:應用程式就是一個程序。不管是我們開發的應用程式,還是我們執行的其他的應用程式,都需要先把程式安裝在本地的硬

JAVA面向物件高階特性繼承(1)常見問題解答

1、什麼是繼承? 答:如果說A是一個B,則我們說A繼承自B。通過繼承來實現程式碼的複用。 2、Java中如何實現繼承?  答:Java類通過extends關鍵字實現繼承,所有的類都間接或者直接繼承自Object類。 3、Java中,有繼承關係時,變數隱藏的原則?  答:子類

Java學習java高階特性

本部分內容主要有集合框架及泛型,實用類,輸入和輸出處理,註解與多執行緒,網路程式設計與XML技術。初次學習這部分會感覺很難,主要是概念難於理解,最好是多看看例子,多練習。下面是個人的總結 一、集合框架及泛型1、集合框架是一套效能優良、使用方便的介面和類(位於java.util包中)解決陣列在儲存上不能很好適應

黑馬程式設計師-------Java高階特性--------反射

黑馬程式設計師—–Java高階特性—–反射 一.概述 Java 反射是Java語言的一個很重要的特徵,它使得Java具體了“動態性”。 這個機制允許程式在執行時透過Reflection APIs取得任何一個已知名稱的class的內部資訊,包括其mod

Java基礎學習筆記二十三 Java核心語法反射

負責 目錄 boolean tostring 筆記 str 編譯 三種 進制 類加載器 類的加載 當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,鏈接,初始化三步來實現對這個類進行初始化。 加載就是指將class文件讀入內存,並為之創建一個Clas

Java基礎加強反射

驅動 pri tostring reflect get api tcl 所有 hide 1.什麽是反射? 反射其實就是動態的加載類,我們在寫JDBC的時候加載驅動Class.forName("xxx")時就涉及到了反射。 反射機制是在運行狀態中,對於任意一個類,都能夠知

Java三大特性封裝

轉載請標明出處: http://blog.csdn.net/wu_wxc/article/details/51463610 本文出自【吳孝城的CSDN部落格】 封裝是將類的某些資訊和例項細節之類的隱藏在類的內部,方便修改和實現,只允許該類提供的方法進行訪問,如set,

python高階特性迭代與迭代器

全部測試程式碼 #! /usr/bin/env python3 #_*_ conding:utf-8 _*_ 迭代:Iterable #python中使用for ... in ...來迭代物件 #python的for迴圈抽象程度高,不僅可作用在list和tuple上,還可以在任何可

Java高階特性—鎖

1).synchronized   加同步格式:     synchronized( 需要一個任意的物件(鎖) ){       程式碼塊中放操作共享資料的程式碼。     }   synchronized的缺陷    synchronized是java中的一個關鍵字,也就是說是Java語言內建的特性。   

Java基礎總結反射

Java反射機制:是在執行狀態中,對於任意一個類,都能知道這個類的所有屬性和方法;對於任何一個物件都能夠呼叫它的任何一個方法說著屬性;這種動態獲取的資訊以及動態呼叫的物件的方法的功能成為Java語言的反射機制。 那麼,如果想解刨一個類的話,首先就要獲取到該類的位元組碼檔案物件:獲取方法有如下三種

PHP高階特性檔案處理

檔案系統函式用法詳述 1.基本的判斷函式 is_dir — 判斷給定檔名是否是一個目錄 is_file — 判斷給定檔名是否為一個檔案 is_executable — 判斷給定檔名是否可執行 is_link — 判斷給定檔名是