Java學(xué)習(xí)之反射

一、Class

1、概述:

1、Class是Java程序中各個(gè)Java類的總稱;它是反射的基石,通過(guò)Class類來(lái)使用反射。

2、Class和class的區(qū)別

1)class:Java中的類用于描述一類事物的共性,該類事物有什么屬性,沒有什么屬性,至于這個(gè)屬性的值是什么,則由此類的實(shí)例對(duì)象確定,不同的實(shí)例對(duì)象有不同的屬性值。

2)Class:指的是Java程序中的各個(gè)Java類是屬于同一類事物,都是Java程序的類,這些類稱為Class。例如人對(duì)應(yīng)的是Person類,Java類對(duì)應(yīng)的就是Class。

3、屬性:類名,類的訪問(wèn)屬性,類所屬包名,字段名稱列表,方法名稱列表等。

2、對(duì)象的創(chuàng)建和使用:

1、創(chuàng)建實(shí)例對(duì)象:不可用new Class()的方式,因?yàn)镃lass沒有這樣的構(gòu)造方法。而是將字節(jié)碼對(duì)象賦值給Class變量。如Class c1 =Person.class。

如Person類,它的字節(jié)碼:首先要將Person的java文件編譯為class文件放于硬盤上,即為二進(jìn)制代碼,再將這些代碼加載到內(nèi)存中,接著用它創(chuàng)建一個(gè)個(gè)對(duì)象。就是把類的字節(jié)碼加載進(jìn)內(nèi)存中,再用此字節(jié)碼創(chuàng)建一個(gè)個(gè)對(duì)象。當(dāng)有如Person、Math、Date等等的類,那么這些字節(jié)碼就是分別的一個(gè)Class對(duì)象。

Class c2 =Date.class;

2、獲得類的字節(jié)碼對(duì)象:
Class.forName(”java.lang.String”) 即獲得String.class。

得到這個(gè)字節(jié)碼對(duì)象有兩種情況:
1)此類已經(jīng)加載進(jìn)內(nèi)存:若要得到此類字節(jié)碼,不需要再加載。
2)此類還未加載進(jìn)內(nèi)存:類加載器加載此類后,將字節(jié)碼緩存起來(lái),forName()方法返回加載進(jìn)來(lái)的字節(jié)碼。

3、得到各字節(jié)碼對(duì)應(yīng)的實(shí)例對(duì)象(Class類型)的方式:
1)類名.class:如System.class,String.class等等
2)對(duì)象.class:如new Date().getClass()或者d.getClass()。(Date d = new Date())
3)Class.forName(“類名”):如Class.forName(”java.lang.String”)

當(dāng)獲取類名的時(shí)候,是不知道此類的名稱的,forName(字符串參數(shù))方法中傳入字符串型的變量作為對(duì)外訪問(wèn)的入口,即傳入什么類名就獲得什么類名,從而得知相應(yīng)的類名。

注:
forName() 是靜態(tài)方法,是反射中使用的一種方式獲取字節(jié)碼的實(shí)例對(duì)象。

每個(gè)類的字節(jié)碼對(duì)象只有唯一的一個(gè),如任何字符串對(duì)象,對(duì)應(yīng)唯一的String.clas字節(jié)碼。

4、九個(gè)預(yù)定義的Class:
1)包括八種基本類型(byte、short、int、long、float、double、char、boolean)的字節(jié)碼對(duì)象和一種返回值為void類型的void.class。

2)Integer.TYPE是Integer類的一個(gè)常量,它代表此包裝類型包裝的基本類型的字節(jié)碼,所以和int.class是相等的。

基本數(shù)據(jù)類型的字節(jié)碼都可以用與之對(duì)應(yīng)的包裝類中的TYPE常量表示
數(shù)組類型的Class實(shí)例對(duì)象,可以用Class.isArray()方法判斷是否為數(shù)組類型的。

5、總結(jié):只要是在源程序中出現(xiàn)的類型都有各自的Class實(shí)例對(duì)象,如int[].class、void.class等。

3、方法:

1、static Class forName(String className)
---> 返回與給定字符串名的類或接口的相關(guān)聯(lián)的Class對(duì)象。

2、Class getClass()
---> 返回的是Object運(yùn)行時(shí)的類,即返回Class對(duì)象即字節(jié)碼對(duì)象

3、Constructor getConstructor()
---> 返回Constructor對(duì)象,它反映此Class對(duì)象所表示的類的指定公共構(gòu)造方法。

4、Field getField(String name)
---> 返回一個(gè)Field對(duì)象,它表示此Class對(duì)象所代表的類或接口的指定公共成員字段。

5、Field[] getFields()
---> 返回包含某些Field對(duì)象的數(shù)組,表示所代表類中的成員字段。

6、Method getMethod(String name,Class… parameterTypes)
---> 返回一個(gè)Method對(duì)象,它表示的是此Class對(duì)象所代表的類的指定公共成員方法。

7、Method[] getMehtods()
---> 返回一個(gè)包含某些Method對(duì)象的數(shù)組,是所代表的的類中的公共成員方法。

8、String getName()
---> 以String形式返回此Class對(duì)象所表示的實(shí)體名稱。

9、String getSuperclass()
---> 返回此Class所表示的類的超類的名稱

10、boolean isArray()
---> 判定此Class對(duì)象是否表示一個(gè)數(shù)組

11、boolean isPrimitive()
---> 判斷指定的Class對(duì)象是否是一個(gè)基本類型。

12、T newInstance()
---> 創(chuàng)建此Class對(duì)象所表示的類的一個(gè)新實(shí)例。

示例:

public static void fuction()throws Exception{  
        String str1 = "abc";  
        Class cls1 = str1.getClass();  
        Class cls2 = String.class;  
        Class cls3 = Class.forName("java.lang.String");  
        System.out.println(cls1 == cls2);//true  
        System.out.println(cls1 == cls3);//true  
          
        //判斷是否為基本類型:isPrimitive()  
        System.out.println(cls1.isPrimitive());//false  
        System.out.println(int.class == Integer.class);//false  
        //Integer.TYPE代表包裝類對(duì)應(yīng)的基本數(shù)據(jù)類型的字節(jié)碼  
        System.out.println(int.class == Integer.TYPE);//true  
        System.out.println(int[].class.isPrimitive());//false  
        //判斷是否為數(shù)組類型的  
        System.out.println(int[].class.isArray());//true  
}

二、反射

1、概述:把Java類中的各種成分映射成相應(yīng)的Java類。
如Class中的每一個(gè)方法返回的都是一種類(型),即Method對(duì)所有方法抽取成了這個(gè)類Method,它的每一個(gè)對(duì)象(如變量methodObj1)代表了一個(gè)方法。

2、一個(gè)類中的組成成分:
成員變量、方法、構(gòu)造函數(shù)、包等信息,也用一個(gè)個(gè)java類來(lái)表示(如汽車是一個(gè)類,其中的發(fā)動(dòng)機(jī),變速箱等也是對(duì)應(yīng)的一個(gè)個(gè)類),表示Java類的Class類顯然要提供一系列的方法來(lái)獲取其中的變量、方法、構(gòu)造函數(shù)、修飾符、包等信息,這些信息就是用相應(yīng)的類的實(shí)例對(duì)象來(lái)表示,他們是Field、Method、Contructor、Package等。

3、一個(gè)類中的每個(gè)成員都可用相應(yīng)的反射API類的一個(gè)實(shí)例對(duì)象來(lái)表示,通過(guò)調(diào)用Class類的方法可得到這些實(shí)例對(duì)象。

反射中的各種類:

1、Constructor類

1、概述:Constructor代表某個(gè)類的構(gòu)造方法

2、獲取構(gòu)造方法:
1)如何得到摸個(gè)類的所有構(gòu)造方法:如得到String類的所有構(gòu)造方法

Constructor[] cons = Class.forName(“java.lang.String”).getConstructors();

2)獲取某一個(gè)構(gòu)造方法:

Constructor con =String.class.getConstructor(StringBuffer.class);  //①

3、創(chuàng)建實(shí)例對(duì)象:
1)通常方式:

String str = new String(new StringBuffer (”abc”));

2)反射方式:

String str = (String)con.newInstance(new StringBuffer(“abc”));  //②

調(diào)用獲得的方法時(shí)要用到上面相同類型的實(shí)例對(duì)象,即兩個(gè)StringBuffer()要對(duì)應(yīng)相等。
NewInstance() :構(gòu)造出一個(gè)實(shí)例對(duì)象,每調(diào)用一次就構(gòu)造一個(gè)對(duì)象。

注意:上面的兩個(gè)地方①②都要用到StringBuffer,這必須是一致的。
第①個(gè)是指定要帶StringBuffer參數(shù)類型的構(gòu)造方法,即所需使用的是含StringBuffer類型的構(gòu)造方法。
第②個(gè)是用這個(gè)構(gòu)造方法創(chuàng)建對(duì)象,要傳入的參數(shù)類型是StringBuffer。

4、Class.newInstance():創(chuàng)建一個(gè)對(duì)象,不帶參數(shù)的構(gòu)造方法。

演示:

//new String(new StringBuffer("abc"));  
Constructor constructor1 =   
String.class.getConstructor(StringBuffer.class);  
String str2 =  
 (String)constructor1.newInstance(new StringBuffer("abc"));  
System.out.println(str2);  
          
//Class.newInstrance創(chuàng)建不帶參數(shù)的構(gòu)造方法  
String str3 =   
(String)Class.forName("java.lang.String").newInstance();  
System.out.println("str3:"+str3);  

2、Field類

1、概述:Field類代表成員變量(字段)的反射。

示例:

public class ReflectPoint {  
    private int x;  
    public int y;  
  
    public String toString(){  
        return str1+";" + str2 + ";" + str3;  
    }  
}  
public class FieldTest(){  
ReflectPoint pt1 = new ReflectPoint(3,5);  
    //fieldX和fieldY并不是對(duì)象身上的變量,而是類上的  
    //要用它去取某個(gè)對(duì)象上的對(duì)應(yīng)的值,傳入什么對(duì)象,就取相應(yīng)對(duì)象的值。  
    Field fieldY = pt1.getClass().getField("y");  
    System.out.println(fieldY.get(pt1));  
    //獲取私有的成員變量  
Field fieldX = pt1.getClass().getDeclaredField("x");  
    fieldX.setAccessible(true);  
    System.out.println(fieldX.get(pt1));  
}

2、獲取成員變量:
如上例子所示:
1)獲取公有的成員變量:

getField(String name)和get(變量)

2)獲取私有的成員變量:暴力反射

getDeclared(String name)
setAccessible(boolean b)  //將b設(shè)為true即可

get(變量)

//替換字符   
private static void changeStringValue(Object obj) throws Exception {  
    Field[] fields = obj.getClass().getFields();  
    for(Field field : fields){  
        //此處需要用==比較,因?yàn)槭峭环葑止?jié)碼對(duì)象  
        if(field.getType() == String.class){  
            String oldValue = (String)field.get(obj);  
            String newValue = oldValue.replace('b','a');  
            field.set(obj, newValue);  
        }  
    }  
}

3、Method類

1、概述:Method類代表某個(gè)類中的一個(gè)成員方法。
調(diào)用某個(gè)對(duì)象身上的方法,要先得到方法,再針對(duì)某個(gè)對(duì)象調(diào)用。

2、專家模式:誰(shuí)調(diào)用這個(gè)數(shù)據(jù),就是誰(shuí)在調(diào)用它的專家。

如人關(guān)門:
調(diào)用者:是門調(diào)用管的動(dòng)作,對(duì)象是門,因?yàn)殚T知道如何執(zhí)行關(guān)的動(dòng)作,通過(guò)門軸之類的細(xì)節(jié)實(shí)現(xiàn)。
指揮者:是人在指揮門做關(guān)的動(dòng)作,只是給門發(fā)出了關(guān)的信號(hào),讓門執(zhí)行。
總結(jié):
變量使用方法,是方法本身知道如何實(shí)現(xiàn)執(zhí)行的過(guò)程,也就是“方法對(duì)象”調(diào)用方法,才執(zhí)行了方法的每個(gè)細(xì)節(jié)的。

3、獲取某個(gè)類中的某個(gè)方法:(如String str = ”abc”)
1)通常方式:str.charAt(1)
2)反射方式:

Method charAtMethod =
       Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
charAtMethod.invoke(str,1);

說(shuō)明:
如果傳遞給Method對(duì)象的invoke()方法的第一個(gè)參數(shù)為null,說(shuō)明Method對(duì)象對(duì)應(yīng)的是一個(gè)靜態(tài)方法

4、用反射方式執(zhí)行某個(gè)main方法:
首先要明確為何要用反射:
在寫源程序時(shí),并不知道使用者傳入的類名是什么,但是雖然傳入的類名不知道,而知道的是這個(gè)類中的方法有main這個(gè)方法,所以可以通過(guò)反射的方式,通過(guò)使用者傳入的類名(可定義字符串型變量作為傳入類名的入口,通過(guò)這個(gè)變量代表類名),內(nèi)部通過(guò)傳入的類名獲取其main方法,然后執(zhí)行相應(yīng)的內(nèi)容。

//Method類演示  
private static void methodTest(String [] args) throws Exception {  
    String str1 = "abc";  
    //一般方法:  
    System.out.println(str1.charAt(1));  
    //反射方法 :  
    Method methodCharAt =  
        Class.forName("java.lang.String").getMethod("charAt",int.class);  
    System.out.println(methodCharAt.invoke(str1,1));  
      
    //用反射方式執(zhí)行某個(gè)main方法  
    //一般方式:  
    Test.main(new String[]{"111","222","333"});  
    System.out.println("-------");  
      
    //反射方式:  
    String startingClassName = args[0];  
    Method methodMain =  
        Class.forName(startingClassName).getMethod("main",String[].class);  
        //方案一:強(qiáng)制轉(zhuǎn)換為超類Object,不用拆包  
        methodMain.invoke(null,(Object)new String[]{"111","222","333"});  
        //方案二:將數(shù)組打包,編譯器拆包后就是一個(gè)String[]類型的整體  
        methodMain.invoke(null,new Object[]{new String[]{"111","222","333"}});  
    }  
//定義一個(gè)測(cè)試類  
class Test{  
    public static void main(String [] args){  
        for(String arg : args){  
            System.out.println(arg);  
        }  
    }  
}

4、數(shù)組的反射

1、數(shù)組字節(jié)碼的名字:有[和數(shù)組對(duì)應(yīng)類型的縮寫,如int[]數(shù)組的名稱為:[I

2、基本數(shù)據(jù)類型的一維數(shù)組不能轉(zhuǎn)換為Object數(shù)組,如:

int[] a = new int[3];Object[] obj= a;這樣是不成立的。

3、如何得到某個(gè)數(shù)組中的某個(gè)元素的類型:
例:

int a = newint[3];
Object[] obj= new Object[]{”ABC”,1};

無(wú)法得到某個(gè)數(shù)組的具體類型,只能得到其中某個(gè)元素的類型,

Obj[0].getClass().getName();  //得到的是java.lang.String

若通過(guò)

b.getClass().getName();  //結(jié)果是:[Ljava.lang.Object;
public static void arrayTest()throws Exception {  
    int[] a1 = new int[]{1,2,3};  
    int[] a2 = new int[4];  
    int[][] a3 = new int[2][3];  
    Integer[] ai = new Integer[3];  
    String[] a4 = new String[]{"a","b","c"};  
      
    System.out.println(a1.getClass() == a2.getClass());  
    System.out.println((Object)a1.getClass() == (Object)a3.getClass());  
          
    System.out.println(a3[0].getClass() == a1.getClass());  
    System.out.println(a3[0].getClass().getSuperclass().getName());  
    System.out.println(a1.getClass().equals(a3.getClass()));  
    System.out.println(a1.getClass().equals(a4.getClass()));  
    System.out.println(a1.getClass().getName());  
    System.out.println("----:" + a1.getClass());  
    System.out.println(a1.getClass().getSuperclass().getName());  
    System.out.println(a2.getClass().getSuperclass().getName());  
          
    Object obj1 = a1;  
    Object obj2 = a2;  
    //int基本數(shù)據(jù)類型不是Object的  
    //Object[] obj3 = a1;  
    Object[] obj4 = a3;  
    Object[] obj5 = a4;  
          
    System.out.println(a1);  
    System.out.println(a4);  
      
    System.out.println(Arrays.asList(a1));  
    System.out.println(Arrays.asList(a4));  
    System.out.println("-------");  
    int[] a = new int[3];  
    Object[] obj = new Object[]{"abc",new Integer(1)};  
    System.out.println(a.getClass().getName());  
    System.out.println(obj.getClass().getName());  
    System.out.println(obj[0].getClass().getName());  
}

5、HashSet和與hashCode的分析

示例:

import java.util.ArrayList;  
import java.util.Collection;  
import java.util.HashSet;  
  
public class ReflectTest2 {  
    public static void main(String [] args){  
        Collection cons = new HashSet();  
        ReflectPoint pt1 = new ReflectPoint(3,3);  
        ReflectPoint pt2 = new ReflectPoint(5,5);  
        ReflectPoint pt3 = new ReflectPoint(3,3);  
  
        cons.add(pt1);  
        cons.add(pt2);  
        cons.add(pt3);  
        cons.add(pt1);  
        cons.remove(pt1);  
        System.out.println(cons.size());  
    }  
}  
  
public class ReflectPoint {  
    private int x;  
    public int y;  
    public String str1 = "ball";  
    public String str2 = "basketball";  
    public String str3 = "itcast";  
      
    public ReflectPoint(int x, int y) {  
        super();  
        this.x = x;  
        this.y = y;  
    }  
      
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + x;  
        result = prime * result + y;  
        //System.out.println("demo...");//測(cè)試  
        return result;  
    }  
  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        ReflectPoint other = (ReflectPoint) obj;  
        if (x != other.x)  
            return false;  
        if (y != other.y)  
            return false;  
        return true;  
    }  
  
    public String toString(){  
        return str1+";" + str2 + ";" + str3;  
    }  
}

覆寫hashCode()方法的意義:
只有存入的是具有hashCode算法的集合的,覆寫hashCode()方法才有價(jià)值。

1、哈希算法的由來(lái):
若在一個(gè)集合中查找是否含有某個(gè)對(duì)象,通常是一個(gè)個(gè)的去比較,找到后還要進(jìn)行equals的比較,對(duì)象特別多時(shí),效率很低,通過(guò)哈希算法,將集合分為若干個(gè)區(qū)域,每個(gè)對(duì)象算出一個(gè)哈希值,可將哈希值分組(一般模32為一組),每組對(duì)應(yīng)某個(gè)存儲(chǔ)區(qū)域,依一個(gè)對(duì)象的哈希碼即可確定此對(duì)象對(duì)應(yīng)區(qū)域,從而減少每個(gè)對(duì)象的比較,只需在指定區(qū)域查找即可,從而提高從集合中查找元素的效率。

示意圖

2、如果不存入是hashCode算法的集合中,那么則不用復(fù)寫此方法。

3、只有類的實(shí)例對(duì)象要被采用哈希算法進(jìn)行存入和檢索時(shí),這個(gè)類才需要按要求復(fù)寫hashCode()方法,即使程序可能暫時(shí)不會(huì)用到當(dāng)前類的hashCode()方法,但是為提供一個(gè)hashCode()方法也不會(huì)有什么不好,沒準(zhǔn)以后什么時(shí)候就會(huì)用到這個(gè)方法,所以通常要求hashCode()和equals()兩者一并被覆蓋。

4、提示:
1)若同類兩對(duì)象用equals()方法比較的結(jié)果相同時(shí),他們的哈希碼也必須是相等的,但反過(guò)來(lái)就不成立了,如”BB”和”Aa”兩字符串用equals()比較式不相等的,但是他們的哈希值是相等的。

2)當(dāng)一個(gè)對(duì)象被存儲(chǔ)進(jìn)HashSet集合中,就不能再修改參與計(jì)算哈希值的字段,否則對(duì)象被修改后的哈希值與最初被存入的HashSet集合中的哈希值就不同了。在這種情況下,即使contains()方法是用對(duì)象的當(dāng)前引用作為參數(shù)去HashSet集合中檢索對(duì)象,也將返回找不到對(duì)象的結(jié)果,這也導(dǎo)致無(wú)法從HashSet集合中單獨(dú)刪除當(dāng)前對(duì)象,從而造成內(nèi)存泄露。
簡(jiǎn)單說(shuō),之前存入的對(duì)象和修改后的對(duì)象,是具有不同的哈希值,被認(rèn)為是不同的兩個(gè)對(duì)象,這樣的對(duì)象不再使用,又不移除,而越來(lái)越多,就會(huì)導(dǎo)致內(nèi)存泄露。
補(bǔ)充:
內(nèi)存泄露:某些對(duì)象不再使用了,占用著內(nèi)存空間,并未被釋放,就會(huì)導(dǎo)致內(nèi)存泄露;也就是說(shuō)當(dāng)程序不斷增加對(duì)象,修改對(duì)象,刪除對(duì)象,日積月累,內(nèi)存就會(huì)用光了,就導(dǎo)致內(nèi)存溢出。

3)對(duì)象在調(diào)用方法時(shí),對(duì)象會(huì)先進(jìn)行一次自身hashCode()方法的調(diào)用,再進(jìn)行操作方法。

三、反射的作用

--> 實(shí)現(xiàn)框架的功能

1、概述:

1、框架:通過(guò)反射調(diào)用位置Java類的一種方式。
如房地產(chǎn)商造房子用戶住,門窗和空調(diào)等等內(nèi)部都是由用戶自己安裝,房子就是框架,用戶需使用此框架,安好門窗等放入到房地產(chǎn)商提供的框架中。

框架和工具類的區(qū)別:工具類被用戶類調(diào)用,而框架是調(diào)用用戶提供的類。

2、框架機(jī)器要解決的核心問(wèn)題:
我們?cè)趯懣蚣埽ㄔ旆孔拥倪^(guò)程)的時(shí)候,調(diào)用的類(安裝的門窗等)還未出現(xiàn),那么,框架無(wú)法知道要被調(diào)用的類名,所以在程序中無(wú)法直接new其某個(gè)類的實(shí)例對(duì)象,而要用反射來(lái)做。

3、簡(jiǎn)單框架程序的步驟:
1)右擊項(xiàng)目名-->File-->命名,寫入鍵值對(duì):className=java.util.ArrayList ,等號(hào)右邊的可以自己定義集合的名稱,即用戶可以對(duì)此記事本修改成自己的類名。

2)代碼實(shí)現(xiàn),加載此文件:
①將文件讀取到讀取流中,一定要用完整的路徑,可以使用getRealPath()方法獲取路徑名,再加上自己定義的文件夾名。

②用Properties類的load()方法將流加載經(jīng)內(nèi)存,即提取文件中的信息。

③關(guān)閉流:關(guān)閉的是讀取流,因?yàn)榱髦械臄?shù)據(jù)已經(jīng)加載進(jìn)內(nèi)存。

3)通過(guò)getProperty()方法獲取類名屬性,將傳入的類名賦值給指定變量。

4)用反射的方式,創(chuàng)建對(duì)象newInstance()

5)進(jìn)行相關(guān)的具體操作。

2、類加載器:

1、簡(jiǎn)述:類加載器是將.class的文件加載經(jīng)內(nèi)存,也可將普通文件中的信息加載進(jìn)內(nèi)存。

2、文件的加載問(wèn)題:
1)eclipse會(huì)將源程序中的所有.java文件加載成.class文件,以確保編譯,然后放到classPath指定的目錄中去。并且會(huì)將非.java文件原封不動(dòng)的復(fù)制到.class指定的目錄中去。在真正編譯的時(shí)候,使用classPath目錄中的文件,即放置.class文件的目錄。

2)寫完程序是要講配置文件放到.class文件目錄中一同打包,這些都是類加載器加載的,資源文件(配置文件)也同樣加載了配置文件。

3)框架中的配置文件都要放到classPath指定的文件夾中,原因是它的內(nèi)部就是用類加載器加載的文件。

3、資源文件的加載:是使用類加載器。
1)由類加載器ClassLoader的一個(gè)對(duì)象加載經(jīng)內(nèi)存,即用getClassLoader()方法加載。若要加載普通文件,可用getResourseAsStream(String name)在classPath的文件中逐一查找要加載的文件。

2)在.class身上也提供了方法來(lái)加載資源文件,其實(shí)它內(nèi)部就是先調(diào)用了Loader方法,再加載的資源文件。
如:

Reflect.class.getResourseAsStream(String name)

4、配置文件的路徑問(wèn)題:

第一、用絕對(duì)路徑,通過(guò)getRealPath()方法運(yùn)算出來(lái)具體的目錄,而不是內(nèi)部編碼出來(lái)的。

一般先得到用戶自定義的總目錄,在加上自己內(nèi)部的路徑。可以通過(guò)getRealPath()方法獲取文件路徑。對(duì)配置文件修改是需要要儲(chǔ)存到配置文件中,那么就要得到它的絕對(duì)路徑才行,因此,配置文件要放到程序的內(nèi)部。

第二、name的路徑問(wèn)題:

①如果配置文件和classPath目錄沒關(guān)系,就必須寫上絕對(duì)路徑,

②如果配置文件和classPath目錄有關(guān)系,即在classPath目錄中或在其子目錄中(一般是資源文件夾resource),那么就得寫相對(duì)路徑,因?yàn)樗约毫私庾约簩儆谀膫€(gè)包,是相對(duì)于當(dāng)前包而言的。

示例:
配置文件內(nèi)容:

className=java.util.ArrayList

程序示例:

import java.io.FileInputStream;  
import java.io.InputStream;  
import java.util.ArrayList;  
import java.util.Collection;  
import java.util.HashSet;  
import java.util.Properties;  
  
public class ReflectTest2 {  
    public static void main(String [] args)throws Exception{  
        //讀取系統(tǒng)文件到讀取流中  
        //方式一:  
        //InputStream ips = new FileInputStream("config.propert");  
        /*getRealPath()--得到完整的路徑//如:金山詞霸/內(nèi)部 
         * 一定要用完整的路徑,但完整的路徑不是硬編碼出來(lái)的,而是運(yùn)算出來(lái)的。*/  
        //方式二:  
        //InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/text1/config.propert");  
        //方式三:  
            //第一種:配置文件(資源文件)在當(dāng)前包中  
        InputStream ips = ReflectTest2.class.getResourceAsStream("resourse/config.propert");  
            //第二種:配置文件(資源文件)不在當(dāng)前包中,和此包沒太大關(guān)系  
        //InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/test2/resourse/config.properties");  
          
        //加載文件中的鍵值對(duì)  
        Properties props = new Properties();  
        props.load(ips);  
        //關(guān)閉資源,即ips調(diào)用的那個(gè)系統(tǒng)資源  
        //注意:關(guān)閉的是ips操作的流,加載進(jìn)內(nèi)存后,就不再需要流資源了,需要關(guān)閉  
        ips.close();  
        //定義變量,將文件中的類名賦值給變量  
        String className = props.getProperty("className");  
        //通過(guò)變量,創(chuàng)建給定類的對(duì)象  
        Collection cons =   
                (Collection)Class.forName(className).newInstance();  
          
        //將元素添加到集合中  
        /*Collection cons = new HashSet();*/  
        ReflectPoint pt1 = new ReflectPoint(3,3);  
        ReflectPoint pt2 = new ReflectPoint(5,5);  
        ReflectPoint pt3 = new ReflectPoint(3,3);  
        cons.add(pt1);  
        cons.add(pt2);  
        cons.add(pt3);  
        cons.add(pt1);  
        //移除元素  
        cons.remove(pt1);  
        System.out.println(cons.size());  
    }  
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,635評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,733評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,935評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,172評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,595評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,908評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,712評(píng)論 18 399
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,618評(píng)論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,781評(píng)論 18 139
  • 我向一位搞心理學(xué)的老師討教, "我的孩子現(xiàn)在對(duì)學(xué)習(xí)不感興趣, 不愛閱讀". 這位老師給我回了句"這是因?yàn)槟闾信d趣...
    快來(lái)跳舞閱讀 302評(píng)論 0 3
  • 長(zhǎng)長(zhǎng)的夜,慢慢的憶 那一年,這一天 我是少年,你恰當(dāng)年華 夏至,月初上,小風(fēng),一雙人 心跳和微笑,眉眼和依戀 無(wú)論...
    四年夏閱讀 142評(píng)論 0 1