利用反射构造对象
这里先补充一个概念:类的反射
在程序运行的时候,查看一个类里面有哪些信息(包含的数据成员和方法成员),这个过程称之为反射。
如果我们知道要使用哪个类,只需要用这个类来创建对象,然后就可以调用获取这个对象里面的数据和方法;相反,如果我们不知道使用哪个类,就需要使用反射获取类的信息,看里面有些什么东西,然后再使用。
下面来看一份代码:
User.java:
1 package com.hw.Class0228;
2
3 public class User {
4 private int age;
5 private String name;
6 private double score;
7 private int id;
8
9 public User(){}
10 public User(int age,String name,double score){
11 this.age = age;
12 this.name = name;
13 this.score = score;
14 }
15 private User(int id){
16 this.id = id;
17 }
18
19 public int getAge(){
20 return age;
21 }
22 public void setAge(int age){
23 this.age = age;
24 }
25
26 public String getName(){
27 return name;
28 }
29 public void setName(String name){
30 this.name = name;
31 }
32
33 public double getScore(){
34 return score;
35 }
36 public void setScore(double age){
37 this.score = score;
38 }
39
40 public void introduce(){
41 System.out.println("大家好,我的名字是:"+getName());
42 }
43 public void show(){
44 System.out.println(id+"of"+getName()+"的分数是:"+getScore());
45 }
46 }
Demo01_GetClass.java:
1 package com.hw.Class0228;
2
3 import java.lang.reflect.Constructor;
4 public class Demo01_GetClass {
5 public static void main(String[] args) throws Exception {
6 User user1 = new User(18,"小明",98); //这里先创建两个对象
7 User user2 = new User(20,"小红",100);
8
9 Class c1 = user1.getClass(); //调用getClass()方法获取一个Class对象
10 Class c2 = user2.getClass();
11
12 Class c4 = User.class; //通过类
13 System.out.println(c1==c4);
14
15 Class c5 = Class.forName("com.hw.Class0228.User"); //使用这个静态方法
16 System.out.println(c1==c5);
17
18 //得到所有的public构造方法
19 // Constructor[] cs = c5.getConstructors();
20 // for(Constructor con : cs){
21 // System.out.println(con);
22 // }
23
24 /**
25 * 下面这种方法是得到单个(指定的)构造方法。里面传递的参数是可变参数(个数可变)
26 * 每个参数的类型都是Class类型的,所以这里还是一个Class对象
27 * 因为每一个类型都对应一个Class对象
28 * 所以当传递一组类型过去的时候,会根据这一组类型匹配对应的构造方法
29 */
30 Constructor con = c5.getConstructor(); //没有参数,就没有类型,只能匹配到无参的构造方法
31
32 /**
33 * 这个方法就是新建实例,里面的参数也是可变参数。
34 * 又因为con是无参的构造方法,所以这里也不能传递任何参数
35 * 调用这个方法作用其实就是创建出来了一个对象,这个对象是User类型的。
36 * 但这个方法的返回值却是一个Object类型的。为啥?
37 * 因为我们自己创建的类名有各种可能,这个方法的返回值不可能能够确定,因此这里就是Object类型的
38 * 但本质上是一个Object类型的
39 */
40 Object o = con.newInstance();
41 User user = (User)o; //这里开始是一个验证,验证o其实是一个Object对象
42 user.show();
43 }
44 }
补充:get.Constructor使用来得到构造方法的。使用getConstructors(无参)可以得到所有的构造方法。这个方法返回的是一个constructors的数组。循环输出会输出里面所有public的构造方法。
而get.Constructor则是得到单个构造方法,当然这个里面的参数是可变参数。
而con.newInstance()其实就创建出来了一个User类型的对象。
如果我们想得到私有的构造方法要怎么办?
看代码:
1 package com.hw.Class0228;
2
3 import java.lang.reflect.Constructor;
4 public class Demo01_GetClass {
5 public static void main(String[] args) throws Exception {
6 User user1 = new User(18,"小明",98); //这里先创建两个对象
7 User user2 = new User(20,"小红",100);
8
9 Class c = Class.forName("com.hw.Class0228.User");
10 Constructor[] cs = c.getDeclaredConstructors();
11 for(Constructor con : cs){
12 System.out.println(con);
13 }
14 }
15 }
declared的意思就是声明的。就可以忽略访问权限,全部都可以得到。对应上面这个得到所有的构造方法的方法,同理就还有一个getDeclaredConstructor(),传参数进去就可。
但是啊,我们来看这样一段代码:
1 package com.hw.Class0228;
2
3 import java.lang.reflect.Constructor;
4 public class Demo01_GetClass {
5 public static void main(String[] args) throws Exception {
6 User user1 = new User(18,"小明",98); //这里先创建两个对象
7 User user2 = new User(20,"小红",100);
8
9 Class c = Class.forName("com.hw.Class0228.User");
10 Constructor con = c.getDeclaredConstructor(int.class);
11 Object o = con.newInstance(28);
12 User user = (User)o;
13 user.show();
14 }
15 }
直接报错了。can not access a member of class com.hw.Class0228.User with modifiers "private"
所以,因为这个构造方法是私有的,所以不能得到。但真的就不能得到了吗?非也。
加一个con.setAccessible(true);就可以了。
1 package com.hw.Class0228;
2
3 import java.lang.reflect.Constructor;
4 public class Demo01_GetClass {
5 public static void main(String[] args) throws Exception {
6 User user1 = new User(18,"小明",98); //这里先创建两个对象
7 User user2 = new User(20,"小红",100);
8
9 Class c = Class.forName("com.hw.Class0228.User");
10 Constructor con = c.getDeclaredConstructor(int.class);
11 con.setAccessible(true);
12 Object o = con.newInstance(28);
13 User user = (User)o;
14 user.show();
15 }
16 }