日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java cookbook 3_CookBook/Java核心/3-Java反射.md at master · zhgdbut/CookBook · GitHub

發(fā)布時(shí)間:2024/9/27 java 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java cookbook 3_CookBook/Java核心/3-Java反射.md at master · zhgdbut/CookBook · GitHub 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

#Java核心(三)反射

Java反射給我們提供了在運(yùn)行時(shí)檢查甚至修改應(yīng)用行為的機(jī)制。 反射是java高級(jí)的核心技術(shù),所有有經(jīng)驗(yàn)的程序員都應(yīng)該理解。

通過反射機(jī)制,我們可以在運(yùn)行時(shí)檢視 類、接口、枚舉,獲得他們的結(jié)構(gòu)、方法以及屬性信息,即使在編譯期類是不可訪問的。 我們也可以通過反射創(chuàng)建類實(shí)例,調(diào)用它的方法,或者改變屬性值。

##Java中的反射

Java的反射是一種很強(qiáng)大的機(jī)制,在正常的編程中使用并不多,但它是java的主干,很多Java EE 框架均使用了反射技術(shù):

- **JUnit** 利用反射技術(shù)解析@Test注解,從而得到測(cè)試的方法并調(diào)用它們。

- **Spring** 依賴注入是java反射的典型應(yīng)用

- **Tomcat** web容器通過解析web.xml文件和請(qǐng)求url,將請(qǐng)求正確的轉(zhuǎn)發(fā)到對(duì)應(yīng)的模塊。

- **Eclipse** 自動(dòng)完成方法的名稱輸入

- **Struts**

- **Hibernate**

以上這個(gè)清單只是小部分,它們?nèi)渴褂昧朔瓷浼夹g(shù),因?yàn)檎G闆r下,它們無法訪問用戶編寫的類、接口以及方法等。

但是我們不建議在正常編程中濫用反射技術(shù),因?yàn)槲覀儞碛凶约壕帉懙念惖脑L問權(quán)限了,反射存在以下幾個(gè)缺陷:

- **性能較差** 盡管反射解決了動(dòng)態(tài)類型的問題,但是也引入了在classpath 掃描類進(jìn)行加載的過程,會(huì)影響性能。

- **安全限制** 反射需要在運(yùn)行時(shí)獲得訪問權(quán)限,但是在security manager中可能是不允許的。 這可能會(huì)導(dǎo)致應(yīng)用運(yùn)行失敗。

- **安全問題** 通過反射我們可以訪問那些不建議我們?cè)L問的類,例如我們可以訪問private的屬性并修改其值。 這可能引發(fā)安全問題導(dǎo)致應(yīng)用異常。

- **較高的維護(hù)代價(jià)** 反射相關(guān)的代碼難以理解以及調(diào)試,代碼的錯(cuò)誤不能在編譯期展現(xiàn)出來,使用反射的代碼靈活性不高并難以維護(hù)。

##反射在類中的使用

在java中,任何對(duì)象要么是原始類型或者引用類型。 所有的類、枚舉、數(shù)據(jù)和其他引用類型均繼承自O(shè)bject類。

java.lang.Class是所有反射操作的入口。對(duì)于任何類型的對(duì)象,JVM 會(huì)初始化其一個(gè)不可變的java.lang.Class 實(shí)例來提供檢查對(duì)象的運(yùn)行時(shí)的屬性、創(chuàng)建新對(duì)象、調(diào)用方法、get/set 屬性。

我們來看看Class的重要方法,為了方便起見,我們先創(chuàng)建一些類和接口。

```java

package com.byron4j.hightLevel.reflection;

public interface BaseInterface {

public int interfaceInt=0;

void method1();

int method2(String str);

}

```

```java

package com.byron4j.hightLevel.reflection;

public class BaseClass {

public int baseInt;

private static void method3(){

System.out.println("Method3");

}

public int method4(){

System.out.println("Method4");

return 0;

}

public static int method5(){

System.out.println("Method5");

return 0;

}

void method6(){

System.out.println("Method6");

}

// piblic 的內(nèi)部類

public class BaseClassInnerClass{}

// public 的枚舉

public enum BaseClassMemberEnum{}

}

```

```java

package com.byron4j.hightLevel.reflection;

public class ConcreteClass extends BaseClass implements BaseInterface{

public int publicInt;

private String privateString="private string";

protected boolean protectedBoolean;

Object defaultObject;

public ConcreteClass(int i){

this.publicInt=i;

}

@Override

public void method1() {

System.out.println("Method1 impl.");

}

@Override

public int method2(String str) {

System.out.println("Method2 impl.");

return 0;

}

@Override

public int method4(){

System.out.println("Method4 overriden.");

return 0;

}

public int method5(int i){

System.out.println("Method4 overriden.");

return 0;

}

// inner classes

public class ConcreteClassPublicClass{}

private class ConcreteClassPrivateClass{}

protected class ConcreteClassProtectedClass{}

class ConcreteClassDefaultClass{}

//member enum

enum ConcreteClassDefaultEnum{}

public enum ConcreteClassPublicEnum{}

//member interface

public interface ConcreteClassPublicInterface{}

}

```

下面來看看使用反射的常用方法。

####獲得Class對(duì)象

我們可以通過三種方式獲取對(duì)象的Class實(shí)例:

- 通過靜態(tài)變量class

- 使用示例的getClass()方法

- java.lang.Class.forName(String 完整的類名),完整的類名包含包名。

原始類型的class、包裝類型的TYPE均可以獲得Class對(duì)象。

```java

package com.byron4j.hightLevel.reflection;

public class ReflectionDemo {

public static void main(String[] args) throws Exception{

//方式一: 通過累的靜態(tài)變量class獲取Class對(duì)象

Class concreteClass = ConcreteClass.class;

//方式二:通過實(shí)例的getClass()方法獲取Class對(duì)象

concreteClass = new ConcreteClass(7).getClass();

//方式三:

concreteClass = Class.forName("com.byron4j.hightLevel.reflection.ConcreteClass");

//打印類相關(guān)信息

System.out.println(concreteClass.getCanonicalName());

System.out.println(concreteClass.getName());

/*++++++++++++++++++++++++++++++++++++++++++++++++

* 原始類型的class、包裝類型的TYPE

* +++++++++++++++++++++++++++++++++++++++++++++++

*/

Class primative = boolean.class;

System.out.println(primative.getCanonicalName());

Class doubleClass = Double.TYPE;

System.out.println(doubleClass.getName());

//數(shù)組類型的class示例

Class> arrayClass = Class.forName("[D");

System.out.println(arrayClass.getCanonicalName());

arrayClass = Class.forName("[B");

System.out.println(arrayClass.getCanonicalName());

arrayClass = Class.forName("[S");

System.out.println(arrayClass.getCanonicalName());

arrayClass = Class.forName("[C");

System.out.println(arrayClass.getCanonicalName());

arrayClass = Class.forName("[F");

System.out.println(arrayClass.getCanonicalName());

}

}

```

輸出如下所示:

```

com.byron4j.hightLevel.reflection.ConcreteClass

com.byron4j.hightLevel.reflection.ConcreteClass

boolean

double

double[]

byte[]

short[]

char[]

float[]

```

Class的getCanonicalName()方法返回類的名稱。在泛型中使用 java.lang.Class,可以幫助框架獲取子類。

####獲取超類Super Class

**getSuperclass()** 方法,返回類的超類(基類、父類)的class實(shí)例,如果該類是java.lang.Object、原始類型、接口則返回null。如果該class是數(shù)組形式,則該方法返回java.lang.Object。

```java

Class> superClass = Class.forName("com.byron4j.hightLevel.reflection.ConcreteClass").getSuperclass();

System.out.println(superClass);

System.out.println(Object.class.getSuperclass());

System.out.println(String[][].class.getSuperclass());

```

輸入如下:

```

class com.byron4j.hightLevel.reflection.BaseClass

null

class java.lang.Object

```

####獲取公有的class

Class的getClasses() 方法可以獲取class的所有繼承的超類、接口和自己定義的公有類、接口、枚舉等的數(shù)組形式。

```java

Class[] classARR = concreteClass.getClasses();

System.out.println(Arrays.toString(classARR));

```

輸出:

```java

[class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicClass,

class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicEnum,

interface com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicInterface,

class com.byron4j.hightLevel.reflection.BaseClass$BaseClassInnerClass,

class com.byron4j.hightLevel.reflection.BaseClass$BaseClassMemberEnum]

```

#### 獲取自身聲明的類

**getDeclaredClasses()**獲取當(dāng)前類型自身定義的所有類、接口,并不包含從父類繼承過來的來、接口。

```java

Class[] declareClassARR = concreteClass.getDeclaredClasses();

System.out.println("Arrays.toString(declareClassARR));

```

輸出:

```

[class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassDefaultClass,

class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassDefaultEnum,

class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPrivateClass,

class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassProtectedClass,

class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicClass,

class com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicEnum,

interface com.byron4j.hightLevel.reflection.ConcreteClass$ConcreteClassPublicInterface]

```

#### 獲取定義該class的類

class.getDeclaringClass()獲取定義class的類。如果該類不是任何類或接口的成員,則返回null。

```java

/**================================================

* getDeclaringClass

* ================================================

*/

System.out.println(BaseClassInnerClass.class.getDeclaringClass());

System.out.println(Double.TYPE.getDeclaringClass());

```

該類BaseClassInnerClass是在BaseClass中定義的,于是輸出:

```

class com.byron4j.hightLevel.reflection.BaseClass

null

```

#### 獲取包名

getPackage() 方法獲取包的class實(shí)例。

```java

/*===========================================

* getPackage()

* ==========================================

*/

System.out.println(concreteClass.getPackage().getName());

```

輸出:

```

com.byron4j.hightLevel.reflection

```

#### 獲取類的修飾符

getModifiers()方法可以獲取class實(shí)例的訪問修飾符的個(gè)數(shù)。java.lang.reflect.Modifier.toString()可以獲取class的修飾符的字符串形式。

```java

/*===========================================

* getModifiers()、Modifier.toString()

* ==========================================

*/

System.out.println(concreteClass.getModifiers());

System.out.println(Modifier.toString(concreteClass.getModifiers()));

```

輸出:

```

1

public

```

#### 獲取類型參數(shù)

getTypeParameters()方法獲取class的類型聲明參數(shù),如果有的話。比如集合框架的接口均制定了泛型。

```java

Arrays.asList(Class.forName("java.util.Map").getTypeParameters()).forEach(

s -> { System.out.println(s); }

);

```

輸出:

> K

> V

####獲取class實(shí)現(xiàn)的接口

getGenericInterfaces() 可以獲取class已經(jīng)實(shí)現(xiàn)的接口的數(shù)組形式,并包含泛型接口。 getInterfaces()方法會(huì)返回所有實(shí)現(xiàn)的接口,但是不包含泛型接口。

```java

/**=============================================

* getGenericInterfaces()、getInterfaces()

* =============================================

*/

Arrays.asList(concreteClass.getInterfaces()).forEach(

s -> { System.out.println("com.byron4j.hightLevel.reflection.ConcreteClass實(shí)現(xiàn)的接口:" + s); }

);

System.out.println("========================================");

Arrays.asList(concreteClass.getGenericInterfaces()).forEach(

s -> { System.out.println("com.byron4j.hightLevel.reflection.ConcreteClass實(shí)現(xiàn)的接口:" + s); }

);

System.out.println("========================================");

System.out.println("========================================");

Arrays.asList(Class.forName("java.util.ArrayList").getInterfaces()).forEach(

s -> { System.out.println("java.util.ArrayList實(shí)現(xiàn)的接口:" + s); }

);

System.out.println("========================================");

Arrays.asList(Class.forName("java.util.ArrayList").getGenericInterfaces()).forEach(

s -> { System.out.println("java.util.ArrayList實(shí)現(xiàn)的接口:" + s); }

);

```

輸出:

```

com.byron4j.hightLevel.reflection.ConcreteClass實(shí)現(xiàn)的接口:interface com.byron4j.hightLevel.reflection.BaseInterface

========================================

com.byron4j.hightLevel.reflection.ConcreteClass實(shí)現(xiàn)的接口:interface com.byron4j.hightLevel.reflection.BaseInterface

========================================

========================================

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.util.List

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.util.RandomAccess

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.lang.Cloneable

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.io.Serializable

========================================

java.util.ArrayList實(shí)現(xiàn)的接口:java.util.List

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.util.RandomAccess

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.lang.Cloneable

java.util.ArrayList實(shí)現(xiàn)的接口:interface java.io.Serializable

```

####獲取所有的public方法

getMethods()方法可以獲取所有的public方法,包含父類、接口中繼承來的public方法。

```java

/**=============================================

* getMethods()

* =============================================

*/

System.out.println("========================================");

Arrays.asList(concreteClass.getMethods()).forEach(

s -> { System.out.println("public類型的方法:" + s); }

);

```

輸出:

```

public類型的方法:public void com.byron4j.hightLevel.reflection.ConcreteClass.method1()

public類型的方法:public int com.byron4j.hightLevel.reflection.ConcreteClass.method2(java.lang.String)

public類型的方法:public int com.byron4j.hightLevel.reflection.ConcreteClass.method4()

public類型的方法:public int com.byron4j.hightLevel.reflection.ConcreteClass.method5(int)

public類型的方法:public static int com.byron4j.hightLevel.reflection.BaseClass.method5()

public類型的方法:public final void java.lang.Object.wait() throws java.lang.InterruptedException

public類型的方法:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

public類型的方法:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

public類型的方法:public boolean java.lang.Object.equals(java.lang.Object)

public類型的方法:public java.lang.String java.lang.Object.toString()

public類型的方法:public native int java.lang.Object.hashCode()

public類型的方法:public final native java.lang.Class java.lang.Object.getClass()

public類型的方法:public final native void java.lang.Object.notify()

public類型的方法:public final native void java.lang.Object.notifyAll()

```

####獲取class的所有public構(gòu)造器

getConstructors()方法能夠獲取所有的public類型構(gòu)造器

```java

/**=============================================

* getConstructors()

* =============================================

*/

System.out.println("========================================");

Arrays.asList(concreteClass.getConstructors()).forEach(

s -> { System.out.println("public類型的構(gòu)造器:" + s); }

);

```

輸出:

> public類型的構(gòu)造器:public com.byron4j.hightLevel.reflection.ConcreteClass(int)

####獲取所有的public屬性(成員變量)

getFields()方法可以獲取所有的public屬性。包含父類、接口中的屬性。

```java

/**=============================================

* getFields()

* =============================================

*/

System.out.println("========================================");

Arrays.asList(concreteClass.getFields()).forEach(

s -> { System.out.println("public類型的屬性:" + s); }

);

```

輸出:

```

public類型的屬性:public int com.byron4j.hightLevel.reflection.ConcreteClass.publicInt

public類型的屬性:public static final int com.byron4j.hightLevel.reflection.BaseInterface.interfaceInt

public類型的屬性:public int com.byron4j.hightLevel.reflection.BaseClass.baseInt

```

####獲取所有的注解

getAnnotations()方法可以獲取所有的注解。但是只有保留策略為**RUNTIME**的注解。

我們給 類加上注解@Deprecated。

```java

@Deprecated

public class ConcreteClass extends BaseClass implements BaseInterface{...}

/

/**=============================================

* getAnnotations()

* =============================================

*/

System.out.println("========================================");

Arrays.asList(concreteClass.getAnnotations()).forEach(

s -> { System.out.println("注解:" + s); }

);

```

輸出:

> 注解:@java.lang.Deprecated()

##反射在屬性(成員變量)中的應(yīng)用

反射API提供了幾個(gè)方法可以在運(yùn)行時(shí)分解類的成員變量以及設(shè)置其值。

####獲取public屬性

除了前面的getFields()方法能獲取全部public屬性之外,還提供了一個(gè)獲取指定屬性名稱的方法getField()。這個(gè)方法會(huì)在該class-->接口-->父類的順序?qū)ふ抑付ǖ膶傩浴?/p>

**場(chǎng)景一**:我們?cè)贑oncreteClass類、BaseClass類、BaseInterface接口分別增加一個(gè)屬性:

public String name = "currClass---NAME";

public String name = "superClass---NAME";

public String name = "superInterface---NAME";

```java

System.out.println(concreteClass.getField("name"));

輸出為:

public java.lang.String com.byron4j.hightLevel.reflection.ConcreteClass.name

```

**場(chǎng)景二**:我們?cè)贐aseClass類、BaseInterface接口分別增加一個(gè)屬性:

public String name = "superClass---NAME";

public String name = "superInterface---NAME";

這時(shí)候獲取的屬性name是接口中的屬性:

> public static final java.lang.String com.byron4j.hightLevel.reflection.BaseInterface.name

**場(chǎng)景三**:我們僅僅在BaseClass類增加一個(gè)屬性:

public String name = "superClass---NAME";

這時(shí)候獲取的屬性name是父類中的屬性:

> public java.lang.String com.byron4j.hightLevel.reflection.BaseClass.name

如果是獲取不存在的屬性,則出現(xiàn)異常:

System.out.println(concreteClass.getField("hello"));

輸出:

> java.lang.NoSuchFieldException: hello

####獲取聲明屬性的類型

```java

try {

System.out.println( concreteClass.getField("interfaceInt").getDeclaringClass() );

} catch (NoSuchFieldException | SecurityException e) {

e.printStackTrace();

}

```

輸出:

> interface com.byron4j.hightLevel.reflection.BaseInterface

####獲取屬性的類型

getType()方法返回屬性的類型的class實(shí)例。

```

System.out.println(concreteClass.getField("interfaceInt").getType().getCanonicalName());

```

輸出:

> int

####Get/Set public類型的屬性值

Field.get(Object) 獲取該屬性的值。

```java

Field field = concreteClass.getField("publicInt");

System.out.println("屬性的類型:"+field.getType());

ConcreteClass obj= new ConcreteClass(7);

System.out.println("獲取屬性值:" + field.get(obj));

field.set(obj, 77);

System.out.println("獲取屬性值:" + field.get(obj));

```

輸出:

> 屬性的類型:int

獲取屬性值:7

獲取屬性值:77

Field.get()返回的是一個(gè)Object類型,如果是原始類型則返回其包裝類型。如果是final屬性,set() 方法拋出**java.lang.IllegalAccessException**。

####Get/Set private類型的屬性值

java中在類之外是不能訪問private變量的。但是通過反射可以關(guān)閉檢查訪問修飾符的機(jī)制。

```java

Field privateField = concreteClass.getDeclaredField("privateString");

System.out.println(privateField.get(obj));

```

輸出,不能訪問private的屬性:

> java.lang.IllegalAccessException: Class com.byron4j.hightLevel.reflection.ReflectionDemo2 can not access a member of class com.byron4j.hightLevel.reflection.ConcreteClass with modifiers "private"

設(shè)置可訪問機(jī)制Field.setAccessible(true);

```java

Field privateField = concreteClass.getDeclaredField("privateString");

privateField.setAccessible(true);

System.out.println(privateField.get(obj));

privateField.set(obj, "新的私有屬性值[value]");

System.out.println(privateField.get(obj));

```

輸出:

> private string

> 新的私有屬性值[value]

##與方法相關(guān)的反射方法

使用反射技術(shù)可以獲得方法的信息以及調(diào)用執(zhí)行它。我們來學(xué)習(xí)獲得方法、調(diào)用方法并訪問私有方法。

####獲得public方法

我們可以使用 getMethod()方法獲的public class的方法,需要提供方法的名稱、參數(shù)類型。如果class找不到指定的方法,則會(huì)繼續(xù)向上從其父類中查找。

下面我們以一個(gè)獲取HashMap 的put方法的例子來展示如何方法的參數(shù)類型、方法訪問修飾符和返回類型。

```java

/*=========================================

* 方法

* ========================================

*/

Class mapClass = HashMap.class;

Method mapPut = mapClass.getMethod("put", Object.class, Object.class);

//獲取參數(shù)類型

System.out.println(Arrays.toString(mapPut.getParameterTypes()));

//獲取返回類型

System.out.println(mapPut.getReturnType());

//訪問修飾符

System.out.println(Modifier.toString(mapPut.getModifiers()));

```

輸出:

> [class java.lang.Object, class java.lang.Object]

class java.lang.Object

public

####調(diào)用public方法

可以利用Method.invoke() 方法調(diào)用指定的方法。

```java

//調(diào)用方法

Map map = new HashMap();

mapPut.invoke(map, "key", "val");

System.out.println(map);

```

輸出:

> {key=val}

####調(diào)用private方法

我們可以使用getDeclaredMethod()方法獲取私有方法,然后關(guān)閉訪問限制,即可調(diào)用。

```java

/**

* 訪問私有方法

*/

Method method3 = BaseClass.class.getDeclaredMethod("method3", null);

method3.setAccessible(true);

//靜態(tài)方法的調(diào)用對(duì)象可以傳入null

method3.invoke(null, null);

```

輸出:

> Method3

總結(jié)

以上是生活随笔為你收集整理的java cookbook 3_CookBook/Java核心/3-Java反射.md at master · zhgdbut/CookBook · GitHub的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。