JAVA類加載和反射介紹


簡單的來說,反射機制指的是程序在運行時能夠獲取自身的信息。在java中,只要給定類的名字,那么就可以通過反射機制來獲得類的所有信息.
反射機制的優點就是可以實現動態創建對象和編譯,體現出很大的靈活性,特別是在J2EE的開發中它的靈活性就表現的十分明顯。

當程序主動使用某個類時,若該類還沒加載到內存中,系統會通過加載,鏈接,初始化3個操作對類進行初始化。
類字面常量”,class”創建Class對象的引用時,不會自動地初始化該Class對象,准備工作包含3個步驟:
1.加載:由類加載器執行,該步驟查找字節碼,並從這些字節碼中創建一個Class對象
2.鏈接:在鏈接階段將驗證類中的字節碼,為靜態域分配存儲空間,並且如果必需的話,將解析這個類創建的對其他類的所有引用。
3.初始化:如果該類有超類,則對其初始化,執行靜態初始化器和靜態初始化塊

類的初始化時機
1.創建類的實例
2.訪問類或接口的靜態變量(static final常量除外,static final變量可以)
3.調用類的靜態方法
4.反射(Class.forName(packageName.className))
5.初始化類的子類(子類初始化問題:滿足主動調用,即訪問子類中的靜態變量、方法,否則僅父類初始化)
6.java虛擬機啟動時被標明為啟動類的類
注:加載順序:啟動類的static block最先加載
(父類靜態成員、靜態代碼塊—>子類靜態成員、靜態代碼塊—>父類實例成員、代碼塊——>父類構造函數—>子類實例成員、代碼塊—>子類構造函數)

我們需要明白在JAVA中任何class都要裝載在虛擬機上才能運行,而forClass就是裝載類用的,這是要和new不一樣,要分清楚哦。
A a = (A)Class.forName(“package.A”).newInstance();和 A a = new A;是等價的。
記住一個概念,靜態代碼是和class綁定的,class裝載成功就表示執行了你的靜態代碼,而且以后不會再走這套靜態代碼了
Class.forName(xxx.xx.xx)的作用是要求JVM查找並加載指定的類,也即是說JVM會執行該類的靜態代碼段。

JAVA中獲取Class對象有3種方式:
1.Class.forName()
2.Object.getClass()
3.類字面常量 xx.class

代碼例子:

package Reflect;
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo1=null;
        Class<?> demo2=null;
        Class<?> demo3=null;
        try{
            //一般盡量采用這種形式
            demo1=Class.forName("Reflect.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
        demo2=new Demo().getClass();
        demo3=Demo.class;
         
        System.out.println("類名稱   "+demo1.getName());//Reflect.Demo
        System.out.println("類名稱   "+demo2.getName());//Reflect.Demo
        System.out.println("類名稱   "+demo3.getName());//Reflect.Demo        
    }
}

 

從Class中獲取信息(可以查看Class的API文檔了解):

獲取類的構造器
首先介紹一下Constructor類,這個類用來封裝反射得到的構造器,Class有四個方法來獲得Constructor對象
public Constructor<?>[] getConstructors() 返回類中所有的public構造器集合,默認構造器的下標為0
public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回指定public構造器,參數為構造器參數類型集合
public Constructor<?>[] getDeclaredConstructors() 返回類中所有的構造器,包括私有
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回任意指定的構造器

獲取類的成員變量
成員變量用Field類進行封裝,主要的方法非常的類似:
public Field getDeclaredField(String name) 獲取任意指定名字的成員
public Field[] getDeclaredFields() 獲取所有的成員變量
public Field getField(String name) 獲取任意public成員變量
public Field[] getFields() 獲取所有的public成員變量

獲取類的方法
public Method[] getMethods() 獲取所有的共有方法的集合
public Method getMethod(String name,Class<?>... parameterTypes) 獲取指定公有方法 參數1:方法名 參數2:參數類型集合
public Method[] getDeclaredMethods() 獲取所有的方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 獲取任意指定方法

常用的就這些,知道這些,其他的都好辦……

 

獲取基本信息的例子:

import java.lang.reflect.*;
import java.lang.annotation.*;

//使用2個注釋修飾該類
@SuppressWarnings(value="unchecked")
@Deprecated
public class ClassTest
{
    //為該類定義一個私有的構造器
    private ClassTest(){
    }
    
    //定義一個有參數的構造器
    public ClassTest(String name){
        System.out.println("執行有參數的構造器");
    }
    
    //定義一個無參數的info方法
    public void info(){
        System.out.println("執行無參數的info方法");
    }
    
    //定義一個有參數的info方法
    public void info(String str){
        System.out.println("執行有參數的info方法"
            + ",其實str參數值:" + str);
    }
    
    //定義一個測試用的內部類
    class Inner{
    }
    
    public static void main(String[] args) throws Exception{
        //下面代碼可以獲取ClassTest對應的Class
        Class<ClassTest> clazz = ClassTest.class;
        
        //獲取該Class對象所對應類的全部構造器
        Constructor[] ctors = clazz.getDeclaredConstructors();
        System.out.println("ClassTest的全部構造器如下:");
        for (Constructor c : ctors)
        {
            System.out.println(c);
            //private ClassTest()
            //public ClassTest(java.lang.String)
        }
        
        
        //獲取該Class對象所對應類的全部public構造器
        Constructor[] publicCtors = clazz.getConstructors();
        System.out.println("ClassTest的全部public構造器如下:");
        for (Constructor c : publicCtors)
        {
            System.out.println(c);
            //public ClassTest(java.lang.String)
        }
        
        //獲取該Class對象所對應類的全部public方法
        Method[] mtds = clazz.getMethods();
        System.out.println("ClassTest的全部public方法如下:");
        for (Method md : mtds)
        {
            System.out.println(md);
            //public static void ClassTest.main(java.lang.String[]) throws java.lang.Exception
            //public void ClassTest.info()
            //public void ClassTest.info(java.lang.String)
            //public final void java.lang.Object.wait() throws java.lang.InterruptedException
            //public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
            //public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
            //public native int java.lang.Object.hashCode()
            //public final native java.lang.Class java.lang.Object.getClass()
            //public boolean java.lang.Object.equals(java.lang.Object)
            //public java.lang.String java.lang.Object.toString()
            //public final native void java.lang.Object.notify()
            //public final native void java.lang.Object.notifyAll()
        }
        
        //獲取該Class對象所對應類的指定方法
        System.out.println("ClassTest里帶一個字符串參數的info方法為:"
            + clazz.getMethod("info" , String.class));
        //public void ClassTest.info(java.lang.String)
        
        //獲取該Class對象所對應類的上的全部注釋
        Annotation[] anns = clazz.getAnnotations();
        System.out.println("ClassTest的全部Annotattion如下:");
        for (Annotation an : anns)
        {
            System.out.println(an);
        }
        
        System.out.println("該Class元素上的@SuppressWarnings注釋為:"
            + clazz.getAnnotation(SuppressWarnings.class));
        
        //獲取該Class對象所對應類的全部內部類
        Class<?>[] inners = clazz.getDeclaredClasses();
        System.out.println("ClassTest的全部內部類如下:");
        for (Class c : inners)
        {
            System.out.println(c);
            //class ClassTest$Inner
        }
        
        //使用Class.forName方法加載ClassTest的Inner內部類
        Class inClazz = Class.forName("ClassTest$Inner");
        
        //通過getDeclaringClass()訪問該類所在的外部類
        System.out.println("inClazz對應類的外部類為:" + inClazz.getDeclaringClass());
        //class ClassTest
        System.out.println("ClassTest的包為:" + clazz.getPackage());
        //null
        System.out.println("ClassTest的父類為:" + clazz.getSuperclass());
        //class java.lang.Object
    }
}

 

通過Class調用其他類中的構造函數 (也可以通過這種方式通過Class創建其他類的對象)

package Reflect;
 
import java.lang.reflect.Constructor;
 
class Person{
     
    public Person() {
         
    }
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //取得全部的構造函數
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[0].newInstance();
            per2=(Person)cons[1].newInstance("Rollen");
            per3=(Person)cons[2].newInstance(20);
            per4=(Person)cons[3].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);//[null  0]
        System.out.println(per2);//[Rollen  0]
        System.out.println(per3);//[null  20]
        System.out.println(per4);//[Rollen  20]
    }
}
綜合例子:
package Reflect;
 
interface China{
    public static final String name="Rollen";
    public static int age=20;
    public void sayChina();
    public void sayHello(String name, int age);
}
 
class Person implements China{
    public Person() {
    }
    public Person(String sex){
        this.sex=sex;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public void sayChina(){
        System.out.println("hello ,china");
    }
    @Override
    public void sayHello(String name, int age){
        System.out.println(name+"  "+age);
    }
    private String sex;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        
        //保存所有的接口
        Class<?> intes[]=demo.getInterfaces();
        for (int i = 0; i < intes.length; i++) {
            System.out.println("實現的接口   "+intes[i].getName());
            // Reflect.China
        }
        
        //獲得其他類中的全部構造函數
        Constructor<?>cons[]=demo.getConstructors();
        for (int i = 0; i < cons.length; i++) {
            System.out.println("構造方法:  "+cons[i]);
            //public Reflect.Person()
            /public Reflect.Person(java.lang.String)
        }
        
        for (int i = 0; i < cons.length; i++) {
            Class<?> p[]=cons[i].getParameterTypes();
            System.out.print("構造方法:  ");
            int mo=cons[i].getModifiers();
            System.out.print(Modifier.toString(mo)+" ");
            System.out.print(cons[i].getName());
            System.out.print("(");
            for(int j=0;j<p.length;++j){
                System.out.print(p[j].getName()+" arg"+i);
                if(j<p.length-1){
                    System.out.print(",");
                }
            }
            System.out.println("){}");
        }
        //構造方法:  public Reflect.Person(){}
        //構造方法:  public Reflect.Person(java.lang.String arg1){}
        
        //通過反射調用其他類中的方法
        try{
            //調用Person類中的sayChina方法
            Method method=demo.getMethod("sayChina");
            method.invoke(demo.newInstance());//hello ,china
            //調用Person的sayHello方法
            method=demo.getMethod("sayHello", String.class,int.class);
            method.invoke(demo.newInstance(),"Rollen",20);//Rollen  20
             
        }catch (Exception e) {
            e.printStackTrace();
        }
        
        
        System.out.println("===============本類屬性========================");
        // 取得本類的全部屬性
        Field[] field = demo.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 權限修飾符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";");
            //private java.lang.String sex;        
        }
        System.out.println("===============實現的接口或者父類的屬性========================");
        // 取得實現的接口或者父類的屬性
        Field[] filed1 = demo.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 權限修飾符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + filed1[j].getName() + ";");
        }
        //public static final java.lang.String name;
        //public static final int age;
        

        Object obj = null;
        try{
         obj=demo.newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        
        
        
        //通過反射操作屬性
        Field field = demo.getDeclaredField("sex");
        field.setAccessible(true);
        field.set(obj, "男");
        
        //通過反射取得並修改數組的信息:
        int[] temp={1,2,3,4,5};
        Class<?>demo=temp.getClass().getComponentType();
        System.out.println("數組類型: "+demo.getName());// int
        System.out.println("數組長度  "+Array.getLength(temp));//5
        System.out.println("數組的第一個元素: "+Array.get(temp, 0));//1
        Array.set(temp, 0, 100);
        System.out.println("修改之后數組第一個元素為: "+Array.get(temp, 0));//100
    }
}

 

將反射用於工廠模式(結合屬性文件的工廠模式):

首先創建一個fruit.properties的資源文件,內容為:
apple=Reflect.Apple
orange=Reflect.Orange

主類代碼:

package Reflect;
 
import java.io.*;
import java.util.*;
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
//操作屬性文件類
class init{
    public static Properties getPro() throws FileNotFoundException, IOException{
        Properties pro=new Properties();
        File f=new File("fruit.properties");
        if(f.exists()){
            pro.load(new FileInputStream(f));
        }else{
            pro.setProperty("apple", "Reflect.Apple");
            pro.setProperty("orange", "Reflect.Orange");
            pro.store(new FileOutputStream(f), "FRUIT CLASS");
        }
        return pro;
    }
}
 
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}

class hello{
    public static void main(String[] a) throws FileNotFoundException, IOException{
        Properties pro=init.getPro();
        fruit f=Factory.getInstance(pro.getProperty("apple"));
        if(f!=null){
            f.eat();//Apple
        }
    }
}

 

 

參考:
參考sina博文<<forName和類字面常量.class>>
參考<<瘋狂JAVA編程>>第18章
java反射詳解 (各個例子寫的還是挺不錯的)
http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM