程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java通過反射創建對象實現教程

Java通過反射創建對象實現教程

編輯:關於JAVA
 

java可以在運行時動態獲取某個類的類信息,這就是java的反射。

一、通過反射創建不帶參數的對象

這個比較簡單,不需要獲取這個類的構造方法類,不需要指明構造參數的參數列表。下面是要使用的類和方法,使用步驟如下:

Class(類):

Class 類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數組屬於被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也表示為 Class 對象。

Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的。

以下示例使用 Class 對象來顯示對象的類名:

 

void printClassName(Object obj) { System.out.println("The class of " + obj + " is " + obj.getClass().getName()); }

這個類就是類對象,是具體某個類對象,通常我們說說的對象是,某個類的對象,而Class是類級別的對象,描述的類的信息。
例如String a=new String();
這個a指的是類String的對象,那麼什麼是類對象呢,看這個例子:
Class c=String.class;這個c就是String的類對象,描述的是String的信息。不是對象信息。

Class forName(String className):
返回與帶有給定字符串名的類或接口相關聯的 Class 對象。調用此方法等效於:
Class.forName(className, true, currentLoader)
其中 currentLoader 表示當前類的定義類加載器。
例如,以下代碼片段返回命名為 java.lang.Thread 的類的運行時 Class 描述符。

Class t = Class.forName("java.lang.Thread")
調用 forName("X") 將導致命名為 X 的類被初始化。

 

參數:
className - 所需類的完全限定名。
返回:
具有指定名的類的 Class 對象。
拋出:
LinkageError - 如果鏈接失敗
ExceptionInInitializerError - 如果此方法所激發的初始化失敗
ClassNotFoundException - 如果無法定位該類
通過指明類所在的具體位置來生成這個類的類對象。注意:className指明的是具體的這個類所在的位置,例如java內置的String類,那麼它的位置是 className=java.lang.String;如果自己創建的類,當加載到項目中後請也指明其具體的位置,例如有一個自己創建的類GameCanvas在 com.jijing.gameDemo中,className=com.jijing.gameDemo.GameCanvas;

public T newInstance();
創建此 Class 對象所表示的類的一個新實例。如同用一個帶有一個空參數列表的 new 表達式實例化該類。如果該類尚未初始化,則初始化這個類。
注意,此方法傳播 null 構造方法所拋出的任何異常,包括已檢查的異常。使用此方法可以有效地繞過編譯時的異常檢查,而在其他情況下編譯器都會執行該檢查。 Constructor.newInstance 方法將該構造方法所拋出的任何異常包裝在一個(已檢查的)InvocationTargetException 中,從而避免了這一問題。

 

返回:
此對象所表示的類的一個新分配的實例。
拋出:
IllegalAccessException - 如果該類或其 null 構造方法是不可訪問的。
InstantiationException - 如果此 Class 表示一個抽象類、接口、數組類、基本類型或 void; 或者該類沒有 null 構造方法; 或者由於其他某種原因導致實例化失敗。
ExceptionInInitializerError - 如果該方法引發的初始化失敗。
SecurityException - 如果存在安全管理器 s,並滿足下列任一條件:
調用 s.checkMemberAccess(this, Member.PUBLIC) 拒絕創建該類的新實例
調用者的類加載器不同於也不是當前類的類加載器的一個祖先,並且對 s.checkPackageAccess() 的調用拒絕訪問該類的包
這個方法是 Class類中的方法,且只能創建不帶任何參數的對象形式(構造函數沒有參數列表)。直接返回T模版類型的對象,自己要把它轉換為實際類型。

 

下面是實際例子:

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

String s=(String)c.newInstance();

 

二、創建帶參數的對象

創建帶參數的對象就比較復雜 ,由於構造函數不止一個,且參數列表參數類型不一要,所以自己要指明構造函數中的參數列表,自己也必須明確參數類型的傳入,否則會出現異常的。下面是一些類和方法的說明:

 

public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。parameterTypes 參數是 Class 對象的一個數組,這些 Class 對象按聲明順序標識構造方法的形參類型。 如果此 Class 對象表示非靜態上下文中聲明的內部類,則形參類型作為第一個參數包括顯示封閉的實例。
要反映的構造方法是此 Class 對象所表示的類的公共構造方法,其形參類型與 parameterTypes 所指定的參數類型相匹配。

 

參數:
parameterTypes - 參數數組
返回:
與指定的 parameterTypes 相匹配的公共構造方法的 Constructor 對象
拋出:
NoSuchMethodException - 如果找不到匹配的方法。
SecurityException - 如果存在安全管理器 s,並滿足下列任一條件:
調用 s.checkMemberAccess(this, Member.PUBLIC) 拒絕訪問構造方法
調用者的類加載器不同於也不是當前類的類加載器的一個祖先,並且對 s.checkPackageAccess() 的調用拒絕訪問該類的包
從以下版本開始:
JDK1.1
裡面要注意的就是parametrrTypes這個Class類型的參數列表,用來指明當前你要創建的類的某個構造方法的參數列表,且順序要是當前這個類的構造方法中聲明的參數列表相同。注意都是Class類型,指明一些類信息就可以了。可以按照下面的規則來傳入相應的類信息參數列表:
例如:Integer類,它有兩個構造函數,
public Integer(int value)
構造一個新分配的 Integer 對象,它表示指定的 int 值。
 

參數:
value - Integer 對象表示的值。
這個構造函數指明的Class參數列表是一個Interger Class類型的類對象
這麼寫:Interger.TYPE:返回的是其Class類信息
另一個構造函數:

 

public Integer(String s) throws NumberFormatException
構造一個新分配的 Integer 對象,它表示 String 參數所指示的 int 值。使用與 parseInt 方法(對基數為 10 的值)相同的方式將該字符串轉換成 int 值。
 

參數:
s - 要轉換為 Integer 的 String。
拋出:
NumberFormatException - 如果 String 不包含可解析的整數。
另請參見:
parseInt(java.lang.String, int)
 

其參數類型是這樣創建:String.class

class參數列表創建總結:如果是基本類型請使用它們的Type字段,如果是非基本類型使用class字段來返回其CLass類信息。

 

現在就是如何創建對象了,對於帶參數的對象,你要傳入參數,可以使用newInstance(參數列表)來創建對象,這個Constructor對象的方法。


public T newInstance(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。個別參數會自動解包,以匹配基本形參,必要時,基本參數和引用參數都要進行方法調用轉換。
如果底層構造方法所需形參數為 0,則所提供的 initargs 數組的長度可能為 0 或 null。

如果構造方法的聲明類是非靜態上下文的內部類,則構造方法的第一個參數需要是封閉實例;請參閱Java 語言規范 第 15.9.3 節。

如果所需的訪問檢查和參數檢查獲得成功並且實例化繼續進行,這時構造方法的聲明類尚未初始化,則初始化這個類。

如果構造方法正常完成,則返回新創建且已初始化的實例。

 

參數:
initargs - 將作為變量傳遞給構造方法調用的對象數組;基本類型的值被包裝在適當類型的包裝器對象(如 Float 中的 float)中。
返回:
通過調用此對象表示的構造方法來創建的新對象
拋出:
IllegalAccessException - 如果此 Constructor 對象實施 Java 語言訪問控制並且底層構造方法是不可訪問的。
IllegalArgumentException - 如果實參和形參的數量不同;如果基本參數的解包轉換失敗;如果在可能的解包後,無法通過方法調用轉換將參數值轉換為相應的形參類型;如果此構造方法屬於枚舉類型。
InstantiationException - 如果聲明底層構造方法的類表示抽象類。
InvocationTargetException - 如果底層構造方法拋出異常。
ExceptionInInitializerError - 如果此方法引發的初始化失敗。
好了,下面就是一個實例,包括構造函數中包括自定義的類,基本數據類型,和非基本數據類型。

 

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jijing.classDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author Administrator
* 用來演示通過反射來創建對象,帶參數的構造方法
*/
public class ClassMain {

public ClassMain(){
}
public static void main(String args[]){
//創建不帶參數的對象
//ReflectClass rc1=(ReflectClass) ClassMain.getInstance("com.jijing.classDemo.ReflectClass");
//System.out.println("ReflectClass111="+rc1);
System.out.println("******************************");
ReflectClass rc2=(ReflectClass) ClassMain.getInstance("com.jijing.classDemo.ReflectClass",
new Class[]{Integer.TYPE,String.class,MyClass.class},
new Object[]{20,"我是ReflectClass",new MyClass("我是MyClass")});
System.out.println("ReflectClass222="+rc2);
}


/**
*
* @param className 類路勁的名字
* @return 返回根據className指明的類信息
*/
public static Class getclass(String className){
Class c=null;
try {
c=Class.forName(className);
} catch (ClassNotFoundException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
}
return c;
}

/**
*
* @param name 類路勁
* @param classParas Class類信息參數列表
* 如果是基本數據類型是可以使用其Tpye類型,如果用class字段是無效的
* 如果是非數據類型可以使用的class字段來創建其Class類信息對象,這些都要遵守。
* @param paras 實際參數列表數據
* @return 返回Object引用的對象,實際實際創建出來的對象,如果要使用可以強制轉換為自己想要的對象
*
* 帶參數的反射創建對象
*/
public static Object getInstance(String name,Class classParas[],Object paras[]){
Object o=null;
try {
Class c=getclass(name);
Constructor con=c.getConstructor(classParas);//獲取使用當前構造方法來創建對象的Constructor對象,用它來獲取構造函數的一些
try {
//信息
o=con.newInstance(paras);//傳入當前構造函數要的參數列表
} catch (InstantiationException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (NoSuchMethodException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
}

return o;//返回這個用Object引用的對象
}

/**
*
* @param name 類路勁
* @return 不帶參數的反射創建對象
*/
public static Object getInstance(String name){
Class c=getclass(name);
Object o=null;
try {
o=c.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
}
return o;
}

}
/**
*
* @author Administrator
* 自定義一個類型
*/
class MyClass{
private String name="";//名字顯示,用來表明創建成功
MyClass(String name){
this.name=name;
show();//顯示
}
public void show(){
System.out.println(name);
}
@Override
public String toString(){
return "MyClass="+name;
}
}

/**
*
* @author Administrator
* 通過反射創建對象
*/
class ReflectClass{
private String name="ReflectClass";
public ReflectClass(int age,String name,MyClass my){
this.name=name;
show(age,name,my);
}
// ReflectClass(){//構造函數重載,使用不同的參數列表創建對象
// //沒有帶參數的構造方法
// }
/**
*
* @param age
* @param name
* @param my
*/
public final void show(int age,String name,MyClass my){
System.out.println("age="+age+" name="+name+" my="+my);
}
@Override
public String toString(){
return "ReflectClass="+name;
}
}

 

上面有三個方法自己可以拿去用,已經封裝好了,就是這三個方法。  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved