• java


    class描述了一类事物(对象)

    反射则是用来描述class

    可以理解为class进行操作

    System.out.print下面的注解一般是输出结果

    package reflect;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    
    public class ReflectTest {
        public static void main(String[] args){
    
            try {
                System.out.println("-------------------------------------获取类--------------------------------------------------");
                //直接获取一种class:
                //方法一:包名.类名: package.class
                Class clazz1 = Class.forName("reflect.TestClass");
                //方法二:直接通过类
                Class clazz2 = TestClass.class;
                //方法三:通过对象
                TestClass tc1 = new TestClass();
                Class clazz3 = tc1.getClass();
    
                System.out.println("-------------------------------------获取类的修饰符--------------------------------------------------");
                //获取class的修饰符  //这个获取很容易不过很难看懂,所以写个方法modifierHelper用来解析
                int modify = clazz1.getModifiers();
                System.out.println(modify);
                System.out.println(modifierHelper(modify));
                //1
                //public
                modify = Runnable.class.getModifiers(); //换个java自带接口:Runnable
                System.out.println(modifierHelper(modify));
                //abstract interface public
                modify = String.class.getModifiers(); //java自带类:String
                System.out.println(modifierHelper(modify));
                //final public
    
                System.out.println("-------------------------------------获取类的包--------------------------------------------------");
                //获取类的名字
                String className1 = clazz1.getName();//获得全名:  包名+类名
                System.out.println(className1);
                //reflect.TestClass
                String className2 = clazz1.getSimpleName();//获得类名:  类名
                System.out.println(className2);
                //TestClass
    
                //获取类所属的包
                Package p = clazz1.getPackage(); //获取包
                System.out.println(p.getName()); //获取名字
                //reflect
    
                System.out.println("-------------------------------------获取类的父类--------------------------------------------------");
                //获取父类
                Class parent = clazz1.getSuperclass();//虽然我这个测试类没有用extends,但是所有类默认继承Object
                System.out.println(parent.getName());
                //java.lang.Object
                parent = ArrayList.class.getSuperclass();//试试ArrayList
                System.out.println(parent.getName());
                //java.util.AbstractList
                System.out.println(ArrayList.class.getSuperclass().getSuperclass());
                //class java.util.AbstractCollection 还可以找到父类的父类
    
                System.out.println("-------------------------------------获取类接口--------------------------------------------------");
                //获取接口,因为一个类可以有多个接口,所以可以返回多个类,用数组返回
                Class[] cArray = ArrayList.class.getInterfaces();
                for(Class c: cArray){
                    System.out.println(c.getName());
                }
                //java.util.List
                //java.util.RandomAccess
                //java.lang.Cloneable
                //java.io.Serializable
    
                //ArrayList的源代码:public class ArrayList<E> extends AbstractList<E>
                //        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    
    
                System.out.println("-------------------------------------获取类的属性--------------------------------------------------");
                //获取class中的属性
                Field f1 = clazz1.getField("age"); //参数为属性名字
                //但是不能取到testName,因为那个是private的    (这也是为什么说为了安全属性最好设为private的原因之一。)
    
                Class fType = f1.getType();//返回属性的数据类型Class
                System.out.println(fType.getName());
                //int       因为是基本类型所以没有包名一类的。
    
                String s =f1.getName();//返回属性的名字
                System.out.println(s);
                //age
    
                //返回所有的属性
                Field[] fArr1 = clazz1.getFields();
                for(Field f: fArr1){
                    System.out.println(f.getType() + " " + f.getName());
                }
                //int age
                //不能返回私有的
    
                Field[] fArr2 = clazz1.getDeclaredFields();
                for(Field f: fArr2){
                    System.out.println(f.getType() + " " + f.getName());
                }
                //class java.lang.String testName
                //int age
                //返回了私有的属性!
    
    
                System.out.println("-------------------------------------操作类的属性--------------------------------------------------");
                //属性.赋值(对象,值)
                //用映射方法声明一个对象
                TestClass tc2 = (TestClass)clazz1.getDeclaredConstructor().newInstance();
                //之前是直接clazz1.newInstance(),现在过时了,不过也可以用.
                // clazz1.newInstance()其实就是默认调用了无参数构造方法,如果没有无参数的构造方法会报错。
                //clazz1.getDeclaredConstructor().newInstance();就算没有定义无参数构造方法也不会报错。
    
                System.out.println(tc2.show());
                //nname = null|age = 0   没有定义声明对象属性的值,所以自动赋给了一个默认值
    
                Field f2 = clazz1.getField("age"); //把TestClass的属性赋给了f2
                f2.set(tc2,222);//f2操作的是TestClass的age属性,这里给对象tcTest的age属性赋值222.  属性.set(对象,值);   平时我们都是: 对象.属性 = 值
                //这种方法不能给private或者final类型的赋值。
                System.out.println(tc2.show());
                //name = null|age = 222   赋值成功
    
                Field f3 = clazz1.getDeclaredField("testName");
                f3.setAccessible(true); //f3是private的,默认不可外部直接操作,用映射存值和取值都不行 ,所以先把f3设为可以操作的
                f3.set(tc2,"bbb"); //给f3赋值
                System.out.println(tc2.show());
                //name = bbb|age = 222   赋值成功
    
                String nameValue = (String)f3.get(tc2);   //属性.get(Object);  用来取对象的属性值,返回的是object对象,需要强转
                System.out.println(nameValue);
                //bbb     赋值成功
    
                //这里就可以看出映射的作用了,可以让你直接从外部操作私有变量。
    
                //比较:
                //getDeclaredField
                //可以获取当前类公有的和私有的属性
                //getField
                //可以获取当前类的公有属性(包括继承过来的属性)
    
    
                System.out.println("-------------------------------------搞事开始,修改String的值--------------------------------------------------");
                //学会了映射以后可以开始搞事
                //String 的内部结构是private final byte[] value;数组,所以是不能改变长度和值的,因此每次给String赋值其实是默认new了一个String
                //其实就是char[]数组,char和byte可以直接转换,所以下面为了直观直接用char[]操作。
                //因此学校里学的时候String具有不可变性。不过实际上用反射机制是可以变的
                String str1 = "aaa";
                String str2 = str1;  //引用变量赋值赋的是地址
                System.out.println(str1 == str2);
                //true
                str1 = "bbb";
                System.out.println(str1);
                System.out.println(str1);
                System.out.println(str1 == str2);
                //false
                // == 比较的是地址,str1改变了值后地址发生了改变
    
                //如果我们修改完String后,地址str1 == str2仍然为true,则说明地址没变,只是内容变了。
                //声明2个对象
                String str3 = "aaa";
                String str4 = str3;
                System.out.println(str3 == str4);
                //true
                //获取String 的 class
                Class strClass = str3.getClass();
                //获取属性
                Field str3_f = strClass.getDeclaredField("value");
                //赋予权限
                str3_f.setAccessible(true);
                //获取属性char[],数组是引用变量,final修饰后不能修改地址,但是可以修改值
                byte[] cArr = (byte[])str3_f.get(str3); //把str3中的char[]取出来
                cArr[0] = 'b';
                cArr[1] = 'b';
                cArr[2] = 'b';
                //不修改地址,直接修改数组内的值
                //长度不能修改
    
                System.out.println("str3 = " + str3);
                System.out.println("str4 = " + str4);
                System.out.println(str3 == str4);
                //str3 = bbb
                //str4 = bbb
                //true
                //修改成功,不过报了warning,说进行了不合理的操作 =w= 确实不太合理... final private的变量就这么从外部被修改了= =
                //所以尝试一下就好了,平时开发用不到,纯粹搞事情。
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static String modifierHelper(int i){
            // 一个类的modifier返回的数字,是符合以下要求的数字之和。
            //1024: abstract
            //512: interface
            //256: native
            //128: transient
            //64: volatile
            //32: synchronized
            //16: final
            //8: static
            //4: protected
            //2: private
            //1: public
            //0 默认不写
            String s = "";
    
            if(i >= 1024){
                s = s + "abstract ";
                i = i%1024;
            }
            if(i >= 512){
                s = s + "interface ";
                i = i%512;
            }
            if(i >= 256){
                s = s + "native ";
                i = i%256;
            }
            if(i >= 128){
                s = s + "transient ";
                i = i%128;
            }
            if(i >= 64){
                s = s + "volatile ";
                i = i%64;
            }
            if(i >= 32){
                s = s + "synchronized ";
                i = i%32;
            }
            if(i >= 16){
                s = s + "final ";
                i = i%16;
            }
            if(i >= 8){
                s = s + "static ";
                i = i%8;
            }
            if(i >= 4){
                s = s + "protected ";
                i = i%4;
            }
            if(i >= 2){
                s = s + "private ";
                i = i%2;
            }
            if(i == 1){
                s = s + "public ";
            }
            return s;
        }
    }
    package reflect;
    
    public class TestClass {
        //属性
        private String testName;
        public int age;
        //构造方法
        public TestClass(){
        }
        public TestClass(String name, int age){
            this.testName = name;
            this.age = age;
        }
        //
        {
            System.out.println("我在构造函数之前运行");
        }
        //方法
        //
    
        public String getTestName() {
            return testName;
        }
    
        public void setTestName(String name) {
            this.testName = name;
        }
    
        public String show(){
            return "name = " + this.testName + "|age = " + this.age;
        }
    }
  • 相关阅读:
    python 和 R 语言中的等差数列
    python 用 matplotlib 绘制误差条图
    Python 模拟伯努利试验和二项分布
    R 基于朴素贝叶斯模型实现手机垃圾短信过滤
    PCA 在手写数字数据集上的应用
    R 实现朴素贝叶斯分类器模型
    R语言 绘制正(余)弦图
    R 绘制反正(余)弦图像
    R 绘制正(余)切图像
    R 语言 do.call() 函数
  • 原文地址:https://www.cnblogs.com/clamp7724/p/11655237.html
Copyright © 2020-2023  润新知