日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
原來高手是這么回答和使用反射的,又覺得漲了不少知識(shí)

反射是Java語(yǔ)言中非常重要的一個(gè)基礎(chǔ)知識(shí)點(diǎn),它的應(yīng)用往往在于代碼的封裝上和框架的設(shè)計(jì)上,對(duì)于一般的碼農(nóng)和初級(jí)工程師來說,在日常的編碼工作中很少直接使用反射,所以不少Java小伙伴對(duì)反射是既熟悉又陌生。

泰來網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,泰來網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為泰來1000多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營(yíng)銷網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的泰來做網(wǎng)站的公司定做!

熟悉是都聽說過,聽說是一個(gè)很牛掰的技術(shù),是封裝框架,走向架構(gòu)的必修課,陌生在于日常開發(fā)很少直接使用,反正不影響哥們施展CV大法。

如果企業(yè)沒有編程規(guī)范要求和來自領(lǐng)導(dǎo)的review,優(yōu)化程序是不可能的,重構(gòu),向上封裝?想都不要想。如果想要讓自己的編程功力提高,提升自己的架構(gòu)思維,那么在日常編碼過程中,一定要多去思考,我的代碼能否再精簡(jiǎn)?能否再通用?能否變成一個(gè)團(tuán)隊(duì)插件?想要實(shí)現(xiàn)這個(gè)目的,反射就可能派上用場(chǎng)了。

本文會(huì)從以下幾點(diǎn)為小伙伴解密反射,保障看完神清氣爽,直呼哇塞:

  • 反射的概念和相關(guān)API
  • 反射語(yǔ)法,如何獲取和操作反射類,構(gòu)造器,方法,屬性
  • 反射的應(yīng)用場(chǎng)景,從框架和個(gè)人項(xiàng)目經(jīng)驗(yàn)分享
  • 面試中高手都怎么回答反射的優(yōu)缺點(diǎn)拿到高薪

什么是反射

Reflection(反射)是Java程序開發(fā)語(yǔ)言的重要特性之一,通過反射機(jī)制允許在程序運(yùn)行期間,可以根據(jù)任意一個(gè).class【字節(jié)碼文件】文件獲取到這個(gè)類的所有信息,包括(成員變量,成員方法,構(gòu)造器等),并可以通過相應(yīng)的方式操縱類的字段、方法、構(gòu)造器

基于反射機(jī)制,Java實(shí)現(xiàn)在程序運(yùn)行期間,動(dòng)態(tài)獲取信息和動(dòng)態(tài)調(diào)用對(duì)象的方法,提高了程序的擴(kuò)展性

使用反射的前提是必須有字節(jié)碼文件,也就是.class文件,.class文件就是通過.java文件編譯而來的。Java作為面向?qū)ο蟮木幊陶Z(yǔ)言,提供了為反射準(zhǔn)備的字節(jié)碼文件對(duì)象java.lang.Class

反射相關(guān)API

反射機(jī)制相關(guān)的包都在

java.lang.reflect.*;

一些反射中的常用類:

作用

java.lang.Class

代表整個(gè)字節(jié)碼。代表一個(gè)類型,代表整個(gè)類

java.lang.reflect.Method

代表字節(jié)碼中的方法字節(jié)碼。代表類中的方法

java.lang.reflect.Constructor

代表字節(jié)碼中的構(gòu)造方法字節(jié)碼。代表類中的構(gòu)造方法

java.lang.reflect.Field

代表字節(jié)碼中的屬性字節(jié)碼。代表類中的成員變量(靜態(tài)變量+實(shí)例變量)

還可以通過字節(jié)碼對(duì)象【Class對(duì)象】獲取注解以下信息,這些信息不在java.lang.reflect包中,所以單獨(dú)列出來

作用

java.lang.annotation.Annotation

可以獲取類,字段,方法等地方的注解

java.lang.Package

獲取所在包

java.lang.ClassLoader

獲取類加載器

反射語(yǔ)法應(yīng)用

反射是將運(yùn)行中的class文件讀取到并封裝進(jìn)反射類【Class】中,并且可以根據(jù)反射類獲取類中的構(gòu)造方法,普通方法和屬性,接下來根據(jù)案例依次演示

獲取反射類

咱們寫的代碼是存儲(chǔ)在后綴名是 .java的文件里的,但是它會(huì)被編譯,最終真正去執(zhí)行的是編譯后的 .class文件。Java是面向?qū)ο蟮恼Z(yǔ)言,一切皆對(duì)象,所以java認(rèn)為這些編譯后的 class文件也是一種對(duì)象,給抽象成了一種類,這個(gè)類就是Class,獲取反射類有三種方式:

  • 通過Object類的 getClass方法來獲取,所有的類都直接或者間接繼承Object類,所有的對(duì)象都可以使用該方法
  • 使用 類名.class 的方式
  • 使用Class.forName方法

需求:有以下Student類,我們通過三種方式獲取該類的Class對(duì)象,并根據(jù)Class對(duì)象的getName方法,輸出類的全路徑

student類:

package com.stt.reflect;

public class Student {
private Long id;
private String name;
private String sex;
private Integer age;
}

獲取反射類:

public class StudentMain {
public static void main(String[] args) {
// 1、通過 getClass 方法獲取 Class類,
// 1) 創(chuàng)建Student類對(duì)象
Student student = new Student();
// 2) 所有的類都直接或者間接繼承Object類,每個(gè)對(duì)象都有g(shù)etClass方法
Class studentClazz1 = student.getClass();
System.out.println("studentClazz1===>" + studentClazz1.getName());
// 2、通過.class獲取
Class studentClazz2 = Student.class;
System.out.println("studentClazz2===>" + studentClazz2.getName());
// 3、通過Class類的forName方法獲取,傳入類的全路徑
try {
// 此方法拋出 ClassNotFoundException 異常,因?yàn)樘顚懙念惾窂娇赡苠e(cuò)誤,該類可能不存在
Class studentClazz3 = Class.forName("com.stt.reflect.Student");
System.out.println("studentClazz3===>" + studentClazz3.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}

輸出結(jié)果:

反射獲取構(gòu)造方法

方法

作用

Constructor getConstructor(Class... parameterTypes)

根據(jù)參數(shù)列表,獲取指定數(shù)據(jù)類型的構(gòu)造方法,拋出 NoSuchMethodException, SecurityException

Constructor[] getConstructors()

獲取所有的構(gòu)造方法,拋出 SecurityException

改造Student類,增加四個(gè)構(gòu)造方法,默認(rèn)有一個(gè)無參的構(gòu)造方法

package com.stt.reflect;

public class Student {
private Long id;
private String name;
private String sex;
private Integer age;

// 無參構(gòu)造
public Student() {
System.out.println("=======無參構(gòu)造方法=======");
}

// 單參構(gòu)造
public Student(String name) {
this.name = name;
System.out.println("=======單參構(gòu)造方法=======name:" + name);
}

// 兩參構(gòu)造
public Student(Long id, String name) {
this.id = id;
this.name = name;
System.out.println("========兩參構(gòu)造方法=======id:" + id + ", name: " + name);
}

// 三參構(gòu)造
public Student(Long id, String name, String sex) {
this.id = id;
this.name = name;
this.sex = sex;
System.out.println("========三參構(gòu)造方法=======id:" + id + ", name: " + name + ", sex: " +sex);
}

// 四參構(gòu)造
public Student(Long id, String name, String sex, Integer age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
System.out.println("========三參構(gòu)造方法=======id:" + id + ", name: " + name + ", sex: " + sex + ", age: " +age);
}
}

獲取指定參數(shù)構(gòu)造方法

  • 根據(jù)getConstructor()方法獲取構(gòu)造方法
  • 通過 Constructor 類的 newInstance()方法可以調(diào)用對(duì)應(yīng)的構(gòu)造方法創(chuàng)建對(duì)象
package com.stt.reflect;

import java.lang.reflect.Constructor;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取無參的構(gòu)造方法
Constructor noParamConstructor = clazz.getConstructor();
// 通過Constructor創(chuàng)建對(duì)象
Student student1 = noParamConstructor.newInstance();
// 3、獲取單燦構(gòu)造方法,單參是String類型的name,所以參數(shù)寫為String.class
Constructor oneStringParamConstructor = clazz.getConstructor(String.class);
Student student2 = oneStringParamConstructor.newInstance("添甄");
// 4、獲取兩參構(gòu)造方法,類型分別為L(zhǎng)ong和String
Constructor twoStringParamConstructor = clazz.getConstructor(Long.class,String.class);
Student student3 = twoStringParamConstructor.newInstance(1L,"添甄");
}
}

運(yùn)行結(jié)果:

獲取所有構(gòu)造方法

將無參的構(gòu)造方法設(shè)置為私有

private Student() {
System.out.println("=======無參構(gòu)造方法=======");
}

獲取所有構(gòu)造方法:

package com.stt.reflect;

import java.lang.reflect.Constructor;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取所有構(gòu)造方法
Constructor[] constructors = clazz.getConstructors();

// 3、遍歷構(gòu)造方法
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}

輸出結(jié)果:

可以獲取所有的公開構(gòu)造方法,私有構(gòu)造獲取不到

獲取私有構(gòu)造

小貼士:通過反射獲取私有的構(gòu)造函數(shù)時(shí),用普通的getConstructor()會(huì)報(bào)錯(cuò),因?yàn)樗撬接械?,所以提供了專門反射私有構(gòu)造函數(shù)的方法 getDeclaredConstructor(int.class);

如果要調(diào)用這個(gè)方法還需要設(shè)置一下暴力反射才可以,即調(diào)用構(gòu)造器對(duì)象的setAccessible(true);方法

獲取所有私有方法:

package com.stt.reflect;

import java.lang.reflect.Constructor;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取所有構(gòu)造方法,包括私有
Constructor[] constructors = clazz.getDeclaredConstructors();
// 3、遍歷構(gòu)造方法
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}

運(yùn)行結(jié)果:

獲取私有構(gòu)造方法并調(diào)用

僅僅獲取到調(diào)用會(huì)出現(xiàn) IllegalAccessException 異常

package com.stt.reflect;

import java.lang.reflect.Constructor;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取無參的構(gòu)造方法,包括私有
Constructor constructor = clazz.getDeclaredConstructor();
// 3、此時(shí)直接調(diào)用會(huì)報(bào)錯(cuò)
Student student = constructor.newInstance();

}
}

報(bào)錯(cuò):

設(shè)置暴力破解即可訪問:也就是調(diào)用一下 setAccessible(true)方法

package com.stt.reflect;

import java.lang.reflect.Constructor;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取無參的構(gòu)造方法,包括私有
Constructor constructor = clazz.getDeclaredConstructor();
// 3、暴力破解,允許調(diào)用私有方法
constructor.setAccessible(true);
// 4、此時(shí)直接調(diào)用會(huì)報(bào)錯(cuò)
Student student = constructor.newInstance();

}
}

運(yùn)行結(jié)果:

反射獲取方法

在Student類中添加以下普通方法

package com.stt.reflect;

public class Student {
// ......

public void speak() {
System.out.println("你好??!" + name);
}

public Integer getAge() {
System.out.println("getAge===》" + this.age);
return this.age;
}

public void setName(String name) {
this.name = name;
System.out.println("設(shè)置名字為:" + name);
}

public static void skill() {
System.out.println("======skill靜態(tài)方法======");
}

private void method1() {
System.out.println("======私有方法======");
}

private static void method2(String[] args) {
System.out.println("======私有靜態(tài)方法======" + args);
}
}

獲取所有非私有方法

獲取方法,通過 Method 類型對(duì)象封裝

package com.stt.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取所有非私有方法,包括父類中方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}

如下圖:獲取到了所有的非私有方法,包括父類中的方法

獲取所有方法

通過調(diào)用getDeclaredMethods方法獲取所有方法,

package com.stt.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、獲取所有非私有方法,包括父類中方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}

如下,獲取了包括私有方法,但是不包括父類中的方法

獲取指定方法并調(diào)用

我們可以通過 getMethod(String name, Class... parameterTypes) 方法,根據(jù)方法名和參數(shù)獲取方法,在通過Method對(duì)象的 invoke(Object obj, Object... args)方法調(diào)用方法,如果是私有方法,你懂的,需要暴力破解一下再調(diào)用,和構(gòu)造器一樣

  • 調(diào)用四個(gè)參數(shù)構(gòu)造方法創(chuàng)建student對(duì)象
  • 分別調(diào)用speak,getAge和setName方法,分別對(duì)應(yīng)無返回值和有返回值和有參數(shù)等情況
package com.stt.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");

// 2、獲取無參的 speak 方法
Method speakMethod = clazz.getMethod("speak");
// 3、創(chuàng)建Student對(duì)象
Constructor constructor = clazz.getConstructor(Long.class,String.class,String.class,Integer.class);
Student student = constructor.newInstance(1L,"添甄","男",26);
// 傳入 student,意為要調(diào)用student對(duì)象的speak
Object returnResult = speakMethod.invoke(student);
System.out.println("方法返回值==》" + returnResult);

// 4、調(diào)用getAge方法,沒有參數(shù)有返回值
Method ageMethod = clazz.getMethod("getAge");
Integer returnAge = (Integer)ageMethod.invoke(student);
System.out.println(returnAge);

// 5、調(diào)用有參數(shù)的方法,getMethod參數(shù)2寫為參數(shù)的類型
Method setNameMethod = clazz.getMethod("setName",String.class);
setNameMethod.invoke(student, "王小波");

}
}

調(diào)用私有方法

方式和調(diào)用私有構(gòu)造器一致,首先通過 getDeclaredMethod 獲取私有方法,其次調(diào)用 setAccessible(true) 設(shè)置可訪問為true

package com.stt.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、創(chuàng)建Student對(duì)象
Constructor constructor = clazz.getConstructor(Long.class,String.class,String.class,Integer.class);
Student student = constructor.newInstance(1L,"添甄","男",26);
// 3、通過 getDeclaredMethod 獲取私有方法 private void method1()

Method method1 = clazz.getDeclaredMethod("method1");
// 設(shè)置為可訪問 true
method1.setAccessible(true);
// 調(diào)用方法
Object invoke = method1.invoke(student);
}
}

參數(shù)為數(shù)組

參數(shù)維數(shù)組有點(diǎn)特殊,這是因?yàn)?jdk1.4和jdk1.5處理invoke方法有區(qū)別

1.5:public Object invoke(Object obj,Object…args):1.5參數(shù)為Object類型的可變參數(shù)

1.4:public Object invoke(Object obj,Object[] args):1.4參數(shù)為一個(gè)Object類型數(shù)組

在反射方法時(shí),如果方法的參數(shù)是一個(gè)數(shù)組,考慮到向下兼容問題,會(huì)按照J(rèn)DK1.4的語(yǔ)法來對(duì)待(JVM會(huì)把傳遞的數(shù)組參數(shù)拆開,拆開就會(huì)報(bào)參數(shù)的個(gè)數(shù)不匹配的錯(cuò)誤) 解決辦法:防止JVM拆開你的數(shù)組 方式一:把數(shù)組看做是一個(gè)Object對(duì)象 方式二:重新構(gòu)建一個(gè)Object數(shù)組,那個(gè)參數(shù)數(shù)組作為唯一的元素存在。

package com.stt.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、創(chuàng)建Student對(duì)象
Constructor constructor = clazz.getConstructor(Long.class,String.class,String.class,Integer.class);
Student student = constructor.newInstance(1L,"添甄","男",26);
// 3、通過 getDeclaredMethod 獲取私有方法 private void method1()

Method method1 = clazz.getDeclaredMethod("method2",String[].class);
// 設(shè)置為可訪問 true
method1.setAccessible(true);
// 調(diào)用方式1:將數(shù)組強(qiáng)轉(zhuǎn)為Object對(duì)象
method1.invoke(student,(Object)new String[]{"a","b"});

// 調(diào)用方式2:將數(shù)組存儲(chǔ)進(jìn)Object數(shù)組中
method1.invoke(student,new Object[]{new String[]{"a","b"}});
}
}

錯(cuò)誤調(diào)用:如果直接傳進(jìn)數(shù)組,則會(huì)出現(xiàn)IllegalArgumentException【非法參數(shù)異?!繄?bào)錯(cuò)

Method method1 = clazz.getDeclaredMethod("method2",String[].class);
// 設(shè)置為可訪問 true
method1.setAccessible(true);
// 錯(cuò)誤調(diào)用:直接傳遞數(shù)組
method1.invoke(student,new String[]{"a","b"});

反射獲取屬性

設(shè)置name屬性為public

private Long id;
public String name;
private String sex;
private Integer age;

相關(guān)方法:

方法

作用

Field getField(String name)

獲取指定非私有屬性

Field[] getFields()

獲取所有非私有屬性

Field getDeclaredField(String name)

獲取指定私有屬性

Field[] getDeclaredFields()

獲取所有私有屬性

獲取屬性并通過get方法獲取屬性值

package com.stt.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class StudentMain {
public static void main(String[] args) throws Exception {
// 1、獲取Class類,這里將異常向上拋出
Class clazz = Class.forName("com.stt.reflect.Student");
// 2、創(chuàng)建Student對(duì)象
Constructor constructor = clazz.getConstructor(Long.class,String.class,String.class,Integer.class);
Student student = constructor.newInstance(1L,"添甄","男",26);

// 3、獲取name屬性
Field nameField = clazz.getField("name");
// 4、獲取所有費(fèi)私有屬性
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println("field name====》" + field.getName());
System.out.println("字段值==》" + field.get(student));
}

// 5、獲取指定私有屬性
Field sexField = clazz.getDeclaredField("sex");
sexField.setAccessible(true);
System.out.println(sexField.get(student));
}
}

運(yùn)行結(jié)果:

總結(jié)

  • 要使用反射首先通過上述三種方式獲取Class對(duì)象,該對(duì)象有泛型
  • 可以根據(jù)相關(guān)get方法獲取非私有的構(gòu)造方法,普通方法和屬性
  • 可以根據(jù) 相關(guān)getDeclaredXXX系列方法,獲取私有的構(gòu)造方法,普通方法和屬性,如果是私有需要調(diào)用對(duì)應(yīng)的 setAccessible(true)允許暴力訪問進(jìn)行操作
  • 調(diào)用方法和屬性時(shí),需要指定一個(gè)對(duì)象,即調(diào)用該對(duì)象的指定方法
  • Class、Constructor、Method和Field的方法其實(shí)都比較簡(jiǎn)單,可以自己動(dòng)手調(diào)用一下,印象會(huì)更深刻
  • 我們還可以根據(jù)獲取Class、Method、Field、Constructor獲取對(duì)應(yīng)的注解,即 Annotation對(duì)象
  • 而且私有的方法和屬性都可以被強(qiáng)制調(diào)用,反射破壞了封裝性,帶來一些安全隱患

反射應(yīng)用場(chǎng)景

Tomcat加載文件

使用Servlet編寫web應(yīng)用時(shí),往往都有一個(gè)web.xml文件,

 

my3
com.servlet.MyServlet3


my3

當(dāng)前標(biāo)題:原來高手是這么回答和使用反射的,又覺得漲了不少知識(shí)
文章源于:http://www.5511xx.com/article/ccddhjj.html