反射操作核心:一切操作都将使用Object完成,类、数组的引用都可以使用Object进行接收。
Class类:通过一个实例化对象找到一个类的完整信息(通过一个对象得到对象所在的完整的“包.类”名称)。调用Class类时也使用了泛型声明。
1、Class类没有定义构造方法所以实例化Class类对象的三种方法:
通过forName(“完整的包.类名称”)方法
类.class
对象.getClass()
2、Class类的使用:Class主要是反射的源头,不光可以取得对象所在类的信息,也可以直 接通过Class类的方法进行对象实例化操作正常情况下,使用new对对象实例化。
(1)通过无参构造实例化对象:通过Class类本身实例化其他类的对象,则可以使用newInstance()方法,但是必须保证实例化的类中存在一个无参构造方法。
(2)调用有参构造实例化对象:若想用有参构造进行对象的实例化操作,则必须使用Constructor类完成。
步骤:通过Class类中getConstructors()取得本类中的全部构造方法
向构造方法中传递一个对象数组进去,里面包含了构造方法中所需要的各个参数(在声明对象数组时,必须考虑到构造方法中参数的类型顺序,)。
通过Constructor实例化对象。
通过无参构造实例化对象 | 调用有参构造实例化对象 |
public class InstanceDemo01 { public static void main(String args[]){ Class<?> c=null; try { c=Class.forName("org.lxh.demo15.instancedemo.Person"); } catch (Exception e) { e.printStackTrace(); } Person per=null; try { per=(Person)c.newInstance(); } catch (Exception e) { e.printStackTrace(); } per.setName("李星华"); per.setAge(30); System.out.println(per); } } | public class InstanceDemo03 { public static void main(String args[]){ Class<?> c=null; try { c=Class.forName("org.lxh.demo15.instancedemo.Person"); } catch (Exception e) { e.printStackTrace(); } Person per=null; Constructor<?> cons[]=null; cons=c.getConstructors(); try { per=(Person)cons[0].newInstance("李星华",30); } catch (Exception e) { e.printStackTrace(); } System.out.println(per); } } |
3、反射的应用(取得类的完整结构)
用到java.lang.reflect包中的以下几个类:Constructor:表示类中的构造方法
Field:表示类中的属性
Method:表示类中的方法
(1)、取得所实现的全部接口:使用Class类中的getInterfaces()方法。返回一个Class类的数组,之后直接利用Class类中的getName()方法取得类的名称。
(2)、取得父类:一个类可以实现多个接口却只可以继承一个父类。使用Class类中的getSuperclass()方法取得一个类的父类。(没有明确编写父类时默认为Object类)
(3)、取得全部构造方法:使用Class类中的getConstructors()方法。
直接输出Constructor对象得到的完整的信息,是比较全的信息。
用户也可以自己手工拼凑出信息(Java中取得权限时返回到是一个数字必须依靠Modifier类还原为用户可以看懂的权限修饰符)
(4)、取得全部方法:取得一个类中的全部方法,可以使用Class类中的getMethod()方法,返回一个Method类的数组
获得本类中的方法,可以使用Class类中的getDeclaredMethod()方法
(5)、取得全部属性(伐返回的都是Field的数组,每个Field对象表示类中一个属性):
取得实现的接口或父类中的公共属性使用getFields()方法
得到本类中的全部属性使用getDeclaredFields()方法
4、反射机制深入应用
反射除了可以去的一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。
(1)、通过反射调用类中的方法(通过Method类完成)
<1>、通过Class类的getMethod(String name,Class...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型
<2>、使用invoke()进行调用,并向方法中传递要设置的参数。(使用此方法时必须传入一个类的实例化对象)
方法中没有参数时 | 方法中有参数时 |
public class InvokeSayChinaDemo { public static void main(String args[]){ Class<?> c1=null; try { c1=Class.forName("org.lxh.demo15.Person"); } catch (Exception e) { e.printStackTrace(); } try { Method met=c1.getMethod("sayChina"); met.invoke(c1.newInstance()); } catch (Exception e) { e.printStackTrace(); } } } | public class InvokeSayHelloDemo { public static void main(String args[]){ Class<?> c1=null; try { c1=Class.forName("org.lxh.demo15.Person"); } catch (Exception e) { e.printStackTrace(); } try { Method met=c1.getMethod("sayHello",String.class,int.class); String rv=null; rv=(String)met.invoke(c1.newInstance(),"李兴华",30); System.out.println(rv); } catch (Exception e) { e.printStackTrace(); } } } |
(2)、通过反射操作数组:反射机制不仅只能用在类上,还可以用在任意的引用数据类型的数据上(这包含数组,即可以使用反折射操作数组)。
通过Class类取得一个数组的Class对象:public Class<?> getComponenType()
在反射操作包java.lang.reflect中使用Array类表示一个数组,可以通过此类取得数组长度,取得数组内容的操作。
5、动态代理
代理设计:一操作的接口有两个子类:一个是真实主题的实现类
另一个是代理类,代理实现类要完成此真实主题实现类更多的内容而且本身还需处理一些具体业务有关的程序代码。
实现动态代理机制:需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类支持。
(1)、InvocationHandler接口只定义一个invoke()方法(参数Object proxy:被代理的对象。Method method:要调用的方法。Object args[]方法调用时所需要的参数)
(2)、Proxy类专门完成代理的操作:通过此类为一个或多个接口动态的生成实现类。通过newProxyInstance()方法可动态生成实现类。(参数ClassLoader loader:类加载器。Class<?>[] interfaces:得到全部接口。InvocationHandler h:得到InvocationHandler接口的子类实例)
Java中三类加载器 |
|
Bootstrap ClassLoader | 采用C++编写,开发中看不到 |
Extension ClassLoader | 进行扩展类的加载,对应jre\lib\ext目录中的类 |
AppClassLoader | 加载classpath指定的类(默认的ClassLoader) |