黑马程序员技术交流社区

标题: 【上海校区】反射(二) [打印本页]

作者: 偷树的光头强    时间: 2019-10-24 15:37
标题: 【上海校区】反射(二)
                                                          反射(二)
一、反射概念
反射就是通过一个类的Class对象把类中的各种成员映射成对应的Java类。
一个类中的:成员变量、构造函数、成员方法都有对应的Java类:Field、ContructorMethod       
就比如:一个汽车是一个大类,汽车中的发动机、轮胎等等都可以是一个个小的类。
一个类的Class对象可以获取其所有成员的信息,比如一个方法的名称、修饰符、参数类型、返回值等等信息封装成一个描述方法的类(Method)中。
换句话说反射通过Class类的对象可以获取一个类中的成员,比如函数,保存在Method类中。
然后通过Method类的对象来获取一个成员函数的名称、修饰符、参数类型、返回值等等信息。
一个类中的所有成员,都可以通过Class对象获得,并封装为对应的对象。我们拿到这些对象以后,有什么用?怎么用?这正是我们学习反射的要点!
1、使用Class类中的newInstance()函数创建某个类的对象
通过上述办法已经获取到了Class对象,即就是获取到某个类的class文件。现在我们不使用Java中的new关键字来创建这个class文件所描述的那个事物的真实对象, 而通过Class这个对象,动态的创建这个类的真实对象。
在Class类中有一个newInstance()方法,可以动态的创建出当前这个class文件的真实对象。
[Java] 纯文本查看 复制代码
public class Person {
        //属性
        private String name;
        private int age;
        public Person(String name, int age) {
                this.name = name;
                this.age = age;
        }
        public Person() {
        }
}

[Java] 纯文本查看 复制代码
/*
* 使用Class类中的newInstance()函数获取某个class文件中的真实对象
*/
public class ReflectDemo1 {
        public static void main(String[] args) throws Exception {
                // 获取Class类的对象
                Class clazz = Class.forName("cn.itcast.sh.reflect.demo.Person");
                //使用对象调用函数创建Person类的对象
                Person p = (Person) clazz.newInstance();
                /*
                 * 上述两行代码等同于
                 *Person p= new Person();
                 *注意:这里是使用Person类中的无参构造函数在创建对象,所以要求Person类中必须具备无参构造函数,
                 *否则就会报 java.lang.InstantiationException:不能实例化异常
                 */
                System.out.println(p);//cn.itcast.sh.reflect.demo.Person@5a20d10a
                //利用无参构造函数创建对象
                String s = String.class.newInstance();
                System.out.println(s.length());//0
        }
}

2、使用反射获取一个类中的所有构造函数(包括有参数和私有的构造函数)(Constructor类)
1)使用Class类的对象即字节码对象可以获取class文件中的所有构造函数,具体应该借助Class类中的如下函数:
Constructor getDeclaredConstructor(Class ... parameterTypes)根据参数列表获取指定的构造函数 包括私有的
说明:由于这里需要Class类的对象,所以在给参数的时候,直接使用实参类型的类获取Class对象即可。
举例:假设需要获取String类型的构造函数,那么这里直接使用String.class作为getDeclaredConstructor(Class ... parameterTypes)的参数。
2)获取到构造函数对象之后,就可以使用获取的构造函数对象创建某个类的真实对象。我们通过反射已经获取到构造函数,查阅Constructor类中的描述,发现Constructor类中的newInstance(Object... initargs) 方法,这个方法可以动态的创建出这个构造函数对象所表示的那个类的真实对象。
说明: Object... initargs 创建对象的时候需要传递的真实的数据,就是构造函数所需要的实际参数。
注意:通过Class类中的Constructor getDeclaredConstructor(Class ... parameterTypes)函数可以获得类中的所有的构造函数,包括私有的构造函数,但是私有的构造函数我们在其他类中是无法使用的,如果要想使用必须强制取消Java对私有成员的权限检测或者可以理解暴力访问。
小结:
当要访问Class对象中的私有的构造或成员时,需要使用getDeclaredXxxx()函数:Xxxx表示:Constructor、Field、Method。
在访问Class对象中的私有的构造函数或成员时,需要取消java语言的默认访问权限检查
setAccessible(boolean)  true表示强制取消Java对私有成员的权限检测。 false表示不会取消Java对私有成员的权限检测。
3、反射公开的非静态的成员方法
Method getDeclaredMethod(String name,Class ... parameterTypes)获取某个方法。
说明:
1)在Class类中提供的getDeclaredMethod方法上接收一个String name,name表示的是需要反射的那个方法的名字。
因为在一个类中可以有多个不同名的方法。在反射的时候需要指定这个方法的名字,同时在一个类中还可能出现方法的重载,这时还需要指定具体反射的是哪个方法参数类型。
2)让反射到的一个方法运行,需要使用Method类中的invoke方法  :
Object invoke(Object obj, Object... args)   
invoke方法中的第一个参数 Object obj:表示的是当前需要调用这个方法的那个对象
invoke方法中的第二个参数Object... args:
表示的是真正需要运行的某个类中被反射的那个方法需要接收的真实参数
在调用Method类中的invoke方法的时候,其实底层是在运行被反射的那个方法,
既然是某个方法在运行,那么方法运行完之后可能会有返回值。








欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2