1.问题的提出:
(1)给你一个类的全路径,比如
classPath="com.cx.Cat"
可以根据classPath去创建实例,不能直接使用new..
(2)给一个xml配置文件,如何创建类的一个实例对象
2.反射用在什么地方?
主要是用在框架上(struts/hibernate/spring...),如果只写普通的java程序,可以不去考虑反射。反射是java的基石。
3.(1)每个类被加载后,系统都会为该类生成一个对应的class对象,通过该class对象就可以访问到JVM中的这个类。
(2)获得Class对象的三种方式:
//得到Cat的Class对象(得到的是同一个对象) //1.通过forName Class clazz1=Class.forName("com.cx.reflection.Cat"); //2.通过class属性 Class clazz2=Cat.class; //3.通过Cat实例对象来获取 Cat cat=new Cat(); Class clazz3=cat.getClass();
(3)一旦获取了某个类的Class对象,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了
4.通过反射生成对象有两种方式:
(1)使用Class对象的newInstance()方法,要求该Class对象的对应类有默认的构造器,java9中已废除
Class clazz1=Class.forName("com.cx.reflection.Cat"); //1.通过Class对象可以创建对象实例 Cat cat1=(Cat)clazz1.newInstance(); cat1.show();
(2)可以指定某个构造函数去创建对象
//通过(public Cat(String name,int age))来创建实例 Constructor c1=clazz1.getConstructor(String.class,int.class); Cat cat1=(Cat)c1.newInstance("小白",6); cat1.show();
一个容易错的例子:当构造函数的参数是数组的时候
//通过public Cat(String [] foods)来创建实例 Constructor c2=clazz1.getConstructor(String[].class); String[] foods={"鱼","老鼠"}; c2.newInstance(foods);
问题:wrong number of arguments。
newInstance是可变参数,当传入数组时,会自动的转为c2.newInstance(foods[0],foods[1]),和构造器的形式不匹配,反射不会成功。
解决办法:将对象数组强转为一个对象
c2.newInstance((Object)foods);
5.使用反射调用方法
//使用反射来调用public void show() //cat1.show(); Method method=clazz1.getMethod("show",null); //invoke的第一个参数表示对象实例,第二个参数表示给该方法传入的值 method.invoke(cat1, null);
问题:如何去调用一个private的方法?(暴力访问)
//如何调用私有的函数,比如private void show(String name) Method method4=clazz1.getDeclaredMethod("show", String.class); //暴力访问 method4.setAccessible(true); method4.invoke(cat1, "小白");
静态方法:可以method.invoke(null, "小白");
6.使用反射访问属性值(也分为public和private)
//使用反射访问属性值 //Field field=clazz1.getField("name"); Field field=clazz1.getDeclaredField("name"); field.setAccessible(true); System.out.println(field.get(cat1));