Java反射获取private属性和方法(子类,父类,祖先....)

Java反射获取private属性和方法(子类,父类,祖先….)

先来看一个例子:String可变还是不可变?

大家都应该知道,或者听过,String类是不可变的,为什么呢?因为String其实使用一个 
private final char [] value;来保存字符的;final,private,明显就不让你改了啊。但是,大家请看:

        String a="abc";
        Field valueFieldString=String.class.getDeclaredField("value");
        valueFieldString.setAccessible(true);
        char[]value=(char[])valueFieldString.get(a);
        value[2]='@';
        String b="abc";
        //a.intern();
        System.out.println(a);
        System.out.println(b);
        System.out.println(a==b);
        System.out.println("abc"==b);
        System.out.println("ab@"==a);
        System.out.println(a.equals("ab@"));
        System.out.println(a.equals("abc"));
        System.out.println("abc".equals("ab@"));
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

输出(猜猜看,和你想的一不一样呢?):

ab@
ab@
true
true
false//(如果把intern那个注释去掉的话,就是true)
true
true
true
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果,你都答对了,恭喜你,那请直接跳到 反射用法.

否则:请看下面分析

先摘一段官方intern()的注释:

* Returns a canonical representation for the string object. 
* <p> 
* A pool of strings, initially empty, is maintained privately by the 
* class {@code String}. 
* <p> 
* When the intern method is invoked, if the pool already contains a 
* string equal to this {@code String} object as determined by 
* the {@link #equals(Object)} method, then the string from the pool is 
* returned. Otherwise, this {@code String} object is added to the 
* pool and a reference to this {@code String} object is returned. 

3个点: 
* 1.常量池(JVM中就是方法区)是由 String 这个class来私有的管理的。* 
* 2.调用intern()时,会查看常量池是否存在这个String对象,这是通过equals()方法来判断的。* 
* 3.如果存在,则返回常量池中那个String对象,否则,加入到常量池,并返回当前对象。*

ps : equals()方法,首先是看obj1==obj2,也就是引用地址是否相等,如果等则返回true,然后是逐个字符比较。

ok,有了以上知识。其实到这里你自己也可以分析出来了。

我们来分析一下 
首先,String a="abc"; 这句话在内存(常量池)中放入了一个String对象:“abc”(内存地址假设为0x123,由char [] value = [‘a’,’b’,’c’]保存), 
然后第2~5行,我们先不管语法,只要知道是把“abc”这个字符串的第三个字符’c’替换为’@’, 
此时char [] value = [‘a’,’b’,’c’] 变为了char [] value = [‘a’,’b’,’@’],String这个class对象管理的还是“abc”这个对象。 
接下来 String b="abc",这句话会从常量池中寻找“abc”,此时会发现常量池中“abc”是存在的,于是,b就指向了“abc”,b其实就是“abc”的位置的一个引用,a也是一个“abc”位置的引用。 
那么接下来就是顺理成章了:

        System.out.println(a);//a指向"abc"这个对象,而这个对象,内部存储却是{'a','b','@'}
        System.out.println(b);//同上
        System.out.println(a==b);//都指向0x123
        System.out.println("abc"==b);//都是0x123
        System.out.println("ab@"==a);//"ab@"这个对象在常量池中没有,会先在常量中生成,地址显然不是0x123,所以输出false,但是,当调用了a.intern()后,会调用String的equals()去常量池中新建一个对象"ab@',并返回这个位置。
        System.out.println(a.equals("ab@"));
        System.out.println(a.equals("abc"));
        System.out.println("abc".equals("ab@"));
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果仔细想想,其实还是有疑问,在这里就不展开了,不然偏题了,因为我对底层也不懂,intern是c++实现的,具体看这篇:

http://www.wtoutiao.com/a/1023451.html

反射

反射,RTTI,Class对象,这些就不说了,看一段代码:

static void getClassFieldAndMethod(Class cur_class) {
    String class_name = cur_class.getName();
    Field[] obj_fields = cur_class.getDeclaredFields();
    for (Field field : obj_fields) {
        field.setAccessible(true);
        System.out.println(class_name + ":" + field.getName());
    }
    Method[] methods = cur_class.getDeclaredMethods();
    for (Method method : methods) {
        method.setAccessible(true);
        System.out.println(class_name + ":" + method.getName());
    }
    if (cur_class.getSuperclass() != null) {
        getClassFieldAndMethod(cur_class.getSuperclass());
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这段代码输入是一个Class的对象,递归输出这个类的父类,祖父类直到Object类的所有方法和域。

再看一段:

    static void getObjField(Object obj) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{

        Class cur_class = obj.getClass();
        getClassFieldAndMethod(cur_class);
        Field vfield=cur_class.getDeclaredField("value");
        vfield.setAccessible(true);
        char[]value=(char[])vfield.get(obj);
        System.out.println(Arrays.toString(value));
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

ok,这段代码输入任意一个对象,调用上面那段代码的方法getClassFieldAndMethod(),这样你就知道这个对象都有些什么域,什么方法了,再通过域的名称,就可以获取当前这个对象的域的值,进而可以修改了!!

是不是很简单,从此以后谁都不能限制你在Java程序里面为所欲为了!

要通过Java反射获取父类子类的所有属性,我们可以使用Class类的getFields()和getDeclaredFields()方法。 - getFields()方法可以获取类中所有公共的(即用public修饰的)属性,包括父类中的公共属性。返回的是一个数组,其中包含了所有公共属性的Field对象。 - getDeclaredFields()方法可以获取类中所有声明的属性,包括私有的、受保护的和默认访问权限的属性,但不包括父类中的属性。返回的也是一个数组,其中包含了所有声明的属性的Field对象。 我们可以先获取子类的Class对象,然后利用getFields()和getDeclaredFields()方法获取子类自己声明的属性和从父类继承的公共属性。 再获取父类的Class对象,利用getFields()方法获取父类的公共属性。 下面是一个示例代码: ```java import java.lang.reflect.Field; public class ReflectionExample { public static void main(String[] args) { Child child = new Child(); // 获取子类Class对象 Class<?> childClass = child.getClass(); // 获取子类自己声明的属性和从父类继承的公共属性 Field[] childFields = childClass.getDeclaredFields(); for (Field field : childFields) { System.out.println(field.getName()); } // 获取父类Class对象 Class<?> parentClass = childClass.getSuperclass(); // 获取父类的公共属性 Field[] parentFields = parentClass.getFields(); for (Field field : parentFields) { System.out.println(field.getName()); } } } class Parent { public int parentField; } class Child extends Parent { private String childField; } ``` 在上面的示例中,我们创建了一个Parent类和一个Child类。Child类继承自Parent类,并在自己中声明了一个private的childField属性。 运行示例代码,结果会打印出子类父类的所有属性名: ``` childField parentField ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值