Java--反射

1.反射是什麼?(W)

反射是運行中的程序檢查自己和軟件運行環境的能力,它可以根據它發現的進行改變。反射可以在運行時根據指定的類名獲得類的信息。(無需使用new 就能實例化對象)

2.爲什麼要有反射?(W)

利用反射,可以實現更好的解耦合操作。(代替new來實現對象實例化操作)

3.Object類中的getClass()方法:

作用:通過對象取得此對象所在類的信息。
當我們使用getClass方法時,返回的類型爲java.lang.class,這是反射操作的源頭類,即所有的反射操作都需要通過此類開始。

4.java.lang.Class類對象實例化:

有如下三種方法:

I.調用Object類中的getClass()方法,此類操作必須有實例化對象。

import java.util.Date;
public class Demo {
    public static void main(String[] args) {
        Date date = new Date();
        Class<?> cls = date.getClass();
        System.out.println(cls.getName());
    }
}
java.util.Date

II.使用"類.class"取得,此時可以不用通過指定類的實例化對象取得

public class Demo {
    public static void main(String[] args) {
    	Class<?> cls =java.lang.Object.class;
        System.out.println(cls.getName());
    }
}
java.lang.Object

III.調用Class類提供的方法:

public static<?> forName(String className)throws ClassNotFoundException
public class Demo {
    public static void main(String[] args)throws Exception {
        Class<?> cls =Class.forName("java.lang.Object");
        System.out.println(cls.getName());
    }
}
java.lang.Object

III中調用了Class類中forname()方法。

5.反射怎麼用?(H)

掌握了Class類對象實例化的三種操作形式,就可以利用Class類來進行類的反射控制了。
Class類中有如下重要方法:

public T newInstance()
              throws InstantiationException,
                     IllegalAccessException

public static<?> forName(String name,
                               boolean initialize,
                               ClassLoader loader)
                        throws ClassNotFoundException

最重要的就是newInstance()方法,作用是反射實例化對象。(不使用new也可以生成對象),此方法返回的類型爲Object。
如果要使用此方法反射實例化對象,則類中一定要提供無參構造方法

利用反射實例化對象:

class Book {
    public Book() {
        System.out.println("*****這是無參構造");
    }
    @Override
    public String toString() {
        return "《*****》";
    }
}
public class Demo {
    public static void main(String[] args)throws Exception {
        Class<?> cls =Class.forName("Book");   //設置要操作對象的類名稱
        // 反射實例化後的對象返回的結果都是Object類型
        Object obj = cls.newInstance();            //相當於使用new調用無參構造
        Book book = (Book) obj;                    //向下轉型
        System.out.println(book);
    }
}
*****這是無參構造
《*****

6.使用反射調用構造:

利用Class類的newInstance()方法可以實現反射實例化對象的操作,但是類中必須提供有無參構造方法。如果類中只提供有參構造方法時,就必須通過java.lang.reflect.Constructor類來實現對象的反射實例化操作。
另外,java.lang.reflect是所有反射操作類的程序包,類中的每一個結構都有相應的類進行操作定義,如:構造方法會使用Constructor類。

java.lang.Class類中取得類中的構造方法:

public Constructor<?>[] getConstructors()
//取得全部構造方法               throws SecurityException
public Constructor<T> getConstructor(<?>... parameterTypes)
//取得指定參數類型的構造方法       throws NoSuchMethodException,
                                     SecurityException

利用以上兩個方法可以取得java.lang.reflect.Construcor,而Constructor類的最重要的方法如下:
調用指定參數的構造實例化類對象

public T newInstance(Object... initargs)
              throws InstantiationException,
                     IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException

明確調用類中的有參構造方法:

import java.lang.reflect.Constructor;
class Book {
    private String name;
    private double price;
    public Book(String name,double price){
        this.name=name;
        this.price=price;
    }
    @Override
    public String toString() {
        return "圖書名"+name +",價格"+price ;
    }
}
public class Demo {
    public static void main(String[] args)throws Exception {
        Class<?> cls =Class.forName("Book");   //設置要操作對象的類名稱
        //找到Book類中兩個參數的構造
        Constructor<?> cst =cls.getConstructor(String.class,double.class);
        Object obj =cst.newInstance("Java開發",66.6);         //實例化對象,傳遞內容
        System.out.println(obj);
    }
}

以上程序首先利用Class類取得此構造方法,返回Constructor對象,然後利用Constructor類的newInstance()方法傳遞指定數據,就完成了對象的反射實例化。

7.反射調用方法:

java.lang.Class類取得普通方法的操作:

public 方法[] getMethods()
//取得類中的全部方法  throws SecurityException
public 方法 getMethod(String name,
//取得類中指定方法名稱與參數類型的方法                        類<?>... parameterTypes)
   throws NoSuchMethodException,
                        SecurityException

java.lang.reflect.Method類的最重要方法:

public Object invoke(Object obj,
                     Object... args)
              throws IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException

8.反射調用成員:

java.lang.Class類中取得成員的操作:

//取得本類繼承父類的全部成員
public Field[] getFields()
                  throws SecurityException
                  
//取得本類繼承父類中指定名稱的成員
public Field getField(String name)
               throws NoSuchFieldException,
                      SecurityException
                      
//取得本類定義的全部成員
public Field[] getDeclaredFields()
                          throws SecurityException

//取得本類指定名稱的成員
public Field getDeclaredField(String name)
                       throws NoSuchFieldException,
                              SecurityException

java.lang.reflect.Field類常用方法:

//取得該成員的類型
public<?> getType()

//取得指定對象成員中的內容,相當於直接調用成員
public Object get(Object obj)
           throws IllegalArgumentException,
                  IllegalAccessException
//設置指定對象成員中的內容,相當於直接調用成員設置內容
public void set(Object obj,
                Object value)
         throws IllegalArgumentException,
                IllegalAccessException

利用反射直接操作私有成員:

import java.lang.reflect.Field;
class Book {
    private String name;
}
public class Demo {
    public static void main(String[] args)throws Exception {
        Class<?> cls =Class.forName("Book");   //取得反射對象
        Object obj =cls.newInstance();         //實例化對象
        Field titleField =cls.getDeclaredField("title");//取得類中的title屬性
        titleField.setAccessible(true);         //取消封裝
        titleField.set(obj,"第一行代碼------");
        System.out.println(titleField.get(obj));
    }
}

titleField.setAccessible(true);作用就是取消封裝,如果沒有特殊需要儘量不適用這種。所有屬性訪問還是要通過setter、getter方法操作。

無論是使用反射調用普通還是方法類中的成員,都必須存在實例化對象,因爲類中的屬性必須在類產生實例化對象(有堆內存空間)後纔可以正常使用。

發佈了33 篇原創文章 · 獲贊 1 · 訪問量 4706
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章