1. 程式人生 > >黑馬程式設計師——java的反射機制

黑馬程式設計師——java的反射機制

------- android培訓java培訓、期待與您交流! ----------

前言:通過觀看畢向東老師的java基礎視訊,查漏補缺,將一些自己掌握的還不牢固的知識寫出來,希望和大家交流分享。

一、反射技術是java在執行的時候獲取類的基本資訊。 反射技術大大提高了程式的擴充套件性。

二、對於任意一個類,都能夠知道這個類中的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;

      這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

三、反射技術在三大框架struts2,Hibernate,Spring中有廣泛應用。

四、反射就是把Java類中的各種成分對映成相應的java類。

五、反射的基石——Class類

    1)所有的類檔案都有共同屬性如欄位、方法、建構函式等。把這些類向上抽取,使共性內容封裝成一個類,這個類就叫Class(描述位元組碼檔案的物件)。

         Class類中就包含屬性有field(欄位)、method(方法)、construction(建構函式)。

         對於field中含有修飾符、型別、變數名等複雜的描述內容,因此可以將欄位封裝稱為一個物件。用來獲取類中field的內容,這個物件的描述叫Field。

         同理方法和建構函式也被封裝成物件Method、Constructor。要想對一個類進行內容的獲取,必須要先獲取該位元組碼檔案的物件。該物件是Class型別。

    2) Class類描述的資訊:類的名字,類的訪問屬性,類所屬於的包名,欄位名稱的列表,方法名稱的列表。

           每一個位元組碼就是class的例項物件。如:classcls=Data.class;

    3)位元組碼: 當源程式中用到類時,首先要從硬碟拿到這個類的二進位制程式碼(一個類編譯成class放在硬碟上以後,就是二進位制程式碼)

          要把這些二進位制程式碼載入到記憶體中裡面來, 再用這些位元組碼去複製出一個一個物件來。

    4)Class和class的區別

          a)class:Java類用於描述一類事物的共性。類事物有無相應屬性,以及這個屬性的值是什麼,由此類的例項物件確定,不同的例項物件有不同的屬性值。

          b)Class:指的是Java程式中的各個Java類是屬於同一類事物,都是Java程式的類,這些類稱為Class。

             例如人對應的是Person類,Java類對應的就是Class。Class是Java程式中各個Java類的總稱;它是反射的基石,通過Class類來使用反射。

     5)獲取Class物件的三種方式 。Class物件:載入XX.class檔案進記憶體時就被封裝成了物件,該物件就是位元組碼檔案物件。  

      //方式一:通過物件的getClass方法進行獲取。
      Class clazz=new Person().getClass();//每次都需要具體的類和該類的物件,以及呼叫getClass方法。
      //方式二:任何資料型別都具備著一個靜態的屬性class,這個屬性直接獲取到該型別的對應Class物件。
      Class clazz=Person.class;//比第一種較為簡單,不用建立物件,不用呼叫getClass方法,但是<span style="color:#FF0000;">還是要使用具體的類</span>,和該類中的一個靜態屬性class完成。
      //方式三:這種方式較為簡單,只要知道類的名稱即可。不需要使用該類,也不需要去呼叫具體的屬性和行為。就可以獲取到Class物件了。
      Class clazz=Class.forName("包名.Person");//這種方式僅知道類名就可以獲取到該類位元組碼物件的方式,更有利於擴充套件
      //包名.類名也叫全限定名
     6)九個預定義的Class:

           a)包括八種基本型別(byte、short、int、long、float、double、char、boolean)的位元組碼物件和一種返回值為void型別的void.class。

           b)Integer.TYPE是Integer類的一個常量,它代表此包裝型別包裝的基本型別的位元組碼,所以和int.class是相等的。

                基本資料型別的位元組碼都可以用與之對應的包裝類中的TYPE常量表示

      7)只要是在源程式中出現的型別都有各自的Class例項物件,如int[].class。陣列型別的Class例項物件,可以用Class.isArray()方法判斷是否為陣列型別的。

      8)Class類中的方法

返回值 方法名 方法作用
static Class forName(String className) 返回與給定字串名的類或介面的相關聯的Class物件。
  Class getClass() 返回的是Object執行時的類,即返回Class物件即位元組碼物件 
Constructor getConstructor() 返回Constructor物件,它反映此Class物件所表示的類的指定公共構造方法。
Field getField(String name) 返回一個Field物件,它表示此Class物件所代表的類或介面的指定公共成員欄位。
Field[] getFields() 返回包含某些Field物件的陣列,表示所代表類中的成員欄位。
  Method getMethod(String name,Class… parameterTypes) 返回一個Method物件,它表示的是此Class物件所代表的類的指定公共成員方法。
Method[] getMehtods() 返回一個包含某些Method物件的陣列,是所代表的的類中的公共成員方法。
String getName() 以String形式返回此Class物件所表示的實體名稱。
String getSuperclass() 返回此Class所表示的類的超類的名稱
boolean isArray() 判定此Class物件是否表示一個數組
boolean isPrimitive() 判斷指定的Class物件是否是一個基本型別。
T newInstance() 建立此Class物件所表示的類的一個新例項
    9)通過Class物件獲取類例項              Class類是沒有構造方法的, 因此只能通過方法獲取類例項物件。

             a) 之前我們用的已知類,建立物件的做法:Person p=new Person();

                 過程為:

                         1)JVM查詢並載入XX.class檔案進記憶體,並將該檔案封裝成Class物件。

                         2)再依據Class物件建立該類具體的例項。

                         3)呼叫建構函式對物件進行初始化。                 

               b)  現在用Class物件來獲取類例項物件的做法:        

            String className="包名.Person"; 

            Class clazz=Class.forName(className);

            Object obj=clazz.newInstance();                     

                  過程為:

                        1)JVM查詢並載入指定名字的位元組碼檔案進記憶體,並被封裝成Class物件。

                         2)通過Class物件的newInstance方法建立該Class對應的類例項。

                         3)呼叫newInstance()方法會去使用該類的空引數建構函式進行初始化。

        程式碼示例:

package reflect;
/**
 * 用反射建立物件
 * @author songwenju
 *
 */
//Person類
class Person{
	private String name;
	private int age;
	public Person() {
		super();
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}

	//覆寫toString()方法
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}
//示例
public class CreateObject {
	public static void main(String[] args) throws Exception {
		//這裡用的事第三種方式。設定全限定名
		String className = "reflect.Person";
		//得到Person類的位元組碼物件
		@SuppressWarnings("unchecked")
		Class<Person> claz = (Class<Person>) Class.forName(className);
		//通過newInstance()建立物件
		Person p = claz.newInstance();//呼叫的空的建構函式,如果類中沒有空的建構函式怎麼辦?就要用Constructer類。
		p.setAge(0);
		p.setName("songwenju");
		System.out.println(p);
		
	}
}
六、Constructor類:當通過指定的建構函式進行物件的初始化,就必須先獲取這個建構函式——Constructor。Constructor代表某個類的構造方法。

   1)獲取構造方法:

     //得到這個類的所有構造方法:如得到上面示例中Person類的所有構造方法     
     Constructor[] cons = Class.forName("reflect.Person").getConstructors();
     //獲取某一個構造方法:由括號裡的內容來確定。
     Constructor con=Person.class.getConstructor(String.class,int.class);
    2)建立例項物件:

         a)通常方式:Person p = new Person(“lisi”,30);

         b)反射方式:Person p= (Person)con.newInstance(“lisi”,30);

    3)說明:

          a)建立例項時newInstance()方法中的引數列表必須與獲取Constructor的方法getConstructor()方法中的引數列表一致。

               getConstructor(String.class,int.class)newInstance("lisi",30)

          b)newInstance():構造出一個例項物件,每呼叫一次就構造一個物件。

          c)利用Constructor類來建立類例項的好處是可以指定建構函式,而Class類只能利用無參建構函式建立類例項物件。

     程式碼示例:
package reflect;

import java.lang.reflect.Constructor;

/**
 * 通過Constructor物件來建立類例項方法  
 * @author songwenju
 *
 */
public class CreateObject_2 {
	public static void main(String[] args) throws Exception {
		String className = "reflect.Person";
		Class claz = Class.forName(className);
		//Class claz1 = Person.class;
		
		//獲取指定建構函式的類例項  
		Constructor cons = claz.getConstructor(String.class,int.class);
		Person p = (Person) cons.newInstance("songwenju",12);
		System.out.println(p);
	}
}
七、Field類,代表某個類中一個成員變數
   1)方法
     Field getField(String s);//只能獲取公有和父類中公有
     Field getDeclaredField(String s);//獲取該類中任意成員變數,包括<span style="color:#FF0000;">私有</span>
     setAccessible(ture);//如果是私有欄位,要先將該私有欄位進行取消許可權檢查的能力。也稱暴力訪問。
     set(Object obj, Object value);//將指定物件變數上此Field物件表示的欄位設定為指定的新值。
     Object get(Object obj);//返回指定物件上Field表示的欄位的值。
  2)程式碼示例
<pre name="code" class="java">package reflect;
import java.lang.reflect.Field;

public class FieldDemo {
	public static void main(String[] args) throws Exception {
		Class<Person> claz = Person.class;
		Person p = (Person) claz.newInstance();
		System.out.println(p);
		getPersonField(claz, p);
	}
	public static void getPersonField(Class<Person> claz,Person p) throws Exception{
		//獲取所有的成員變數 ,由於成員變數都是私有的。故這裡要用getDeclaredFields,否則什麼也得不到。
		Field[] fs = claz.getDeclaredFields();
		for (Field field : fs) {
			System.out.println(field);
		}
		
		//獲取指定的成員變數  
		//Field fage = claz.getField("age");報異常
		Field fname = claz.getDeclaredField("name");//私有變數會報錯
		
		System.out.println(fname);
		
		//顯示改變後的值  
		//fage.set(p, 12);
		//System.out.println(fage.get(p));
		
		//暴力訪問私有變數  
		fname.setAccessible(true);
		fname.set(p, "swj");
		System.out.println(fname.get(p));
	}
}

執行結果:

八、Method類:代表某個類中的一個成員方法。呼叫某個物件身上的方法,要先得到方法,再針對某個物件呼叫。

   1)專家模式:誰呼叫這個資料,就是誰在呼叫它的專家。

         變數使用方法,是方法本身知道如何實現執行的過程,也就是“方法物件”呼叫方法,才執行了方法的每個細節的。

   2)Method類的方法

        Method[] getMethods();//只獲取公共和父類中的方法。
        Method[] getDeclaredMethods();//獲取本類中包含私有。
        Method   getMethod("方法名",引數.class(如果是空參可以寫null));
        Object invoke(Object obj ,引數);//呼叫方法,如果方法是靜態,invoke方法中的物件引數可以為null。

        例如:獲取某個類中的某個方法:(String str =”abc”)

        a)通常方式:str.charAt(1)

        b)反射方式:             

         Method charAtMethod =Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
         charAtMethod.invoke(str,1); 
        //說明:如果傳遞給Method物件的invoke()方法的第一個引數為null,說明Method物件對應的是一個靜態方法

程式碼示例:

package reflect;

import java.lang.reflect.Method;

/**
 * 方法的使用
 * @author songwenju
 *
 */
public class MethodDemo {
	public static void main(String[] args) throws Exception {
		Class<Person> claz = Person.class;
		getMethod(claz);
	}
	public static void getMethod(Class<?> claz) throws Exception{
		Person p = (Person) claz.newInstance();
		//獲取所有方法
		Method [] methods = claz.getMethods();//獲取本類和父類公共的方法。
		methods = claz.getDeclaredMethods();//只獲取本類中的方法,包括私有
		for (Method method : methods) {
			System.out.println(method);
		}
		System.out.println("--------------------");
		Method method = claz.getMethod("toString", null);
		Object object = method.invoke(p, null);
		System.out.println(object);
	}
}
執行結果:


3)用反射載入配置檔案。根據配置檔案的方法動態執行類。程式碼如下:
package reflect;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

/**
 * 反射的練習,動態讀取配置檔案資訊
 * @author songwenju
 *
 */

//USB介面
interface USB{
    void open();
    void close();
}

//膝上型電腦
class NoteBook{
    public void run(){
        System.out.println("NoteBook is run");
    }
    
    public void useUSB(USB usb){
        if (usb != null) {
            usb.open();
            usb.close();
        }
    }
}

//滑鼠
class MouseUSB implements USB{
    @Override
    public void open() {
        System.out.println("Mouse is use");
    }

    @Override
    public void close() {
        System.out.println("Mouse is close");
    }
}

//鍵盤
class KeyUSB implements USB{
    @Override
    public void open() {
        System.out.println("key is use");
    }
    
    @Override
    public void close() {
        System.out.println("key is close");
    }
}
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        /*
         * 膝上型電腦使用usb裝置
         */
        NoteBook computer = new NoteBook();
        computer.run();
        
        //關聯配置檔案
        File file = new File("usb.properties");
        FileInputStream fis = new FileInputStream(file);
        Properties properties = new Properties();
        properties.load(fis);
        //System.out.println(properties);
        for (int i = 1; i <= properties.size(); i++) {
            //獲取配置檔案中類名  
            String className = properties.getProperty("usb"+i);
            //獲取類的Class物件  
            Class<?> clazz = Class.forName(className);
            //得到類例項  
            USB usb = (USB) clazz.newInstance();
            //開始使用  
            computer.useUSB(usb);
        }
        fis.close();//關流  
    }
}

配置檔案:usb.properties

usb1=reflect.MouseUSB

usb2=reflect.KeyUSB

執行結果:

九、陣列的反射

   1)具有相同維數和元素型別的陣列屬於同一個型別,即具有相同的Class例項物件。

        陣列位元組碼的名字:有[和陣列對應型別的縮寫,如int[]陣列的名稱為:[I

   2)Object[]與String[]沒有父子關係,Object與String有父子關係,

        所以new Object[]{“aaa”,”bb”}不能強制轉換成new String[]{“aaa”,”bb”}; Object x =“abc”能強制轉換成String x =“abc”。

   3)如何得到某個陣列中的某個元素的型別,int a = new int[3];Object[] obj=new Object[]{”ABC”,1};

        無法得到某個陣列的具體型別,只能得到其中某個元素的型別, Obj[0].getClass().getName()得到的是java.lang.String。

  4)Array工具類用於完成對陣列的反射操作。

        Array.getLength(Object obj);//獲取陣列的長度

        Array.get(Object obj,int x);//獲取陣列中的元素

  5)基本型別的一維陣列可以被當作Object型別使用,不能當作Object[]型別使用;

       非基本型別的一維陣列,既可以當做Object型別使用,又可以當做Object[]型別使用。

     程式碼示例:

package reflect;

import java.lang.reflect.Array;
import java.util.Arrays;

public class ArrayReflect {
	public static void main(String[] args) {
		int[] a1 = new int[]{1,2,3};
		int[] a2 = new int [4];
		int[][] a3 = new int[2][4];
		String [] a4 = new String[]{"a","b","c"};
		//true具有相同維數和元素型別的陣列屬於同一個型別,即具有相同的Class例項物件。
		System.out.println(a1.getClass().equals(a2.getClass()));
		//false,不具有相同的維數
		System.out.println(a1.getClass().equals(a3.getClass()));
		//false,不具有相同的元素型別
		System.out.println(a1.getClass().equals(a4.getClass()));
		
		System.out.println(a1.getClass().getName());//[I
		System.out.println(a4.getClass().getName());//[Ljava.lang.String;
		System.out.println(a1.getClass().getSuperclass());//class java.lang.Object
		System.out.println(a4.getClass().getSuperclass());//class java.lang.Object
		
		Object obj1 = a1;
		Object obj2 = a3;
		Object obj3 = a4;
		
		
		//Object[] obj11 = a1;這樣是不行的,因為a1中的元素是int型別,基本資料型別不是Object  
		Object[] obj13 = a3;
		Object[] obj14 = a4;//這樣可以,因為String陣列中的元素屬於Object  
		
		/* Arrays.asList()方法處理int[]和String[]時的差異。 
         * 列印Arrays.asList(a1);還是跟直接列印a1是一樣的 
         * 列印Arrays.asList(a4);就會把a3的元素打印出來。
         *  
         * 這是因為此方法在JDK1.4版本中,接收的Object型別的陣列, 
         * 而a3可以作為Object陣列傳入。但是a1不可以作為Object陣列傳入,所以只能按照JDK1.5版本來處理。 
         * 在JDK1.5版本中,傳入的是一個可變引數,所以a1就被當作是一個object,也就是一個引數, 
         * 而不是陣列傳入,所以列印的結果還是跟直接列印a1一樣。 
         */  
		System.out.println(a1);//[[email protected]
		System.out.println(a4);//[Ljava.lang.String;@3929df79
		
		System.out.println(Arrays.asList(a1));//[[[email protected]]
		System.out.println(Arrays.asList(a4));//[a, b, c]
		printObject(a1);
		printObject(a4);
		printObject("abc");
		
	}
	//列印任意數值  
    private static void printObject(Object obj) {  
        Class<? extends Object> clazz=obj.getClass();  
        //如果傳入的是陣列,則遍歷  
        if(clazz.isArray()){  
            int len =Array.getLength(obj);//Array工具類獲取陣列長度方法  
            for(int i=0;i<len;i++){  
                System.out.println(Array.get(obj, i));//Array工具獲取陣列元素  
            }  
            System.out.println();
        }  
        else  
            System.out.println("--->"+obj);  
    }  
}
執行結果:

十、HashCode

        只有存入的是具有hashCode演算法的集合的,覆寫hashCode()方法才有價值。

        1)雜湊演算法的由來:

         若在一個集合中查詢是否含有某個物件,通常是一個個的去比較,找到後還要進行equals的比較,物件特別多時,效率很低。

         而使用HashCode演算法,把這個集合分成若干個區域,每個存進來的物件,可以算出一個hashCode值,根據算出來的值,就放到相應的區域中去。

         當要查詢某一個物件,只要算出這個物件的hashCode值,看屬於第幾個區域,然後到相應的區域中去尋找,看是否有與此物件相等的物件。這樣查詢的效能就提高了。

         示意圖:

            

          2)要想HashCode方法有價值的話,前提是物件存入具有hash演算法這種型別的集合。如果不存入是hashCode演算法的集合中,則不用複寫此方法。

          3)如果沒有複寫hashCode方法,物件的hashCode值是按照記憶體地址進行計算的。這樣即使兩個物件的內容是想等的,但是存入集合中的記憶體

             地址值不同,導致hashCode值也不同,被存入的區域也不同。所以兩個內容相等的物件,就可以存入集合中。

             所以就有這樣的說法:如果兩個物件equals相等的話,你應該讓他們的hashCode也相等。如果物件存入的不是根據hash演算法的集合中,就不需要複寫hashCode方法。

         4)當一個物件儲存進HashSet集合中以後,就不能修改這個物件中的那些參與計算雜湊值的欄位了,否則物件修改後的雜湊值與最初儲存進HashSet集合中的雜湊值就不

             同了。在這種情況下,呼叫contains方法或者remove方法來尋找或者刪除這個物件的引用,就會找不到這個物件。從而導致無法從HashSet集合中單獨刪除當前物件,

             從而造成記憶體洩露。(程式中某一些物件不再被使用,以為被刪掉了,但是沒有,還一直在佔用記憶體中,當這樣的物件慢慢增加時,就會造成記憶體洩露。)

        記憶體洩露程式碼示例:
package reflect;

import java.util.Collection;
import java.util.HashSet;

class HashCodeTest{
	private int x;
	private int y;
	public HashCodeTest(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public HashCodeTest() {
		super();
	}
	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}
	public void setX(int x) {
		this.x = x;
	}
	public void setY(int y) {
		this.y = y;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof HashCodeTest)) {
			return false;
		}
		HashCodeTest other = (HashCodeTest) obj;
		if (x != other.x) {
			return false;
		}
		if (y != other.y) {
			return false;
		}
		return true;
	}
	@Override
	public String toString() {
		return "HashCodeTest [x=" + x + ", y=" + y + "]";
	}
	
}

public class HashCodeDemo {
	public static void main(String[] args) {
		Collection<Object> collection = new HashSet<Object>();
		HashCodeTest  hct1 = new HashCodeTest(1, 2);
		HashCodeTest  hct2 = new HashCodeTest(3, 4);
		HashCodeTest  hct3 = new HashCodeTest(5, 6);
		
		collection.add(hct1);
		collection.add(hct2);
		collection.add(hct3);
		hct1.setX(5);
		collection.remove(hct1);
		
		System.out.println(collection.size());
		
	}
}

執行結果:

在remove前後都是3,說明出現記憶體洩露。

十一、反射的應用:框架

        1)框架:通過反射呼叫Java類的一種方式。

              如房地產商造房子使用者住,門窗和空調等等內部都是由使用者自己安裝,房子就是框架,使用者需使用此框架,安好門窗等放入

              到房地產商提供的框架中。

        2)框架和工具類的區別:工具類被使用者類呼叫,而框架是呼叫使用者提供的類。

        3)框架機器要解決的核心問題:

              我們在寫框架(造房子的過程)的時候,呼叫的類(安裝的門窗等)還未出現,那麼框架無法知道要被呼叫的類名,

              所以在程式中無法直接new其某個類的例項物件,而要用反射來做。

        4)簡單框架程式的步驟:

                a)右擊專案File命名一個配置檔案如:config.properties,然後寫入配置資訊。如鍵值對:className=java.util.ArrayList,

                     等號右邊的配置鍵,右邊是值。

                b)程式碼實現,載入此檔案:

                      ①將檔案讀取到讀取流中,要寫出配置檔案的絕對路徑。

                       如:InputStream is=new FileInputStream(“配置檔案”);

                      ②用Properties類的load()方法將流中的資料存入集合。

                      ③關閉流:關閉的是讀取流,因為流中的資料已經載入進記憶體。

                c)通過getProperty()方法獲取className,即配置的值,也就是某個類名。

                d)用反射的方式,建立物件newInstance()。

                e)執行程式主體功能

               改例子的程式碼上面已經提供。

十二、類載入器

     1)類載入器是將.class的檔案載入進記憶體,也可將普通檔案中的資訊載入進記憶體。

     2)檔案的載入問題:

            a)eclipse會將源程式中的所有.java檔案編譯成.class檔案,然後放到classPath指定的目錄中去。並且會將非.java檔案原封

                 不動的複製到.class指定的目錄中去。在執行的時候,執行的是.class檔案。

            b)將配置檔案放到.class檔案目錄中一同打包,類載入器就會一同載入。

      3)資原始檔的載入:是使用類載入器。

              a)由類載入器ClassLoader來載入進記憶體,即用getClassLoader()方法獲取類載入器,然後用類載入器的

                    getResourceAsStream(String name)方法,將配置檔案(資原始檔)載入進記憶體。利用類載入器來載入配置檔案,

                    需把配置檔案放置的包名一起寫上。這種方式只有讀取功能。

               b)Class類也提供getResourceAsStream方法來載入資原始檔,其實它內部就是呼叫了ClassLoader的方法。

                    這時配置檔案是相對類檔案的當前目錄的,也就是說用這種方法,配置檔案前面可以省略包名。

                    如:類名.class.getResourceAsStream(“資原始檔名”)

      4)配置檔案的路徑問題:

           a)用絕對路徑,通過getRealPath()方法運算出來具體的目錄,而不是內部編碼出來的。

                一般先得到使用者自定義的總目錄,在加上自己內部的路徑。可以通過getRealPath()方法獲取檔案路徑。

                對配置檔案修改是需要要儲存到配置檔案中,那麼就要得到它的絕對路徑才行,因此,配置檔案要放到程式的內部。

           b)name的路徑問題:

                ①如果配置檔案和classPath目錄沒關係,就必須寫上絕對路徑,

                ②如果配置檔案和classPath目錄有關係,即在classPath目錄中或在其子目錄中(一般是資原始檔夾resource),

                   那麼就得寫相對路徑,因為它自己瞭解自己屬於哪個包,是相對於當前包而言的。

程式碼示例:
package reflect;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

/**
 * 演示三種載入類檔案的方式
 * @author songwenju
 *
 */
public class LoadDemo {
	public static void main(String[] args)throws Exception {
		Properties props = new Properties();
		
		//方式一,用FileInputStream
		InputStream ips = new FileInputStream("src/reflect/config.properties");
		 
		/* 方式二:
		 * 一個類載入器能載入.class檔案,那它當然也能載入classpath環境下的其他檔案,
		 * 既然它有如此能力,它也只能載入classpath環境下的那些檔案。
         */  
		ips = LoadDemo.class.getResourceAsStream("/reflect/config.properties");
		//方式三:Class提供了一個便利方法,用載入當前類的那個類載入器去載入相同包目錄下的檔案 
		//直接使用類載入器時,不能以/打頭。
		ips = LoadDemo.class.getClassLoader().getResourceAsStream("reflect/config.properties");
		props.load(ips);
		ips.close();
		
		String className = props.getProperty("ClassName");
		System.out.println(className);
		
		
	}
}
執行結果:


------- android培訓java培訓、期待與您交流! ----------

相關推薦

黑馬程式設計師——Java 反射技術

-----------android培訓、java培訓、java學習型技術部落格、期待與您交流!------------ 一、概述  1.理解反射:   反射就是把java類中的各種成分對映成相應的java類。  2.反射中常用的類:   Class類:是反射的基石,由它可

黑馬程式設計師-----java反射總結*

---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ---------------------- 一、java的反射機制概述 反射和類的關係:在程式執行狀態中,對於任意一個類(指.class檔案),都能

黑馬程式設計師——java反射機制

------- android培訓、java培訓、期待與您交流! ---------- 前言:通過觀看畢向東老師的java基礎視訊,查漏補缺,將一些自己掌握的還不牢固的知識寫出來,希望和大家交流分享。 一、反射技術是java在執行的時候獲取類的基本資訊。 反射技術大大提高了

黑馬程式設計師----Java基礎之反射

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g

黑馬程式設計師--java高新技術 25--列舉,反射

---------------------- ASP.Net+Android+IO開發S、.Net培訓、期待與您交流! ---------------------- /*1.5 新特性總結: 靜態匯入 可變引數 增強for(foreach) 基本資料的自動拆裝箱 列舉 泛

黑馬程式設計師-java高新技術(反射

一、反射 1、定義: Java程式中的各個Java類屬於統一類事物,描述這類事物的Java類名就是Class。反射機制指的是程式在執行時能夠獲取自身的資訊。在java中,只要給定類的名字,那麼就可以通過反射機制來獲得類的所有資訊。 2、優點和缺

黑馬程式設計師-java基礎加強-反射的深入講解

-------------------------ASP.Net+Unity開發、.Net培訓、期待與您交流!-------------------------- 透徹分析反射的基礎_Class類 Class類1、定義java程式中的各個java類也屬於同一類事物,而描述這

黑馬程式設計師------java中的反射,beanutils,註解的應用。

Class類:描述眾多java類的物件。代表記憶體裡的一份位元組碼。 有三種方式可以獲取一個類的Class檔案。 方法一:是通過該類物件.getClass()方法。 方法二:通過Class類的靜態方法,Class.forName("name"); 方法三:

黑馬程式設計師---java基礎加強 反射的深入理解

=================第5單元:反射的深入講解=============== 17.透徹分析反射的基礎_Class類 反射的基礎: Class也就是每個java源程式通過編譯後生成的檔案載入進入記憶體的那個位元組碼檔案, 獲取到該位元組碼,就可以獲取

黑馬程式設計師——Java高新技術_反射

反射技術: 其實就是動態載入一個指定的類,並獲取該類中的所有的內容。而且將位元組碼檔案封裝成物件,並將位元組碼檔案中的內容都封裝成物件,這樣便於操作這些成員。簡單說:反射技術可以對一個類進行解剖。 反射的好處:大大的增強了程式的擴充套件性。 反射的基本步驟: 1、獲得Class物件,就是獲取到指定的名稱的位

黑馬程式設計師——Java高新技術之反射學習總結一

                                                                                    反射學習總結 基礎補充: Java程式中的各個Java類屬於同一類事務,描述這類事務的Java類名就是C

黑馬程式設計師 Java高新技術--反射和內省

1.框架與框架要解決的核心問題:比如:我做房子賣給使用者住,由使用者自己安裝門窗和空調,我做的房子就是框架,使用者需要使用我的框架,把門窗插入進我提供的框架中。框架和工具類有區別,工具類被使用者的類呼叫,而框架則是呼叫使用者提供的類。2.框架要解決的核心問題:我在寫框架(房子)時,你這個使用者可能還在上小學,

黑馬程式設計師 java高新技術 反射

---------- android培訓、java培訓、期待與您交流! ---------- 一、Class類     Class是Java程式中各個Java類的總稱;它是反射的基石,通過Class類來使用反射。    物件的建立和使用:       建立例項物件:

黑馬程式設計師--java高新技術----反射

---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ---------------------- 什麼是反射?         反射就是把一個類中的各種元素對映成一個類。 得到一個類中的元素都是從這個

黑馬程式設計師-------Java高階特性--------反射

黑馬程式設計師—–Java高階特性—–反射 一.概述 Java 反射是Java語言的一個很重要的特徵,它使得Java具體了“動態性”。 這個機制允許程式在執行時透過Reflection APIs取得任何一個已知名稱的class的內部資訊,包括其mod

黑馬程式設計師——Java高新技術之反射

-------android培訓、java培訓、期待與您交流! ---------- 反射 JAVA反射機制是在執行狀態中,對於任意一個類 (class檔案),都能夠知道這個類的所有屬性和方法; 對於任意一個物件,都能夠呼叫它的任意一個方法和屬性

黑馬程式設計師JAVA高新技術之反射

反射 一、反射的基石   反射的基石是Class類。Java程式中的各個java類屬於同一類事物,描述這類事物的java類名就是Class. 1.1 Class類的分析   在程式執行時呼叫類的時候,首先將這個類在硬碟上的二進位制程式碼載入到記憶體中,才可以用這個類建立物件

黑馬程式設計師----Java基礎之GUI

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g

黑馬程式設計師----Java基礎之IO包中其它類

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g

黑馬程式設計師----Java基礎基礎之IO流

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g