• Java反射学习总结二(用反射调用对象的私有属性和方法)


    大家都知道正常的调用是不可以访问对象的private修饰的属性和方法的,这也是Java的封装性原则。

    但是有没有方法可以强制去访问对象的private修饰的属性和方法呢?那就是用反射!(这个可能在面试题中被问到哦)

    接下来就来看看是如何实现的:

    我们先去jdk里看一下描述属性的类Field,和方法的类Method:

    java.lang.reflect

    Class Field

    java.lang.reflect

    Class Method


    可以看到这两个类有个共通的特点,就是他们都继承自java.lang.reflect.AccessibleObject这个类,我们好好看看这个类的描述

    java.lang.reflect

    Class AccessibleObject

    • All Implemented Interfaces:
      AnnotatedElement
      Direct Known Subclasses:
      ConstructorFieldMethod


      public class AccessibleObject
      extends Object
      implements AnnotatedElement
      The AccessibleObject class is the base class for Field, Method and Constructor objects. It provides the ability to flag a reflected object as suppressing default Java language access control checks when it is used. The access checks--for public, default (package) access, protected, and private members--are performed when Fields, Methods or Constructors are used to set or get fields, to invoke methods, or to create and initialize new instances of classes, respectively.

    大致意思就是:

    这个AccessibleObject类是Field, Method and Constructor对象的一个父类,他可以让一个反射对象去禁止Java语言的访问控制检测。控制检测有public, default (package) access, protected, and private。。。blah blah blah。。。

    这里我贴出控制访问控制检测的这个方法:(这个类里还有一些相关的方法,有兴趣的大家可以自己去看看)

    setAccessible

    public void setAccessible(boolean flag)
                       throws SecurityException
    Set the accessible flag for this object to the indicated boolean value. A value of true indicates that the reflected object should suppress Java language access checking when it is used. A value of falseindicates that the reflected object should enforce Java language access checks.

    大致意思:

    设置标志去指示对象的boolean值,如果是true则禁止java访问控制检查,如果是false则强制反射对象使用java访问控制检查


    知道了这个方法就可以做一个小例子测试一下啦。

    下面这个例子很简单,就是定义一个dog类,里面有个private的属性dogName,和private的方法say。

    main函数里用反射先去修改dogName,然后在调用say方法打印出来:

    1. public class Test2 {  
    2.   
    3.     public static void main(String[] args) throws Exception {  
    4.         //获得Dog类的Class对象  
    5.         Class<?> classType = Class.forName("Dog");  
    6.         //生成对象的实例  
    7.         Object obj = classType.newInstance();  
    8.           
    9.         //取得dogName属性  
    10.         Field dogName = classType.getDeclaredField("dogName");  
    11.         //禁止Field的访问控制检查  
    12.         dogName.setAccessible(true);  
    13.         //将Field的值设为“Xiao Qiang”  
    14.         dogName.set(obj, "Xiao Qiang");  
    15.           
    16.         //取得say()方法  
    17.         Method say = classType.getDeclaredMethod("say", new Class[]{});  
    18.         //禁止say方法的访问控制检查  
    19.         say.setAccessible(true);  
    20.         //调用say方法  
    21.         say.invoke(obj, new Object[]{});  
    22.     }  
    23.   
    24. }  
    25.   
    26.  class Dog {  
    27.     //私有的属性  
    28.     private String dogName = "Wang Cai";  
    29.     //私有的方法  
    30.     private void say() {  
    31.         System.out.println(dogName + ": Wang Wang");  
    32.     }  
    33. }  

    输出结果:Xiao Qiang: Wang Wang

    这里需要特别注意一个地方:

    如果想用反射修改访问控制检查的话,获取Method和Field对象的时候一定要用getDeclaredField和getDeclaredMethod。不要用getField和getMethod。

    虽然这两个方法的参数都是相同的,但不同点在于getMethod和getField只能获得public修饰的属性和方法。而getDeclared可以获取任何类型的属性和方法,因为这个例子要调用私有的属性和方法,所以要用getDeclaredXX。

  • 相关阅读:
    注释神器
    Q币直充-迅银渠道商(php 面向对象类)
    rsync 同步多台服务器项目目录
    wdcp 打开网页显示 Apache 2 Test Page powered by CentOS -- 来自辉哥博客
    elasticsearch批量修改,批量更新某个字段
    Ik分词器没有使用---------elasticsearch-analysis-ik 5.6.3分词问题
    spring-boot-starter-data-elasticsearch 整合elasticsearch 5.x详解
    FastJson--SerializerFeature.PrettyFormat 如何实现格式化源码查看
    由Premature end of Content-Length delimited message body因发的问题排查
    JVM的YoungGC日志查看
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6397401.html
Copyright © 2020-2023  润新知