簡(jiǎn)單易懂Java反射的setAccessible()方法
前言:在使用Field類(lèi)的對(duì)象訪(fǎng)問(wèn)我自定義的Employee類(lèi)對(duì)象的name域時(shí),拋出異常illegalAccessException。查詢(xún)?cè)驗(yàn)椋涸谠L(fǎng)問(wèn)name域時(shí),Java進(jìn)行了訪(fǎng)問(wèn)檢查,發(fā)現(xiàn)該域是private修飾的,不能直接訪(fǎng)問(wèn),因此拋出異常。
概要
本文首先詳細(xì)介紹訪(fǎng)問(wèn)檢查的概念,然后介紹關(guān)于反射的運(yùn)行時(shí)訪(fǎng)問(wèn)檢查,并說(shuō)明可能存在的問(wèn)題。最后介紹可以通過(guò)setAccessible方法屏蔽或者說(shuō)禁用運(yùn)行時(shí)訪(fǎng)問(wèn)檢查。讓我們開(kāi)始把~~
一、 什么是Java的訪(fǎng)問(wèn)檢查
訪(fǎng)問(wèn)檢查,就是查看成員屬性、成員方法的使用是否符合訪(fǎng)問(wèn)權(quán)限(public、protected、default、private)。
有點(diǎn)太理論化了,簡(jiǎn)單來(lái)說(shuō),如果一個(gè)類(lèi)的成員(屬性或者方法)的訪(fǎng)問(wèn)權(quán)限是private,那么該成員只能在當(dāng)前類(lèi)中使用;如果一個(gè)類(lèi)的成員的訪(fǎng)問(wèn)權(quán)限是public,那么該成員可以在任意類(lèi)中使用;如果一個(gè)類(lèi)的成員的訪(fǎng)問(wèn)權(quán)限是default,那么該成員只能在同一個(gè)包下面的類(lèi)中使用;如果一個(gè)類(lèi)的成員的訪(fǎng)問(wèn)權(quán)限是protected,那么該成員可以在同一個(gè)包下面的類(lèi)中和其他包下面的該類(lèi)的子類(lèi)中使用。
如果,類(lèi)的成員的訪(fǎng)問(wèn)權(quán)限是default,你卻在另一個(gè)包中使用了該成員,當(dāng)編譯時(shí),編譯器會(huì)進(jìn)行訪(fǎng)問(wèn)檢查,發(fā)現(xiàn)成員的使用與給定的訪(fǎng)問(wèn)權(quán)限不一致,因此會(huì)報(bào)錯(cuò)。
舉個(gè)例子,在com.example包下創(chuàng)建People類(lèi),有四個(gè)成員變量。在com.example.app包下(它是不同于com.example的包)下,使用People類(lèi)的四個(gè)成員變量。
package com.example;
package com.example;
public class People {
private int privateVar = 1;
int defaultVar = 2;
protected int protectedVar = 3;
public int publicVar = 4;
}
package com.example.app;
import com.example.People;
public class TestMain {
public static void main(String[] args) {
People p = new People();
System.out.println(p.privateVar);
System.out.println(p.defaultVar);
System.out.println(p.protectedVar);
System.out.println(p.publicVar);
}
}
編譯后提示,publicVar的使用符合public的訪(fǎng)問(wèn)權(quán)限,所以沒(méi)有出錯(cuò)。

相信大家都理解了訪(fǎng)問(wèn)檢查是什么,那么,反射對(duì)象的訪(fǎng)問(wèn)檢查是怎么的呢?
一個(gè)類(lèi)的成員屬性、成員方法、構(gòu)造函數(shù),在反射中分別被抽象為Field、Method、Counstructor類(lèi)。
我們可以使用Field訪(fǎng)問(wèn)對(duì)象的成員屬性,成員屬性的訪(fǎng)問(wèn)權(quán)限,編譯器是不知道的,只有運(yùn)行時(shí)才知道。因此對(duì)于反射對(duì)象(例如Field)訪(fǎng)問(wèn)權(quán)限的檢查只能交給虛擬機(jī)。
如果,虛擬機(jī)在運(yùn)行時(shí),發(fā)現(xiàn)成員的使用與給定的訪(fǎng)問(wèn)權(quán)限不一致,如下代碼
package com.example.app;
import com.example.People;
import java.lang.reflect.Field;
public class TestMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
People p = new People();
Class cl = p.getClass();
// 利用反射訪(fǎng)問(wèn)private修飾的成員變量
Field f = cl.getDeclaredField("privateVar")
System.out.println(f.get(p));
}
}
運(yùn)行時(shí),拋出異常:java.lang.IllegalAccessException

綜上,訪(fǎng)問(wèn)檢查可以時(shí)編譯器在編譯時(shí)進(jìn)行或者虛擬機(jī)在運(yùn)行時(shí)進(jìn)行(主要是針對(duì)反射)
二、 setAccessible() 方法介紹
setAccessible(boolean flag)方法是AccessibleObject類(lèi)中的一個(gè)方法,它是Field、 Method、Constructor的公共父類(lèi)。當(dāng)Field、Method或Constructor (三者都是反射對(duì)象)分別用于設(shè)置字段(set(Object obj, Object value))或獲取字段(get(Object obj))、調(diào)用方法(invoke(Object obj, Object... args))或創(chuàng)建和初始化類(lèi)的新實(shí)例(newInstance(Object... initargs))時(shí),將執(zhí)行運(yùn)行時(shí)訪(fǎng)問(wèn)檢查。
引用自《Java核心技術(shù) 第十版》

注意:方法名setAccessible很容易讓人產(chǎn)生誤解,給人的感覺(jué)是設(shè)置了成員的可訪(fǎng)問(wèn)性,例如,覺(jué)得public修飾的成員是任意類(lèi)都可以訪(fǎng)問(wèn)的,所以可訪(fǎng)問(wèn)標(biāo)志是true;覺(jué)得private修飾的成員只有本類(lèi)可以訪(fǎng)問(wèn),所以可訪(fǎng)問(wèn)標(biāo)志是false。其實(shí)不然,不管是什么訪(fǎng)問(wèn)權(quán)限,其可訪(fǎng)問(wèn)標(biāo)志的值都為false。
測(cè)試代碼如下:
package com.example.app;
import com.example.People;
import java.lang.reflect.Field;
public class TestMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
People p = new People();
Class cl = p.getClass();
// 打印輸出所有成員變量的名字及可訪(fǎng)問(wèn)標(biāo)志
for (Field f : cl.getDeclaredFields()) {
System.out.println(f.getName() + ": " + f.isAccessible());
}
}
}
輸入結(jié)果:

上面中的API說(shuō)得很清楚,這個(gè)可訪(fǎng)問(wèn)標(biāo)志表示是否屏蔽Java語(yǔ)言的訪(fǎng)問(wèn)檢查,默認(rèn)值是false,(上面已經(jīng)測(cè)試)
可以通過(guò)setAccessible(true) 修改默認(rèn)值,如此會(huì)屏蔽Java語(yǔ)言的(運(yùn)行時(shí))訪(fǎng)問(wèn)檢查,使得對(duì)象的私有成員可以訪(fǎng)問(wèn),而不報(bào)錯(cuò)。
package com.example.app;
import com.example.People;
import java.lang.reflect.Field;
public class TestMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
People p = new People();
Class cl = p.getClass();
for (Field f : cl.getDeclaredFields()) {
//屏蔽對(duì)象的訪(fǎng)問(wèn)檢查
f.setAccessible(true);
// 訪(fǎng)問(wèn)不符合訪(fǎng)問(wèn)權(quán)限的成員屬性
System.out.println(f.getName() + " = " + f.get(p));
}
}
}
輸入結(jié)果:

到此這篇關(guān)于簡(jiǎn)單易懂Java反射的setAccessible()方法的文章就介紹到這了,更多相關(guān)Java反射setAccessible()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java根據(jù)方法名稱(chēng)取得反射方法的參數(shù)類(lèi)型示例
- java反射遍歷實(shí)體類(lèi)屬性和類(lèi)型,并賦值和獲取值的簡(jiǎn)單方法
- Java 反射獲取類(lèi)詳細(xì)信息的常用方法總結(jié)
- java 利用反射機(jī)制,獲取實(shí)體所有屬性和方法,并對(duì)屬性賦值
- Java 采用反射獲取class屬性值的實(shí)現(xiàn)代碼
- Java利用反射如何查找使用指定注解的類(lèi)詳解
- Java反射根據(jù)不同方法名動(dòng)態(tài)調(diào)用不同的方法(實(shí)例)
- Java反射機(jī)制的實(shí)現(xiàn)詳解
相關(guān)文章
Java控制臺(tái)實(shí)現(xiàn)猜拳游戲小游戲
這篇文章主要為大家詳細(xì)介紹了Java控制臺(tái)實(shí)現(xiàn)猜拳游戲小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
Java排序之冒泡排序的實(shí)現(xiàn)與優(yōu)化
冒泡排序是一種簡(jiǎn)單的交換排序。之所以叫做冒泡排序,因?yàn)槲覀兛梢园衙總€(gè)元素當(dāng)成一個(gè)小氣泡,根據(jù)氣泡大小,一步一步移動(dòng)到隊(duì)伍的一端,最后形成一定對(duì)的順序。本文將利用Java實(shí)現(xiàn)冒泡排序,并進(jìn)行一定的優(yōu)化,希望對(duì)大家有所幫助2022-11-11
StackTraceElement獲取方法調(diào)用棧信息實(shí)例詳解
這篇文章主要介紹了StackTraceElement獲取方法調(diào)用棧信息實(shí)例詳解,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02
IDEA創(chuàng)建Spring項(xiàng)目無(wú)法選擇Java8的問(wèn)題及解決
文章描述了在使用Spring創(chuàng)建項(xiàng)目時(shí)遇到的問(wèn)題,通過(guò)將服務(wù)器地址從https://start.spring.io/替換為https://start.aliyun.com/,成功解決了無(wú)法選擇Java8的問(wèn)題2025-01-01
Java對(duì)象轉(zhuǎn)json JsonFormat注解
這篇文章主要介紹了Java對(duì)象轉(zhuǎn)json JsonFormat注解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
java 實(shí)現(xiàn)發(fā)短信功能---騰訊云短信
如今發(fā)短信功能已經(jīng)成為互聯(lián)網(wǎng)公司的標(biāo)配,接下來(lái)通過(guò)本文給大家介紹java 實(shí)現(xiàn)發(fā)短信功能---騰訊云短信 ,需要的朋友可以參考下2019-08-08
基于list stream: reduce的使用實(shí)例
這篇文章主要介紹了list stream: reduce的使用實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09

