JavaSE 反射中getDeclaredFiled,getField,setAccessible之间的关系和用法

1.        首先明确一点,getDeclaredFiled()只能取得本类独有的成员字段,getField()能取得本类独有的成员字段+父类的成员字段 但 这些都只能是public的. 所谓不可取得即是不可见,NoSuchField.

比如现在有两个类:

public class Animal {
    public String name;
    protected double appetite;
    int age;
    private String habitat;

    public Animal() {
    }

    public Animal(String name, double appetite, int age, String habitat) {
        this.name = name;
        this.appetite = appetite;
        this.age = age;
        this.habitat = habitat;
    }
}
public class Person extends Animal{
    public double height;
    protected double weight;
    String hobby;
    private double salary;

    public Person(){}

    public Person(double height, double weight, String hobby, double salary) {
        this.height = height;
        this.weight = weight;
        this.hobby = hobby;
        this.salary = salary;
    }

}

测试的包结构如下:

 先看同一包内的Demo1:

package demo.reflection1;

import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Field;

/**
 * @Author Mr.Lee
 * @create 2021/12/16 16:01
 */
public class Demo1 {
    Person person;
    Class<? extends Person> clazz;


    @Before
    public void prepare(){
        person = new Person(183.5, 140, "游泳", 10000.0);
        clazz = person.getClass();
    }

    @Test
//    getDeclaredField()只能find本类独有的成员字段
    public void test1() throws NoSuchFieldException {
        System.out.println("-------------本类独有的成员字段都能被found:正常-------------");
        Field height = clazz.getDeclaredField("height");
        System.out.println(height);
        Field weight = clazz.getDeclaredField("weight");
        System.out.println(weight);
        Field hobby = clazz.getDeclaredField("hobby");
        System.out.println(hobby);
        Field salary = clazz.getDeclaredField("salary");
        System.out.println(salary);

        System.out.println("-----------父类的任意一个:报错,因为都不能被found----------------");
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);
        Field appetite = clazz.getDeclaredField("appetite");
        System.out.println(appetite);
        Field age = clazz.getDeclaredField("age");
        System.out.println(age);
        Field habitat = clazz.getDeclaredField("habitat");
        System.out.println(habitat);
    }
}

 

 

 

    @Test
//    getField()能find本类独有的成员字段+父类的成员字段 但 这些都只能是public的.
    public void test2() throws NoSuchFieldException {
        System.out.println("------------public的都能被found:正常-----------");
        Field height = clazz.getField("height");
        System.out.println(height);
        Field name = clazz.getField("name");
        System.out.println(name);

        System.out.println("----------非public的任意一个:报错,因为都不能被found-----------");
        Field weight = clazz.getField("weight");
        Field hobby = clazz.getField("hobby");
        Field salary = clazz.getField("salary");

        Field appetite = clazz.getField("appetite");
        Field age = clazz.getField("age");
        Field habitat = clazz.getField("habitat");

    }

 

 

 2.前面getDeclaredField()和getField()区分完了,接着看setAccissible()的作用.

先看同包下的Demo1:

    @Test
//    以getDeclaredField()为例,展示 setAccessible()的访问控制:
//    Demo1和Person同包,正常情况下只能够access public,protected,缺省 成员字段 ; 但通过 字段.setAccessible(true)可以access private成员字段
    public void test3_1() throws NoSuchFieldException, IllegalAccessException {
        System.out.println("---------权限够:正常--------");
        Field height = clazz.getDeclaredField("height");
        System.out.println(height.get(person));
        Field weight = clazz.getDeclaredField("weight");
        System.out.println(weight.get(person));
        Field hobby = clazz.getDeclaredField("hobby");
        System.out.println(hobby.get(person));


        System.out.println("-------权限不够,但setAccessible(true):正常--------");
        Field salary2 = clazz.getDeclaredField("salary");
        salary2.setAccessible(true);
        System.out.println(salary2.get(person));

        System.out.println("--------权限不够:报错,因为IllegalAccess-------");
        Field salary = clazz.getDeclaredField("salary");
        System.out.println(salary.get(person));


    }

 

 Demo2: 不同包且无继承关系,故protected,缺省权限的字段也就不能访问了

package demo.reflection2;

import demo.reflection1.Person;
import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Field;

/**
 * @Author Mr.Lee
 * @create 2021/12/16 16:04
 */
public class Demo2 {
    Person person;
    Class<? extends Person> clazz;


    @Before
    public void prepare(){
        person = new Person(183.5, 140, "游泳", 10000.0);
        clazz = person.getClass();
    }

    @Test
    public void test3_2() throws NoSuchFieldException, IllegalAccessException {
        System.out.println("---------权限够:正常--------");
        Field height = clazz.getDeclaredField("height");
        System.out.println(height.get(person));


        System.out.println("-------权限不够,但setAccessible(true):正常--------");
        Field salary2 = clazz.getDeclaredField("salary");
        salary2.setAccessible(true);
        System.out.println(salary2.get(person));
        Field weight2 = clazz.getDeclaredField("weight");
        weight2.setAccessible(true);
        System.out.println(weight2.get(person));
        Field hobby2 = clazz.getDeclaredField("hobby");
        hobby2.setAccessible(true);
        System.out.println(hobby2.get(person));

        System.out.println("--------权限不够:报错,因为不能access -------");
        Field weight = clazz.getDeclaredField("weight");
        System.out.println(weight.get(person));
        Field hobby = clazz.getDeclaredField("hobby");
        System.out.println(hobby.get(person));
        Field salary = clazz.getDeclaredField("salary");
        System.out.println(salary.get(person));
    }
}
}

 

 3.关于found和access: 最后细心的你们一定发现了1中直接输出 getDecalredField() ,2中却输出的 字getDecalredField().get() .

        2中讨论的权限 access的问题,对于getDecalredField()对所有的能被found的字段都能取得不存在illegalAccess,这样就起不到测试权限的作用.而getDecalredField().get()是取实例对象的字段值,可能存在illegalAccess.(可以理解为getDecalredField()返回的Field对象本身就是public的,而getDecalredField().get()返回的实例对象的成员字段权限取决于他自身)

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值