标签:回收 操作 getx 通道 red 反射 except nbsp 个数
反射(reflect):通过类的Class对象来获取类的相关信息,动态操作类中的字段、调用类中的方法。
第二种方式最好。
但有一个问题:使用第二种不能动态创建对象,使用第一种可以。
示例:
1 Class<?> Class1 = Class.forName("test.Student"); //必须写成全类名。因为类名是String形式,编译时并不知道Class对象的类型,所以只能写成?,?相当于Object 2 Class<Student> Class2 = (Class<Student>) Class.forName("test.Student"); //强转后可以写成具体类型 3 4 Class<Student> class3=Student.class; //编译时知道Class对象的类型 5 6 Student student=new Student(); 7 Class<?> class4=student.getClass(); 8 Class<Student> class5= (Class<Student>) student.getClass(); //需要强转
类是对对象的抽象,Class类是对所有类的抽象,Class类的实例称为Class对象。
类都有构造器、字段(成员变量+类变量)、方法(成员方法+类方法),Class对象提供了获取构造器、字段、方法的一系列方法。
T表示可以写成具体的类型,后面不用强转。
?相当于Object,后面需要强转。
Student类如下:
1 class Student{ 2 private int id; 3 private String name; 4 private int age; 5 private int score; 6 7 public Student() { 8 } 9 10 public Student(int id, String name, int age, int score) { 11 this.id = id; 12 this.name = name; 13 this.age = age; 14 this.score = score; 15 } 16 17 public int getId() { 18 return id; 19 } 20 21 public void setId(int id) { 22 this.id = id; 23 } 24 25 public String getName() { 26 return name; 27 } 28 29 public void setName(String name) { 30 this.name = name; 31 } 32 33 public int getAge() { 34 return age; 35 } 36 37 public void setAge(int age) { 38 this.age = age; 39 } 40 41 public int getScore() { 42 return score; 43 } 44 45 public void setScore(int score) { 46 this.score = score; 47 } 48 49 @Override 50 public String toString() { 51 return "Student{" + 52 "id=" + id + 53 ", name=‘" + name + ‘\‘‘ + 54 ", age=" + age + 55 ", score=" + score + 56 ‘}‘; 57 } 58 }
1 Class<Student> studentClass = Student.class; //获取Class对象 2 Constructor<Student> constructor = studentClass.getConstructor(int.class, String.class, int.class, int.class); //获取指定的构造器。参数要写成Class对象的形式 3 Student student = constructor.newInstance(1, "chy", 20, 100); //调用构造器的newInstance()创建对象,参数是实参值 4 System.out.println(student);
1 Student student1 = new Student(1, "张三", 12, 90); //创建对象 2 Student student2 = new Student(2, "李四", 12, 90); 3 4 Class<Student> studentClass = Student.class; //获取Class对象 5 Field nameField = studentClass.getDeclaredField("name"); //字段一般是私有的,所以要用Declared 6 nameField.setAccessible(true); //取消权限检查。 7 /* 8 public在类外可直接操作,所以不需要取消权限检查。 9 private不允许在类外操作,需要取消权限检查才能操作private成员。 10 将通道设置为true,即打开通道,放行,通过检查。 11 */ 12 13 //获取字段的值 14 String name1 = (String) nameField.get(student1); //根据student1的name字段的值,返回Object型 15 String name2 = (String) nameField.get(student2); 16 System.out.println(name1); //张三 17 System.out.println(name2); //李四 18 19 //设置字段的值 20 nameField.set(student1,"zhangsan"); //第二个参数指定新值 21 nameField.set(student2,"lisi"); 22 System.out.println(student1.getName()); //zhangsan 23 System.out.println(student2.getName()); //lisi 24 25 /* 26 Field是通过Class对象获取的,不是通过这个类的某个对象获取的。Field包含了这个类所有对象的指定字段的值。 27 就是说nameField包含了Student类所有实例的name属性值。 28 所以要用一个参数指定操作的是哪个实例的字段。 29 30 如果是8种基础数据类型的字段,使用的是:getInt()、setInt()等getXxx()、setXxx()系列方法, 31 获取值时返回的就是该种数据类型,不必强转 32 33 如果是引用数据类型(包括String),使用的是get()、set()方法,获取值时返回的是Object类型,往往需要强转 34 */
1 Student student = new Student(1, "张三", 12, 90); //创建对象 2 Class<Student> studentClass = Student.class; //获取Class对象 3 4 //调用无参的方法 5 Method getNameMethod = studentClass.getMethod("getName");//方法一般是公有的,不必使用Declared。获取空参的getName()方法。第一个参数指定String类型的方法名 6 //getNameMethod.setAccessible(true); //方法一般是公有的,可以在类外使用,所以不必取消权限检查。 7 String name = (String) getNameMethod.invoke(student); //参数指定对象。 8 /* 9 会把被调方法的返回值作为invoke()的返回值。但不同的被调方法,返回值类型可能是不同的,所以invoke()的返回值类型声明是Object。 10 需要强转。 11 */ 12 System.out.println(name); //张三 13 14 15 //调用有参的方法 16 Method setNameMethod = studentClass.getMethod("setName",String.class);//第一个参数指定方法名,后面参数个数不确定,指定形参的对象类型。(区分重载方法) 17 setNameMethod.invoke(student,"李四"); //第一个参数指定对象,后面参数个数不确定,指定实参值 18 System.out.println(student.getName()); //李四
java.lang.reflect包下有一个Array类,此类有许多静态方法,可以动态创建数组,动态获取、设置数组元素的值。
1 //动态创建数组 2 Object obj = Array.newInstance(String.class, 10); //第一个参数指定数组的元素类型,第二参数指定元素个数 3 String[] arr= (String[]) obj; //动态创建数组的返回值返回值是Object,有时候需要强转 4 5 //动态设置数组元素的值 6 Array.set(obj, 0, "张三"); //第一个参数指定数组,第二个参数指定数组下标,第三个参数指定元素值 7 Array.set(obj,1,"李四"); //虽然obj是Object类型,但要求第一个参数是数组,会自动向下转型 8 9 //动态获取数组元素的值 10 Object first = Array.get(obj, 0); //第一个参数是数组,第二个参数是数组下标 11 Object second=Array.get(obj, 1); 12 System.out.println(first); //会自动向下转型。张三 13 System.out.println(second); //李四 14 15 /* 16 这三个方法均为静态方法,通过Array直接调用。 17 基本数据类型用setXxx()、getXxx(),比如setInt()、getInt(),获取时返回的就是该类型。 18 引用数据类型用set()、get(),获取值时返回值类型是Object。 19 */
原来我们创建对象:Student student=new Student(1,"chy",20,100);
操作字段、调用函数:student.setAge(22);
操作数组:arr[0]=1
把代码写死了。
使用反射:把数据作为参数传入。
比如调用方法:
Method method = studentClass.getMethod("setName",String.class); method.invoke(student,"李四");
把方法名、参数类型作为参数传入,把对象、实参作为方法传入。
传入什么方法,就调用什么方法。比如传入"setName",它就调用setName(),传入"getName",就调用getName()。它是动态调用的,传入什么,就调用什么。
不像原来student.setName("张三");把方法写死了,这句代码只会调用setName(),调用不了其他方法。
比如操作数组:
Array.set(arr, 0, "张三");
把数组、索引、元素值作为参数传入,传入哪个数组就操作哪个数组,传入哪个索引就操作哪个索引,传入什么值,就使用什么值,根据传入的东西来动态操作。
不像原来arr[0]="张三",都写死了,全是固定的,最多索引、元素值使用变量,但数组仍是固定的。
标签:回收 操作 getx 通道 red 反射 except nbsp 个数
原文地址:https://www.cnblogs.com/chy18883701161/p/11385253.html