1. 程式人生 > >Java反射機制的深入應用

Java反射機制的深入應用

前言

在上一篇文章中介紹了Java反射的基本概念以及基本應用,不熟悉的朋友可以點這裡
本篇文章將重點介紹反射機制的深入應用

反射除了可以取得一個類的完整結構外,還可以呼叫類中的指定方法或指定屬性,並且可以通過反射完成對陣列的操作。

通過反射呼叫類中的方法

如果要使用反射呼叫類中的方法可以通過Method類完成,操作步驟如下:
(1) 通過Class類的getMethod(String name,Class….parameterTypes)方法取得一個Method的物件,並設定此方法操作時所需要的引數型別。
(2)之後可以使用invoke()進行呼叫,並向方法中傳遞要設定的引數。

下面通過一個具體的例子來為讀者演示操作,此操作主要完成呼叫Person類中sayChina()方法的功能。(person類的定義在上一篇文章)

import java.lang.reflect.Method;
public class invokeSayChinaDemo{
public static void main(String[] args){
Class<?> c1=null;  //宣告Class物件
try{
   c1=Class.forName("org.ljz.demo.Person"); //例項化Class物件 
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try
{ Method met=c1.getMethod("sayChina"); //此方法沒有引數 met.invoke(c1.newInstance()); //呼叫方法,必須傳遞物件例項 }catch(Exception e){ e.printStackTtace(); } } }

程式執行結果:

作者: ljz, 國籍: China

以上程式通過Class類的getMethod()方法根據一個類中的方法名稱取得Method物件,並通過invoke()呼叫指定的方法。在使用invoke()方法時必須傳入一個類的例項化物件,因為在sayChina()方法上沒有任何的引數,所以此處沒有設定引數型別和引數內容,本程式的操作如圖所示
這裡寫圖片描述

下面再為讀者演示一個向方法中傳遞引數的例項,以呼叫Person類中的sayHello(String name;int age)方法為例,此方法需要傳遞兩個引數。

package org.ljz.demo.invokedemo;
import java.lang.reflect.Method;
public class invokeSayHelloDemo{
public static void main(String[] args){
class<?> c1=null;      //宣告Class物件
try{
c1=Class.forName("org.ljz.demo.Person"); //例項化Class物件
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try{
Method met=c1.getMethod("sayHello", String.class,int.class);  //此方法需要兩個引數
String rv=null;    //接收方法的返回值
//呼叫方法,必須傳遞物件例項,同時傳遞兩個引數值
rv=(String)met.invoke(c1.newInstance(),"ljz",23);
System.out.println(rv);
}catch(Exception e){
e.printStackTrace();
     }
   }
}     

程式執行結果:

ljz,你好!我今年23歲了!

以上程式中,因為sayHello()方法本身要接收兩個引數,所以在使用getMethod()方法呼叫時除了要指定呼叫的方法名稱外,也需要接收引數的型別,由於sayHello()方法呼叫完之後存在返回值,而且返回值的型別是String,所以使用了一個字串接收方法返回的內容。

呼叫setter及getter方法

熟悉面向物件的讀者就知道”類中的屬性必須封裝,封裝之後的屬性要通過setter及getter”方法設定和取得,那麼在使用反射進行呼叫方法操作中,最重要的是呼叫類中的setter及getter方法,這一點在Java的開發中隨處可見,下面為讀者演示如何完成這樣的功能。直接呼叫Person類中的setter及getter方法

程式碼如下:

package org.ljz.demo.invokedemo;
import java.lang.reflect.Method;
public class InvokeSetGetDemo{
public static void main(String[] args){
Class<?> c1=null;   //宣告Class物件
Object obj=null;   //宣告一個物件
try{
c1=Class.forName("org.ljz.demo.Person");//例項化物件
}catch(ClassNotFountException e){
e.printStackTrace();
}
try{
obj=c1.newInstance();  //例項化操作物件
}catch(InstantiationException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}
setter(obj,"name","ljz",String.class);   //呼叫setter方法
setter(obj,"age",23,int.class);  //呼叫setter方法
System.out.print("姓名:");  
getter(obj,"name");    //呼叫getter方法
System.out.print("年齡:");
getter(obj,"age");   //呼叫getter方法
}
/**
 *@param obj 操作的物件
 *@param att 操作的屬性 
 *@param value 設定的值 
 *@param type 引數的型別
 */ 
 public static void setter(Object obj,String att,Object value, Class<?> type){  //呼叫setter方法
try{
    Method met=obj.getClass().getMethod("set"+initStr(att),type);//設定方法引數型別
met.invoke(obj,value);  //呼叫方法
}catch(Exception e){
e.printStackTrace();
  }
}

public static void getter(Object obj,String att){ //呼叫getter方法
try{
    Method met=obj.getClass().getMethod("get" + initStr(att));  //此方法不需要引數
System.out.println(met.invoke(obj));  //接收方法的返回值
}catch(Exception e){
e.printStackTrace();
  }
}
public static String initStr(String old){  //單詞首字母大寫
String str=old.substring(0,1).toUpperCase()+old.substring(1);
return str;
 }
}

程式執行結果:

姓名: ljz
年齡:23

以上程式完成了呼叫類中setter及getter方法的功能,下面我們分步介紹本程式的思路

(1) 在設定方法名稱時,本程式直接傳入的是類中的屬性名稱,例如name或age。但是實際上方法名稱是setName(0,getName(),setAge(),getAge(),這樣,所有屬性名稱的首字母需要大寫,所以為了解決這樣的問題,單獨設定了一個方法initStr(),通過此方法將字串中的首字母大寫。首字母大寫之後在增加set及get字串以找到相應的方法。

(2)呼叫setter()方法時,傳入了例項化物件,要操作的屬性名稱(在方法中會將其首字母大寫),要設定的引數內容以及具體的引數型別,這樣做是為了滿足getMethod() 和invoke()方法的使用要求。

(3)在呼叫getter()方法時,也同樣傳入同一個例項化物件,因為其本身不需要任何的接收引數,所以只傳入屬性名稱(在方法中會將其首字母大寫), 並在此方法中將內容列印輸出。

以上程式是在反射呼叫方法時的重要應用,讀者一定掌握其原理。因為在以後的開發中,許多系統會為開發者實現好以上的功能。

通過反射操作屬性

在反射操作中雖然可以使用Method呼叫類中的setter及getter方法設定和取得屬性,但是這樣操作畢竟很麻煩,所以在反射機制中也可以直接通過Field類操作類中的屬性,通過Field類提供的set()和get()方法就可以完成設定和取得屬性內容的操作。但是在操作前首先需要注意的是,在類中的所有屬性已經都設定成私有的訪問許可權,所以在使用set()或get()方法時首先要使用Field類中的setAccessible(true)方法將需要操作的屬性設定成可以被外部訪問。

程式碼如下:

package org.ljz.demo.invokedemo;
import java.lang.reflect.Field;
public class invokeFieldDemo{
public static void main(String[] args) throws Exception{
Class<?> c1=null;    //宣告Class物件
Object obj=bull;     //宣告一個物件
c1=Class.forName("org.ljz.demo.Person");//例項化Class物件
obj=c1.newInstance();  //例項化物件
Field nameField=null;  //表示name屬性
Field ageField=null;  //表示age屬性
naneField=c1.getDeclaredField("name");//取得name屬性
ageField=c1.getDeclaredField("age");// 取得age屬性
nameField.set(obj,"ljz");   //設定name屬性內容
ageField.setAccessible(true); //將age屬性設定成可以被外部訪問
ageField.set(obj,23); //設定age屬性內容
System.out.println("姓名:"+nameField.get(obj));
System.out.println("年齡:"+ageField.get(obj));
   }
}   

程式執行結果:

姓名:ljz
年齡:23

從以上程式碼不難看出,明顯比之前使用setter或getter方法操作屬性的程式碼更加簡單,方便。

通過反射運算元組

反射機制不僅只能用在類上,還可以應用在任意的引用資料型別的資料上,當然,這也就包含了陣列,即可以使用反射運算元組。可以通過Class類的以下方法取得一個數組的Class物件。

public Class<?> getComponentType()

在反射操作包java.lang.reflect中使用Array類表示一個數組,可以通過此類取得陣列長度,取得陣列內容的操作。Array類的常用方法如下所示:
這裡寫圖片描述

下面通過兩個範例讓讀者瞭解以上方法的使用

1. 取得陣列資訊並修改陣列內容

package org.ljz.arraydemo;
import java.lang.reflect.Array;
public class ClassArrayDemo{
public static void main(String[] args)throws Exception{
int temp[]={1,2,3}; //宣告一個整形陣列
Class<?> c=temp.getClass().getComponentType();//取得陣列的Class物件
System.out.println("型別" +c.getNmae()); //取得陣列型別的名稱
System.out.println("長度"+Array.getLength(temp));//得到陣列的長度
System.out.println("第一個內容:"+Array.get(temp,0));//得到第一個內容
Array.set(temp,0,6);   //修改第一個內容
System.out.println("第一個內容"+Array.get(temp,0));//得到第一個內容
  }
 } 

程式執行結果:

型別: int
長度:3
第一個內容:1
第一個內容: 6

以上程式中通過Array類取得了陣列的相關資訊,並通過Array類中的set()方法修改了陣列中的元素內容。

在應用中還可以通過Array類根據自己已有的陣列型別來開闢新的陣列物件,下面我們就來使用Array完成一個可以修改已有陣列大小的功能。

2.修改陣列的大小

package org.ljz.arraydemo
import java.lang.reflect.Array;

public class ChangeArrayDemo{
public static void main(String[] args)throws Exception{
int temp[]={1,2,3};
int newTemp[]=(int[])arrayInc(temp,5);//擴大陣列的長度
String t[]={"zhangsan","lisi","wangwu"};//宣告一個字串陣列
String nt[]=(String[])arrayInc(t,6);//擴大陣列長度
print(nt);//列印陣列資訊
}

public static Object arrayinc(Object obj,int len){ //修改陣列長度
Class<?> c=obj.getClass(); //通過陣列得到Class物件
Class<?> arr=c.getComponentType();//得到陣列的Class物件
Object newO=Array.newInstance(arr,len);//重新開闢新的陣列空間
int co=Array.getLength(obj);//取得陣列長度
System.arraycopy(obj,0,newO,0,co)//複製陣列內容
return newO;
}

public static void print(Object obj){ //輸出陣列
Class<?> c=obj.getClass();  //通過陣列得到Class物件
if(!c.isArray()){
 //判斷是否是陣列
return;
}
Class<?> arr=c.getComponentType();//取得陣列的Class
System.out.println(arr.getName()+"陣列的長度:"+Array.getLength(obj));//輸出陣列的資訊
for(int i=0;i<Array.getLength(obj);i++){  //迴圈輸出
System.out.print(Array.get(obj,i)+",");//通過Array輸出
   }
  }
 }  

程式執行結果:

int陣列的長度是:5
1,2,3,4,5
java.lang.String陣列的長度是6
zhangsan ,lisi, wangwu, null, null, null

後續

下一篇我將介紹動態代理以及反射應用到工廠設計模式的相關應用,感興趣的朋友可以關注一下!

相關推薦

Java反射機制深入詳解

const 運行時 設計 應用程序 類加載器 分配 import 程序 為什麽 一.概念   反射就是把Java的各種成分映射成相應的Java類。   Class類的構造方法是private,由JVM創建。   反射是java語言的一個特性,它允程序在運行時(註意不是編譯的

Java 反射機制應用例項

Java 反射機制的應用例項 1. Java Reflection 2. Java 反射機制提供的功能 3. Java反射機制研究及應用 4. dome 1. Java Reflection R

Java反射機制深入研究

Java反射是Java語言的一個很重要的特徵,它使得Java具體了“動態性”。 在Java執行時環境中,對於任意一個類,能否知道這個類有哪些屬性和方法?對於任意一個物件,能否呼叫它的任意一個方法?答案是肯定的。這種動態獲取類的資訊以及動態呼叫物件的方法的功能來自於Java語言的反射(Reflection

JAVA反射機制應用場景

 Member類:package test; public class Member { private String username; private String password; private String truename; private String

Java反射機制深入應用

前言 在上一篇文章中介紹了Java反射的基本概念以及基本應用,不熟悉的朋友可以點這裡 本篇文章將重點介紹反射機制的深入應用 反射除了可以取得一個類的完整結構外,還可以呼叫類中的指定方法或指定屬性,並且可以通過反射完成對陣列的操作。 通

Java反射機制能夠獲取的信息,與應用

rri 代理 pan [] reflect 語言 子類 list tro 一、什麽是Java反射機制? 【1】反射機制是在運行狀態中,對於任何一個類,都能夠知道這個類的所有屬性和方法; 【2】對於任意一個對象,都能夠調用它的任意一個屬性和方法; 像這種動態獲取類的信

Java反射機制的簡單應用

mod arc pos ret system containe java反射機制 track san 一直感覺java的反射機制非常強大,可是可用的地方不多。在android學習的時候。一直想實現掛斷電話的功能,可是

java反射機制應用之動態代理

代理類 過多 size bject interface 並且 編譯期 代理 抽象 1.靜態代理類和動態代理類區別 靜態代理:要求被代理類和代理類同時實現相應的一套接口;通過代理類的對象調用重寫接口的方法時,實際上執行的是被代理類的同樣的 方法的調用。 動態代理:在程序運

Java高階程式設計開發之反射機制應用

瞭解反射機制之前,我們要明確一點,java語言是面向物件程式設計的開發語言。所以,在java的世界中,萬物皆物件。 那麼這樣的話,我們在程式設計開發過程中,所建立的類是不是物件呢?是誰的物件呢?是哪個類的物件呢? 答案是肯定的。類也是物件,它是java.lang.Clas

Java反射機制的原理及在Android下的簡單應用

package crazypebble.reflectiontest;import java.lang.reflect.Constructor;import java.lang.reflect.Method;publicclass LoadMethod { /** * 在執行時載入指定的類,並呼

java反射機制詳解和應用

1反射機制是什麼 反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。 2反射機制能做什麼 反射機制主要提供了以下功能: 在執行

深入理解java反射機制

轉載自:https://blog.csdn.net/u012585964/article/details/52011138一,java的核心機制        java有兩種核心機制:java虛擬機器(JavaVirtual Machine)與垃圾收集機制(Garbage c

Java反射機制在工廠模式中的應用

在本篇文章中就不詳細介紹工廠模式,主要介紹一下反射在工廠模式中的使用,讓讀者對反射機制帶來的好處有更深的認識。 首先看一下簡單工廠模式 簡單工廠模式(simple factory)是類的建立模式,又叫靜態工廠方法(static factory method)模式。 簡單工廠

java中的反射三(反射機制深入---對陣列的操作)

反射機制對陣列的操作1 取得陣列的Class物件以及相關屬性和方法 public class ClassArrayDemo{ public static void main(String args[]) throws Exception{ int temp[] = {

深入探尋Java反射機制 (Class)

Classes 通過反射機制我們可以在執行時探尋類的內部結構,並獲取以下資訊 Class NameClass Modifiers (public, protected, synchronized等)Package InfoSuper ClassImplemented In

深入探尋Java反射機制

通過Java的反射(Reflection)機制,即使在編譯時不知道class name和method name等資訊,也可以在執行時獲取class、interface、fields和methods等相關資訊,還可以建立新的例項、呼叫方法以及獲取/設定屬性值。 本文將介

java反射機制的業務應用場景-1

       好久不寫東西,最近整理之前的東西時發現以前有一些寫好的東西,其實都是一些學習筆記或是對某個技術理解的一些感想,覺得很有意思,拿出來和大家分享一下。        這篇文章我們先來說一下java的反射機制,java的反射機制其實在1.2的時候就已經有了,那時我們

【原】Java反射機制的原理及在Android下的簡單應用

轉載地址:http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014582.html   花了幾天時間,研究了一下Java的反射機制。在這裡總結一下這幾天學習的成果,一來分享自己的學習過程

深入理解java反射機制中Method類中的invoke()方法

1.先說明Method類中的幾個重要的屬性 1)Method型別的root屬性: 可以理解為每一個 java方法都有唯一的一個Method物件,這個物件就是root,我們可以利用反射建立java方法的眾多的Method類的物件,這些物件指向root,可以理解為root的映象

java反射機制

else ++ 類型 應該 動態 error param 字母 什麽 最近在做一個項目。 需求是這樣的,前端傳一個參數param表示要從服務器獲取的參數,後端需要把對應的參數從服務器中取出來。 本來覺得沒什麽,應該蠻簡單。結果一看表,嗯,40多個參數,如果用if...els