反射

# 反射

## Java反射機制定義

Java反射機制是指在運行狀態(tài)中,<font color='red'>對于任意一個類鼎俘,都能夠知道這個類的所有屬性和方法</font>;<font color='red'>對于任意一個對象审丘,都能夠調(diào)用它的任意一個方法和屬性</font>窝趣;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制。

<font color='red'>用一句話總結(jié)就是反射可以實現(xiàn)在運行時可以知道任意一個類的屬性和方法训柴。</font>

#### 反射的概念

- 靜態(tài)編譯:在編譯時確定類型哑舒,綁定對象,即通過。

- 動態(tài)編譯:運行時確定類型幻馁,綁定對象洗鸵。動態(tài)編譯最大限度發(fā)揮了java的靈活性,體現(xiàn)了多態(tài)的應(yīng)用仗嗦,有以降低類之間的<font color='red'>藕合性</font>

耦合性:<font color='red'>指模塊之間的聯(lián)系及相互影響盡可能地少膘滨,必須聯(lián)系的應(yīng)加以明確的說明</font>,這種聯(lián)系及相互影響稱為模塊的藕合性稀拐。

耦合是<font color='orange'>影響軟件復(fù)雜程度的一個重要因素</font>火邓。應(yīng)該采取的原則是:<font color='red'>盡量使用數(shù)據(jù)耦合,少用控制耦合德撬,限制公共環(huán)境耦合的范圍铲咨,完全不用內(nèi)容耦合</font>

## 反射機制的優(yōu)點與缺點

#### 優(yōu)點

靈活性高。因為**反射屬于動態(tài)編譯**蜓洪,即只有到運行時才動態(tài)創(chuàng)建 &獲取對象實例纤勒。

編譯方式說明:

- 靜態(tài)編譯:在編譯時確定類型 & 綁定對象。如常見的使用`new`關(guān)鍵字創(chuàng)建對象

- 動態(tài)編譯:運行時確定類型 & 綁定對象隆檀。動態(tài)編譯體現(xiàn)了`Java`的靈活性摇天、多態(tài)特性 & 降低類之間的藕合性

#### 缺點

#### 缺點

<font color='red'>執(zhí)行效率低</font>,因為反射的操作主要通過JVM執(zhí)行恐仑,所以時間成本會高于直接執(zhí)行相同操作

- 因為接口的通用性泉坐,<font color='orange'>Java的invoke方法是傳object和object[]數(shù)組的</font>【账基本類型參數(shù)需要<font color='red'>裝箱</font>和<font color='red'>拆箱</font>坚冀,產(chǎn)生大量額外的對象和內(nèi)存開銷,頻繁促發(fā)GC(<font color='cornflowerblue'>垃圾回收</font>)

- 編譯器<font color='red'>難以</font>對動態(tài)調(diào)用的代碼提前做<font color='red'>優(yōu)化</font>

- 反射需要<font color='red'>按名檢索類和方法</font>鉴逞,有一定的時間開銷.

- <font color='red'>容易破壞類結(jié)構(gòu) </font>,因為反射操作饒過了源碼记某,容易干擾類原有的內(nèi)部邏輯

#### Java反射機制提供的功能

![img](反射.assets/12693685-301282eafa32f611.png)

#### <font color='red'>java.lang.Class</font> 類

> 定義:<font color='red'>java.lang.Class</font>類是反射機制的基礎(chǔ)

>? ? ? ? 作用:存放著對應(yīng)類型對象的運行時信息

>

> - 在Java程序運行時,Java虛擬機為所有類型維護一個<font color='red'>java.lang.Class</font>對象

> - 該Class對象存放著所有關(guān)于該對象的 運行時信息

> - 泛型形式為Class<T>

> <font color='red'>每種類型的Class對象只有1個 = 地址只有1個</font>

```Java

? ? ? ? // 對于2個String類型對象构捡,它們的Class對象相同

? ? ? ? Class c1 = "class".getClass();

? ? ? ? Class c2 = Class.forName("java.lang.String");

? ? ? ? // 用==運算符實現(xiàn)兩個類對象地址的比較

? ? ? ? System.out.println(c1 == c2);

? ? ? ? // 輸出結(jié)果:true

```

![image-20201214172821158](反射.assets/image-20201214172821158.png)

#### 實現(xiàn)方式

反射機制的實現(xiàn) 主要通過 操作<font color='red'>java.lang.Class</font>類

- 獲取 目標類型的Class對象

- 通過 Class 對象分別獲取Constructor類對象液南、Method類對象 & Field 類對象

- 通過 Constructor類對象、Method類對象 & Field類對象分別獲取類的構(gòu)造函數(shù)勾徽、方法&屬性的具體信息滑凉,并進行后續(xù)操作

#### 獲取 目標類型的`Class`對象的方式主要有4種方法

```java

? private static void getTargetClass() throws ClassNotFoundException {

? ? ? ? /** 方式1:Object.getClass()

? ? ? ? * Object類中的getClass()返回一個Class類型的實例*/

? ? ? ? Boolean temp = true;

? ? ? ? Class type = temp.getClass();

? ? ? ? System.out.println(type);//結(jié)果:class java.lang.Boolean

? ? ? ? /** 方式2:T.class 語法,T = 任意Java類型

? ? ? ? * 注:Class對象表示的是一個類型,而這個類型未必一定是類

? ? ? ? *如,int不是類畅姊,但int.class是一個Class類型的對象*/

? ? ? ? Class temp2 = Boolean.class;

? ? ? ? System.out.println(temp2);//結(jié)果:class java.lang.Boolean

? ? ? ? Class temp21 = int.class;

? ? ? ? System.out.println(temp21);//結(jié)果:int

? ? ? ? /** 方式3:static method Class.forName

? ? ? ? Class<?> classType = Class . forName ("java.lang.Boolean"); */

? ? ? ? Class temp3 = Class.forName("java.lang.Boolean");

? ? ? ? System.out.println(temp3);//結(jié)果:class java.lang.Boolean

? ? ? ? /** 方式4:TYPE語法

? ? ? ? * Class<?> classType = Boolean . TYPE*/

? ? ? ? Class<?> temp4 = Boolean.TYPE;

? ? ? ? System.out.println(temp4);//結(jié)果:boolean

? ? }

```

![image-20201214180258702](反射.assets/image-20201214180258702.png)

#### 反射類對應(yīng)關(guān)系

> Java反射機制的實現(xiàn)除了依靠Java.lang.Class類咒钟,還需要依靠:Constructor類、Field類若未、Method類朱嘴,分別作用于類的各個組成部分:

>

> ![img](https:////upload-images.jianshu.io/upload_images/12693685-12fdb465f74491df.png?imageMogr2/auto-orient/strip|imageView2/2/w/864/format/webp)

>

> image.png

#### Type類

> Type是Java中所有類型的通用超級接口編程語言。這些包括原始類型粗合,參數(shù)化類型萍嬉,數(shù)組類型、類型變量和原始類型

>? 以下為繼承Type子類

![img](https:////upload-images.jianshu.io/upload_images/12693685-5b894c289d2824f6.png?imageMogr2/auto-orient/strip|imageView2/2/w/877/format/webp)

image.png

#### 通過 Class 對象分別獲取Constructor類對象隙疚、Method類對象 & Field 類對

```java

// 即以下方法都屬于`Class` 類的方法壤追。

<-- 1. 獲取類的構(gòu)造函數(shù)(傳入構(gòu)造函數(shù)的參數(shù)類型)->>

? // a. 獲取指定的構(gòu)造函數(shù) (公共 / 繼承)

? Constructor<T> getConstructor(Class<?>... parameterTypes)

? // b. 獲取所有的構(gòu)造函數(shù)(公共 / 繼承)

? Constructor<?>[] getConstructors();

? // c. 獲取指定的構(gòu)造函數(shù) ( 不包括繼承)

? Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

? // d. 獲取所有的構(gòu)造函數(shù)( 不包括繼承)

? Constructor<?>[] getDeclaredConstructors();

// 最終都是獲得一個Constructor類對象

// 特別注意:

? // 1. 不帶 "Declared"的方法支持取出包括繼承、公有(Public) & 不包括有(Private)的構(gòu)造函數(shù)

? // 2. 帶 "Declared"的方法是支持取出包括公共(Public)供屉、保護(Protected)行冰、默認(包)訪問和私有(Private)的構(gòu)造方法,但不包括繼承的構(gòu)造函數(shù)

? // 下面同理

<--? 2. 獲取類的屬性(傳入屬性名) -->

? // a. 獲取指定的屬性(公共 / 繼承)

? Field getField(String name) ;

? // b. 獲取所有的屬性(公共 / 繼承)

? Field[] getFields() ;

? // c. 獲取指定的所有屬性 (不包括繼承)

? Field getDeclaredField(String name) 贯卦;

? // d. 獲取所有的所有屬性 (不包括繼承)

? Field[] getDeclaredFields() 资柔;

// 最終都是獲得一個Field類對象

<-- 3. 獲取類的方法(傳入方法名 & 參數(shù)類型)-->

? // a. 獲取指定的方法(公共 / 繼承)

? ? Method getMethod(String name, Class<?>... parameterTypes) ;

? // b. 獲取所有的方法(公共 / 繼承)

? Method[] getMethods() 撵割;

? // c. 獲取指定的方法 ( 不包括繼承)

? Method getDeclaredMethod(String name, Class<?>... parameterTypes) 贿堰;

? // d. 獲取所有的方法( 不包括繼承)

? Method[] getDeclaredMethods() ;

// 最終都是獲得一個Method類對象

<-- 4. Class類的其他常用方法 -->

getSuperclass();

// 返回父類

String getName();

// 作用:返回完整的類名(含包名啡彬,如java.lang.String )

Object newInstance();

// 作用:快速地創(chuàng)建一個類的實例

// 具體過程:調(diào)用默認構(gòu)造器(若該類無默認構(gòu)造器羹与,則拋出異常

// 注:若需要為構(gòu)造器提供參數(shù)需使用java.lang.reflect.Constructor中的newInstance()

```

#### 通過 Constructor類對象、Method類對象 & Field類對象分別獲取類的構(gòu)造函數(shù)方法 & 屬性的具體信息 & 進行操作

```java

// 即以下方法都分別屬于`Constructor`類庶灿、`Method`類 & `Field`類的方法纵搁。

<-- 1. 通過Constructor 類對象獲取類構(gòu)造函數(shù)信息 -->

? String getName();// 獲取構(gòu)造器名

? Class getDeclaringClass()往踢;// 獲取一個用于描述類中定義的構(gòu)造器的Class對象

? int getModifiers()腾誉;// 返回整型數(shù)值,用不同的位開關(guān)描述訪問修飾符的使用狀況

? Class[] getExceptionTypes()峻呕;// 獲取描述方法拋出的異常類型的Class對象數(shù)組

? Class[] getParameterTypes()利职;// 獲取一個用于描述參數(shù)類型的Class對象數(shù)組

<-- 2. 通過Field類對象獲取類屬性信息 -->

? String getName();// 返回屬性的名稱

? Class getDeclaringClass()瘦癌; // 獲取屬性類型的Class類型對象

? Class getType()猪贪;// 獲取屬性類型的Class類型對象

? int getModifiers(); // 返回整型數(shù)值讯私,用不同的位開關(guān)描述訪問修飾符的使用狀況

? Object get(Object obj) 热押;// 返回指定對象上 此屬性的值

? void set(Object obj, Object value) // 設(shè)置 指定對象上此屬性的值為value

<-- 3. 通過Method 類對象獲取類方法信息 -->

? String getName()西傀;// 獲取方法名

? Class getDeclaringClass();// 獲取方法的Class對象

? int getModifiers()桶癣;// 返回整型數(shù)值拥褂,用不同的位開關(guān)描述訪問修飾符的使用狀況

? Class[] getExceptionTypes();// 獲取用于描述方法拋出的異常類型的Class對象數(shù)組

? Class[] getParameterTypes()牙寞;// 獲取一個用于描述參數(shù)類型的Class對象數(shù)組

<--額外:java.lang.reflect.Modifier類 -->

// 作用:獲取訪問修飾符

static String toString(int modifiers)?

// 獲取對應(yīng)modifiers位設(shè)置的修飾符的字符串表示

static boolean isXXX(int modifiers)

// 檢測方法名中對應(yīng)的修飾符在modifiers中的值

```

#### 舉個例子,獲取String 所有構(gòu)造方法

![img](反射.assets/12693685-a9e0550bd2fb9e30.png)

image.png

#### 特別注意:訪問權(quán)限問題

> 反射機制的默認行為受限于Java的訪問控制

>? 如肿仑,無法訪問( private )私有的方法、字段

#### 沖突

> Java安全機制只允許查看任意對象有哪些域碎税,而不允許讀它們的值

>? 若強制讀取,將拋出異常

#### 解決方案

> 脫離Java程序中安全管理器的控制馏锡、屏蔽Java語言的訪問檢查雷蹂,從而脫離訪問控制

>? 具體實現(xiàn)手段:使用Field類、Method類 & Constructor類對象的setAccessible()

```java

void setAccessible(boolean flag)? ?

// 作用:為反射對象設(shè)置可訪問標志

// 規(guī)則:flag = true時 杯道,表示已屏蔽Java語言的訪問檢查匪煌,使得可以訪問 & 修改對象的私有屬性

boolean isAccessible()?

// 返回反射對象的可訪問標志的值

static void setAccessible(AccessibleObject[] array, boolean flag)?

// 設(shè)置對象數(shù)組可訪問標志

```

#### 實例1:利用反射獲取類的屬性 & 賦值

```java

/**

? ? * 測試類定義

? ? */

? ? public static class Student {

? ? ? ? private String name;

? ? ? ? public Student() {

? ? ? ? ? ? System.out.println("創(chuàng)建了一個Student實例");

? ? ? ? }

? ? }

? ? /**

? ? * 測試方法

? ? */

? ? private static void example() throws Exception {

? ? ? ? //利用反射獲取屬性 & 賦值

? ? ? ? // 1. 獲取Student類的Class對象

? ? ? ? Class<Student> studentClass = Student.class;

? ? ? ? // 2. 通過Class對象創(chuàng)建Student類的對象

? ? ? ? Constructor<?> constructor = studentClass.getDeclaredConstructor();

? ? ? ? constructor.setAccessible(true);

? ? ? ? Object mStudent = studentClass.newInstance();

? ? ? ? // 3. 通過Class對象獲取Student類的name屬性

? ? ? ? Field f = studentClass.getDeclaredField("name");

? ? ? ? // 4. 設(shè)置私有訪問權(quán)限

? ? ? ? f.setAccessible(true);

? ? ? ? // 5. 對新創(chuàng)建的Student對象設(shè)置name值

? ? ? ? f.set(mStudent, "我是java 反射");

? ? ? ? // 6. 獲取新創(chuàng)建Student對象的的name屬性 & 輸出

? ? ? ? System.out.println(f.get(mStudent));

? ? }

```

測試結(jié)果

![img](反射.assets/12693685-1a8ecebe6b58a07a.png)

#### 利用反射調(diào)用類的構(gòu)造函數(shù)

```java

/**

? ? * 測試類定義

? ? */

? ? public static class Student2 {

? ? ? ? private String name;

? ? ? ? public Student2() {

? ? ? ? ? ? System.out.println("無參構(gòu)造 ");

? ? ? ? }

? ? ? ? public Student2(String str) {

? ? ? ? ? ? System.out.println("有參構(gòu)造 " + "****" + str);

? ? ? ? }

? ? }

? ? /**

? ? * 利用反射調(diào)用構(gòu)造函數(shù)

? ? */

? ? private static void example2() throws Exception {

? ? ? ? //利用反射調(diào)用構(gòu)造函數(shù)

? ? ? ? // 1. 獲取Student類的Class對象

? ? ? ? Class studentClass = Student2.class;

? ? ? ? // 2.1 通過Class對象獲取Constructor類對象,從而調(diào)用無參構(gòu)造方法

? ? ? ? // 注:構(gòu)造函數(shù)的調(diào)用實際上是在newInstance()党巾,而不是在getConstructor()中調(diào)用

? ? ? ? Object mObj1 = studentClass.getConstructor().newInstance();

? ? ? ? // 2.2 通過Class對象獲取Constructor類對象(傳入?yún)?shù)類型)萎庭,從而調(diào)用有參構(gòu)造方法

? ? ? ? Object mObj2 = studentClass.getConstructor(String.class).newInstance("OK");

? ? }

```

[圖片上傳失敗...(image-1c62c9-1532574152311)]

#### 利用反射調(diào)用方法

```java

/**

? ? * 測試類定義

? ? */

? ? public static class Student {

? ? ? ? public Student() {

? ? ? ? ? ? System.out.println("創(chuàng)建了一個Student實例");

? ? ? ? }

? ? ? ? // 無參數(shù)方法

? ? ? ? public void setName1() {

? ? ? ? ? ? System.out.println("調(diào)用了無參方法:setName1()");

? ? ? ? }

? ? ? ? // 有參數(shù)方法

? ? ? ? public void setName2(String str) {

? ? ? ? ? ? System.out.println("調(diào)用了有參方法setName2(String str):" + str);

? ? ? ? }

? ? }

? ? /**

? ? * 利用反射調(diào)用方法

? ? */

? ? private static void example2() throws Exception {

? ? ? ? //利用反射調(diào)用方法

? ? ? ? // 1. 獲取Student類的Class對象

? ? ? ? Class studentClass = Student.class;

? ? ? ? // 2. 通過Class對象創(chuàng)建Student類的對象

? ? ? ? Object mStudent = studentClass.newInstance();

? ? ? ? // 3.1 通過Class對象獲取方法setName1()的Method對象:需傳入方法名

? ? ? ? // 因為該方法 = 無參,所以不需要傳入?yún)?shù)

? ? ? ? Method msetName1 = studentClass.getMethod("setName1");

? ? ? ? // 通過Method對象調(diào)用setName1():需傳入創(chuàng)建的實例

? ? ? ? msetName1.invoke(mStudent);

? ? ? ? // 3.2 通過Class對象獲取方法setName2()的Method對象:需傳入方法名 & 參數(shù)類型

? ? ? ? Method msetName2 = studentClass.getMethod("setName2", String.class);

? ? ? ? // 通過Method對象調(diào)用setName2():需傳入創(chuàng)建的實例 & 參數(shù)值

? ? ? ? msetName2.invoke(mStudent, "Carson_Ho");

? ? }

```

![img](反射.assets/12693685-950889882fd29df7.png)

## API

Kotlin 反射 API 主要來自于 `kotlin.reflect`齿拂、`kotlin.reflect.full` 和 `kotlin.reflect.jvm` 包驳规。其中 `kotlin.reflect`、`kotlin.reflect.full` 是主要的 Kotlin 反射 API署海,而 `kotlin.reflect.jvm` 包主要用于 Kotlin 反射 和 Java 反射的互操作吗购。

??**`kotlin.reflect`** 包是 Kotlin 反射核心 API,它的類圖如下圖 1-1 所示砸狞,它們都是接口捻勉,詳細說明如下:

- `KCkass`。表示一個具有反射功能的類刀森。

- `KParameter`踱启。表示一個具有反射功能的 可傳遞給函數(shù)或?qū)傩缘膮?shù)。

- `KCallable`研底。表示具有反射功能的可調(diào)用實例埠偿,包括屬性和函數(shù),它的直接子接口有 KProperty 和 KFunction飘哨。

- `KFunction`胚想。表示一個具有反射功能的函數(shù)。

- `KProperty`芽隆。表示一個具有反射功能的屬性浊服,它有很多子接口统屈。KProperty0、KProperty1 和 KProperty2 后面的數(shù)字表示接收者作為參數(shù)的個數(shù)牙躺。

- `KMutableProperty`愁憔。表示一個具有反射功能的使用 var 聲明的屬性。KMutableProperty0孽拷、KMutableProperty1 和 KMutableProperty2 后面的數(shù)字含義同 KProperty吨掌。

![img](反射.assets/16251880-81a3a8fbbc0457c9.png)

**注意:**Kotlin 反射 API 所需要的運行時組件來自于獨立的 **`kotlin-reflect.jar`** 文件,在 Android 等移動平臺上為了減少應(yīng)用程序包的大小脓恕,應(yīng)用程序包再默認情況下不包含 **`kotlin-reflect.jar`** 文件膜宋。如果要在應(yīng)用中使用反射功能,則需要額外添加 **`kotlin-reflect.jar`** 文件至應(yīng)用程序包中炼幔,并添加 **`kotlin-reflect.jar`** 到項目的類路徑秋茫。

# Properties

Properties 繼承于 Hashtable。表示一個持久的屬性集乃秀,屬性列表以key-value的形式存在肛著,key和value都是字符串。

Properties 類被許多Java類使用跺讯。例如枢贿,在獲取環(huán)境變量時它就作為System.getProperties()方法的返回值。

我們在很多**需要避免硬編碼的應(yīng)用場景**下需要使用properties文件來加載程序需要的配置信息刀脏,比如JDBC局荚、MyBatis框架等。Properties類則是properties文件和程序的中間橋梁火本,不論是從properties文件讀取信息還是寫入信息到properties文件都要經(jīng)由Properties類危队。

### 常見方法

除了從Hashtable中所定義的方法,Properties定義了以下方法:

![img](反射.assets/2510824-6f56a4a4165d4acc.png)

Properties類

下面我們從**寫入钙畔、讀取茫陆、遍歷**等角度來解析Properties類的常見用法:

### 寫入

Properties類調(diào)用setProperty方法將鍵值對保存到內(nèi)存中,此時可以通過getProperty方法讀取擎析,propertyNames方法進行遍歷簿盅,但是并沒有將鍵值對持久化到屬性文件中,故需要調(diào)用store方法持久化鍵值對到屬性文件中揍魂。

```java

package cn.habitdiary;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Date;

import java.util.Enumeration;

import java.util.Properties;

import junit.framework.TestCase;

public class PropertiesTester extends TestCase {

? ? public void writeProperties() {

? ? ? ? Properties properties = new Properties();

? ? ? ? OutputStream output = null;

? ? ? ? try {

? ? ? ? ? ? output = new FileOutputStream("config.properties");

? ? ? ? ? ? properties.setProperty("url", "jdbc:mysql://localhost:3306/");

? ? ? ? ? ? properties.setProperty("username", "root");

? ? ? ? ? ? properties.setProperty("password", "root");

? ? ? ? ? ? properties.setProperty("database", "users");//保存鍵值對到內(nèi)存

? ? ? ? ? ? properties.store(output, "Steven1997 modify" + new Date().toString());

? ? ? ? ? ? ? ? ? ? ? ? // 保存鍵值對到文件中

? ? ? ? } catch (IOException io) {

? ? ? ? ? ? io.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? if (output != null) {

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? output.close();

? ? ? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? }

}

```

### 讀取

下面給出常見的六種讀取properties文件的方式:

```java

package cn.habitdiary;

import java.io.BufferedInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.util.Locale;

import java.util.Properties;

import java.util.PropertyResourceBundle;

import java.util.ResourceBundle;

/**

* 讀取properties文件的方式

*

*/

public class LoadPropertiesFileUtil {

? ? private static String basePath = "src/main/java/cn/habitdiary/prop.properties";

? ? private static String path = "";

? ? /**

? ? * 一桨醋、 使用java.util.Properties類的load(InputStream in)方法加載properties文件

? ? *

? ? * @return

? ? */

? ? public static String getPath1() {

? ? ? ? try {

? ? ? ? ? ? InputStream in = new BufferedInputStream(new FileInputStream(

? ? ? ? ? ? ? ? ? ? new File(basePath)));

? ? ? ? ? ? Properties prop = new Properties();

? ? ? ? ? ? prop.load(in);

? ? ? ? ? ? path = prop.getProperty("path");

? ? ? ? } catch (FileNotFoundException e) {

? ? ? ? ? ? System.out.println("properties文件路徑書寫有誤,請檢查现斋!");

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return path;

? ? }

? ? /**

? ? * 二喜最、 使用java.util.ResourceBundle類的getBundle()方法

? ? * 注意:這個getBundle()方法的參數(shù)只能寫成包路徑+properties文件名,否則將拋異常

? ? *

? ? * @return

? ? */

? ? public static String getPath2() {

? ? ? ? ResourceBundle rb = ResourceBundle

? ? ? ? ? ? ? ? .getBundle("cn/habitdiary/prop");

? ? ? ? path = rb.getString("path");

? ? ? ? return path;

? ? }

? ? /**

? ? * 三庄蹋、 使用java.util.PropertyResourceBundle類的構(gòu)造函數(shù)

? ? *

? ? * @return

? ? */

? ? public static String getPath3() {

? ? ? ? InputStream in;

? ? ? ? try {

? ? ? ? ? ? in = new BufferedInputStream(new FileInputStream(basePath));

? ? ? ? ? ? ResourceBundle rb = new PropertyResourceBundle(in);

? ? ? ? ? ? path = rb.getString("path");

? ? ? ? } catch (FileNotFoundException e) {

? ? ? ? ? ? // TODO Auto-generated catch block

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return path;

? ? }

? ? /**

? ? * 四瞬内、 使用class變量的getResourceAsStream()方法

? ? * 注意:getResourceAsStream()方法的參數(shù)按格式寫到包路徑+properties文件名+.后綴

? ? *

? ? * @return

? ? */

? ? public static String getPath4() {

? ? ? ? InputStream in = LoadPropertiesFileUtil.class

? ? ? ? ? ? ? ? .getResourceAsStream("cn/habitdiary/prop.properties");

? ? ? ? Properties p = new Properties();

? ? ? ? try {

? ? ? ? ? ? p.load(in);

? ? ? ? ? ? path = p.getProperty("path");

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return path;

? ? }

? ? /**

? ? * 五迷雪、

? ? * 使用class.getClassLoader()所得到的java.lang.ClassLoader的

? ? * getResourceAsStream()方法

? ? * getResourceAsStream(name)方法的參數(shù)必須是包路徑+文件名+.后綴

? ? * 否則會報空指針異常

? ? * @return

? ? */

? ? public static String getPath5() {

? ? ? ? InputStream in = LoadPropertiesFileUtil.class.getClassLoader()

? ? ? ? ? ? ? ? .getResourceAsStream("cn/habitdiary/prop.properties");

? ? ? ? Properties p = new Properties();

? ? ? ? try {

? ? ? ? ? ? p.load(in);

? ? ? ? ? ? path = p.getProperty("path");

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return path;

? ? }

? ? /**

? ? * 六、 使用java.lang.ClassLoader類的getSystemResourceAsStream()靜態(tài)方法

? ? * getSystemResourceAsStream()方法的參數(shù)格式也是有固定要求的

? ? *

? ? * @return

? ? */

? ? public static String getPath6() {

? ? ? ? InputStream in = ClassLoader

? ? ? ? ? ? ? ? .getSystemResourceAsStream("cn/habitdiary/prop.properties");

? ? ? ? Properties p = new Properties();

? ? ? ? try {

? ? ? ? ? ? p.load(in);

? ? ? ? ? ? path = p.getProperty("path");

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? // TODO Auto-generated catch block

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return path;

? ? }

? ? public static void main(String[] args) {

? ? ? ? System.out.println(LoadPropertiesFileUtil.getPath1());

? ? ? ? System.out.println(LoadPropertiesFileUtil.getPath2());

? ? ? ? System.out.println(LoadPropertiesFileUtil.getPath3());

? ? ? ? System.out.println(LoadPropertiesFileUtil.getPath4());

? ? ? ? System.out.println(LoadPropertiesFileUtil.getPath5());

? ? ? ? System.out.println(LoadPropertiesFileUtil.getPath6());

? ? }

}

```

其中第一虫蝶、四章咧、五、六種方式都是先獲得文件的輸入流能真,然后通過Properties類的load(InputStream inStream)方法加載到Properties對象中赁严,最后通過Properties對象來操作文件內(nèi)容。

第二粉铐、三中方式是通過ResourceBundle類來加載Properties文件疼约,然后ResourceBundle對象來操做properties文件內(nèi)容。

**其中最重要的就是每種方式加載文件時蝙泼,文件的路徑需要按照方法的定義的格式來加載忆谓,否則會拋出各種異常,比如空指針異常踱承。**

### 遍歷

下面給出四種遍歷Properties中的所有鍵值對的方法:

```java

? ? /**

? ? * 輸出properties的key和value

? ? */

? ? public static void printProp(Properties properties) {

? ? ? ? System.out.println("---------(方式一)------------");

? ? ? ? for (String key : properties.stringPropertyNames()) {

? ? ? ? ? ? System.out.println(key + "=" + properties.getProperty(key));

? ? ? ? }

? ? ? ? System.out.println("---------(方式二)------------");

? ? ? ? Set<Object> keys = properties.keySet();//返回屬性key的集合

? ? ? ? for (Object key : keys) {

? ? ? ? ? ? System.out.println(key.toString() + "=" + properties.get(key));

? ? ? ? }

? ? ? ? System.out.println("---------(方式三)------------");

? ? ? ? Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();

? ? ? ? //返回的屬性鍵值對實體

? ? ? ? for (Map.Entry<Object, Object> entry : entrySet) {

? ? ? ? ? ? System.out.println(entry.getKey() + "=" + entry.getValue());

? ? ? ? }

? ? ? ? System.out.println("---------(方式四)------------");

? ? ? ? Enumeration<?> e = properties.propertyNames();

? ? ? ? while (e.hasMoreElements()) {

? ? ? ? ? ? String key = (String) e.nextElement();

? ? ? ? ? ? String value = properties.getProperty(key);

? ? ? ? ? ? System.out.println(key + "=" + value);

? ? ? ? }

? ? }

```

dom4j

maven

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哨免,隨后出現(xiàn)的幾起案子茎活,更是在濱河造成了極大的恐慌,老刑警劉巖琢唾,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件载荔,死亡現(xiàn)場離奇詭異,居然都是意外死亡采桃,警方通過查閱死者的電腦和手機懒熙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來普办,“玉大人工扎,你說我怎么就攤上這事∠味祝” “怎么了肢娘?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舆驶。 經(jīng)常有香客問我橱健,道長,這世上最難降的妖魔是什么沙廉? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任拘荡,我火速辦了婚禮,結(jié)果婚禮上撬陵,老公的妹妹穿的比我還像新娘珊皿。我一直安慰自己网缝,他們只是感情好,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布亮隙。 她就那樣靜靜地躺著途凫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溢吻。 梳的紋絲不亂的頭發(fā)上维费,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音促王,去河邊找鬼犀盟。 笑死,一個胖子當著我的面吹牛蝇狼,可吹牛的內(nèi)容都是我干的阅畴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼迅耘,長吁一口氣:“原來是場噩夢啊……” “哼贱枣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颤专,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纽哥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后栖秕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體春塌,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腰湾。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吼句,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情事格,我是刑警寧澤命辖,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站分蓖,受9級特大地震影響尔艇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜么鹤,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一终娃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蒸甜,春花似錦棠耕、人聲如沸余佛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辉巡。三九已至,卻和暖如春蕊退,著一層夾襖步出監(jiān)牢的瞬間郊楣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工瓤荔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留净蚤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓输硝,卻偏偏與公主長得像今瀑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子点把,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

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

  • 今天感恩節(jié)哎橘荠,感謝一直在我身邊的親朋好友。感恩相遇郎逃!感恩不離不棄砾医。 中午開了第一次的黨會,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,564評論 0 11
  • 彩排完衣厘,天已黑
    劉凱書法閱讀 4,217評論 1 3
  • 表情是什么,我認為表情就是表現(xiàn)出來的情緒压恒。表情可以傳達很多信息影暴。高興了當然就笑了,難過就哭了探赫。兩者是相互影響密不可...
    Persistenc_6aea閱讀 125,036評論 2 7