设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间15 现在时间15 缓存数据 一个人挺好的

一个人挺好的 -- 一个

查看: 1218|回复: 2

简单易懂Java反射的setAccessible()方法

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:203
  • 打卡月天数:0
  • 打卡总奖励:3703
  • 最近打卡:2023-08-27 01:46:11
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
420
主题
388
精华
0
金钱
4924
积分
838
注册时间
2022-12-29
最后登录
2025-5-31

发表于 2023-2-17 11:38:39 | 显示全部楼层 |阅读模式
  1. 前言:在使用Field类的对象访问我自定义的Employee类对象的name域时,抛出异常illegalAccessException。查询原因为:在访问name域时,Java进行了访问检查,发现该域是private修饰的,不能直接访问,因此抛出异常。
复制代码
概要

本文首先详细介绍访问检查的概念,然后介绍关于反射的运行时访问检查,并说明可能存在的问题。最后介绍可以通过setAccessible方法屏蔽或者说禁用运行时访问检查。让我们开始把~~

一、 什么是Java的访问检查

访问检查,就是查看成员属性、成员方法的使用是否符合访问权限(public、protected、default、private)。
有点太理论化了,简单来说,如果一个类的成员(属性或者方法)的访问权限是private,那么该成员只能在当前类中使用;如果一个类的成员的访问权限是public,那么该成员可以在任意类中使用;如果一个类的成员的访问权限是default,那么该成员只能在同一个包下面的类中使用;如果一个类的成员的访问权限是protected,那么该成员可以在同一个包下面的类中和其他包下面的该类的子类中使用。
如果,类的成员的访问权限是default,你却在另一个包中使用了该成员,当编译时,编译器会进行访问检查,发现成员的使用与给定的访问权限不一致,因此会报错。
举个例子,在com.example包下创建People类,有四个成员变量。在com.example.app包下(它是不同于com.example的包)下,使用People类的四个成员变量。
  1. package com.example;

  2. package com.example;

  3. public class People {

  4.     private int privateVar = 1;
  5.             int defaultVar = 2;
  6.     protected int protectedVar = 3;
  7.     public int publicVar = 4;
  8. }


  9. package com.example.app;

  10. import com.example.People;
  11. public class TestMain {
  12.     public static void main(String[] args) {
  13.         People p = new People();
  14.         System.out.println(p.privateVar);
  15.         System.out.println(p.defaultVar);
  16.         System.out.println(p.protectedVar);
  17.         System.out.println(p.publicVar);
  18.     }
  19. }
复制代码
编译后提示,publicVar的使用符合public的访问权限,所以没有出错。
123851cy33yi8nn0fmf5cr.jpeg

相信大家都理解了访问检查是什么,那么,反射对象的访问检查是怎么的呢?
一个类的成员属性、成员方法、构造函数,在反射中分别被抽象为Field、Method、Counstructor类。
我们可以使用Field访问对象的成员属性,成员属性的访问权限,编译器是不知道的,只有运行时才知道。因此对于反射对象(例如Field)访问权限的检查只能交给虚拟机。
如果,虚拟机在运行时,发现成员的使用与给定的访问权限不一致,如下代码
  1. package com.example.app;

  2. import com.example.People;
  3. import java.lang.reflect.Field;
  4. public class TestMain {
  5.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
  6.         People p = new People();
  7.         Class cl = p.getClass();
  8.         
  9.         // 利用反射访问private修饰的成员变量
  10.         Field f = cl.getDeclaredField("privateVar")
  11.         System.out.println(f.get(p));        
  12.     }
  13. }
复制代码
运行时,抛出异常:java.lang.IllegalAccessException
123851sannbad61zbw1a3h.jpeg

综上,访问检查可以时编译器在编译时进行或者虚拟机在运行时进行(主要是针对反射)

二、 setAccessible() 方法介绍

 
  1. setAccessible(boolean flag)
复制代码
方法是AccessibleObject类中的一个方法,它是Field、 Method、Constructor的公共父类。当Field、Method或Constructor (三者都是反射对象)分别用于设置字段(
  1. set(Object obj, Object value)
复制代码
)或获取字段(
  1. get(Object obj)
复制代码
)、调用方法(
  1. invoke(Object obj, Object... args)
复制代码
)或创建和初始化类的新实例(
  1. newInstance(Object... initargs)
复制代码
)时,将执行运行时访问检查
引用自《Java核心技术 第十版》
123851f61eda5glgzt5niv.jpeg

注意:方法名setAccessible很容易让人产生误解,给人的感觉是设置了成员的可访问性,例如,觉得public修饰的成员是任意类都可以访问的,所以可访问标志是true;觉得private修饰的成员只有本类可以访问,所以可访问标志是false。其实不然,不管是什么访问权限,其可访问标志的值都为false。
测试代码如下:
  1. package com.example.app;

  2. import com.example.People;
  3. import java.lang.reflect.Field;
  4. public class TestMain {
  5.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
  6.         People p = new People();
  7.         Class cl = p.getClass();
  8.         // 打印输出所有成员变量的名字及可访问标志
  9.         for (Field f : cl.getDeclaredFields()) {
  10.             System.out.println(f.getName() + ": " + f.isAccessible());
  11.         }
  12.     }
  13. }
复制代码
输入结果:
123852mxn8neosx2gwan21.jpeg

上面中的API说得很清楚,这个可访问标志表示是否屏蔽Java语言的访问检查默认值是false,(上面已经测试)
可以通过
  1. setAccessible(true)
复制代码
修改默认值,如此会屏蔽Java语言的(运行时)访问检查,使得对象的私有成员可以访问,而不报错。
  1. package com.example.app;

  2. import com.example.People;

  3. import java.lang.reflect.Field;

  4. public class TestMain {

  5.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
  6.         People p = new People();
  7.         Class cl = p.getClass();

  8.         for (Field f : cl.getDeclaredFields()) {
  9.             //屏蔽对象的访问检查
  10.             f.setAccessible(true);
  11.             // 访问不符合访问权限的成员属性
  12.             System.out.println(f.getName() + " = " + f.get(p));
  13.         }
  14.     }
  15. }
复制代码
输入结果:
123852rgoo22eaffepfga4.jpeg

到此这篇关于简单易懂Java反射的setAccessible()方法的文章就介绍到这了,更多相关Java反射setAccessible()内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
16
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2023-5-23 21:48:35 | 显示全部楼层
感谢大大分享~~~~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
21
积分
22
注册时间
2022-12-26
最后登录
2022-12-26

发表于 4 天前 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表