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; } }