标签:javase 记录 reflection 反射 动态代理
今天来进行反射的总结,在JavaSE应用的几个部分里,我认为反射是非常重要的一个内容,因为我们在后续学习框架,以及编程思想上的理解都离不开它。内容不是很多,但是需要理解。
1.为什么要有反射?
某种情况下,我们需要在运行时才得知并使用一个编译时完全未知的类,创建其对象,调用其方法和属性。
2.反射:
被视为动态语言的关键,允许程序在执行期间借助Reflection API取得任何类的内部信息,并直接操纵任意对象的内部属性和方法。
3.类加载的过程:
当程序主动使用某个类时,如果该类还未被加载到内存,系统会通过以下三个步骤来对类进行初始化。
①类的加载:
将.class文件读入到内存中,并为之创建一个java.lang.Class对象。有类加载器来完成
②类的连接:
将类的二进制数据合并到JRE中。
③类的初始化:
JVM负责对类进行初始化。
扩展:
类加载的特性:
在虚拟机生命周期中一个类只被加载一次
加载原则:延迟加载,能少加载就少加载,因为虚拟机的空间是有限的
类加载的时机:
1)第一次创建对象时
2)调用静态方法时要加载类,访问静态属性时会加载类
3)加载子类必先加载父类
4)创建对象引用不加载类
5)子类调用父类的静态方法时:
①当子类没有覆盖父类的静态方法时 ,只加载父类,不加载子类
②当子类覆盖父类的静态方法时,加载父类, 也加载子类
6)访问静态常量,如果编译器可以直接计算出常量的值,则不会加载类,负责加载类。
4.获取Class类对象的实例:
①
Class clazz = Person.class();
②
Person p = new Person();
Class clazz = p.getClass();
③
String className = "com.qh.review.Person";
Class clazz = Class.forName(className);
④
String className = "com.qh.review.Person";
ClassLoader cl = Person.class.getClassLoader();
class clazz = cl.loadClass(className );
5.类加载器
①获取系统类加载器
ClassLoader cl = ClassLoader.getSystemClassLoader();
System.out.println(cl);
注意:负责加载classpath下的所有jar包
②获取扩展类加载器
ClassLoader cl2 = cl.getParent();
System.out.println(cl2);
注意:负责加载jre/lib/ext下的所有jar包
ClassLoader cl3 = cl2.getParent();
System.out.println(cl3);
注意:负责加载核心类库,无法直接获取
获取当前类由哪个类来加载:
ClassLoader cl = Person.class.ClassLoader();
System.out.println(cl);
6.通过反射来获取对象实例
Person person = Person.class().newInstance();
注意: 这里这个newInstance()实际上调用的是类的构造器。可以通过声明一个带参的构造器来测试。
7.操作属性,这里的代码,我就把我今天回顾的内容粘过来了,大家不想看的可以往下跳过。想看的可作一个参考。
// 操作属性
@Test
public void test4() {
// 先获取具体类的Class对象
Class<?> clazz = null;
try {
clazz = Class.forName("com.qh.review2.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 通过clazz来获取类属性---->public 1,protected 4, private 2, default 0
Field[] fields = clazz.getFields();// 只能获取访问控制修饰符为public的属性.访问控制修饰符为1即为public
for (Field field : fields) {
System.out.println(field.getName());// phone
System.out.println(field.getType());// 1
System.out.println(field.getModifiers()); // class java.lang.String
}
System.out.println("---------------------------------------------");
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field.getName());
System.out.println(field.getModifiers());
System.out.println(field.getType());
System.out.println("************");
}
// 对某一对象的属性进行操作:一个类确定后,就不能修改其修饰符,数据类型,名称。同时操作私有属性的时候,需要修改访问权限。
Field name = null;
Person person = null;
try {
person = (Person) clazz.newInstance();
name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(person, "张三");
} catch (InstantiationException | IllegalAccessException
| NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
System.out.println(person);
}
8.操作方法
@Test
public void test5() {
// 获取所有方法--->方法的修饰符 返回的数值不确定。??
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println("访问控制修饰符:" + methods[i].getModifiers());
System.out.println("返回值类型:" + methods[i].getReturnType());
System.out.println("方法名:" + methods[i].getName());
Class<?>[] parameterType = methods[i].getParameterTypes();
for (Object paramObject : parameterType) {
System.out.println("参数类型:" + paramObject);
}
Class<?>[] exceptionTypes = methods[i].getExceptionTypes();
for(Object eType : exceptionTypes){
System.out.println("异常类型:" + eType);
}
Type[] grnericTypes = methods[i].getGenericParameterTypes();
for(Type type : grnericTypes){
System.out.println("泛型类型:" + type);
}
System.out.println("------------------------------------------");
}
// 操作方法:--->方法只能调用。
System.out.println("操作方法");
try {
Person person = clazz.newInstance();
Method getName = clazz.getDeclaredMethod("getName");
System.out.println(getName.invoke(person));
} catch (InstantiationException | IllegalAccessException
| NoSuchMethodException | SecurityException
| IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
我把获取类对象提到外面了,要不每次还得写。
重点: 这里一定要注意方法的调用。后面的动态代理和AOP要用到。
8.获取父类泛型类型,感觉这个还是蛮重要的。前段时间我写的jdbc中就用到。我还是写一写吧。
Class clazz = Person.class();
Type type = clazz.getGenericSuperClass();
ParameterizedType types = (ParameterizedType)type;
for(Type t : types){
System.out.println(t);
}
这些东西都要熟记,给一个记事本就能写出来,并且别出错。我就是这样要求我的。
9.还有一些类型,这里我就不说了,大家可以参看关于Reflection的API文档
接下来写三个应用:
在写动态代理之前,我们先回顾一下静态代理怎么写?
1.静态代理
代理类和被代理类实现同一个接口,在代理类中通过代理类对象调用接口中的方法,但实际上还是通过被代理类对象调用方法来完成相应的功能。
汗,竟然没我上午总结的好,来看看。
一个接口,一个被代理类,一个代理类,代理类和被代理类都可以实现接口中的方法
被代理类通过代理类来执行代理类中的方法。
interface Factory{
void produce();
}
//被代理类
class NikeFactory implements Factory{
public void produce(){
System.out.println("生产NIKE衣服。。");
}
}
//代理类
class NikeProxy implements Factory{
NikeFactory nf = null;//实际上要调用方法的代理类对象
public NikeProxy(NikeFactory nf){
this.nf = nf;//初始化这个对象
}
public void produce(){
nf.produce();//实际上是代理类对象来生产的衣服
}
}
public class Proxy{
public void main(String[] args){
NikeFactory nf = new NikeFactory();
NikeProxy np = new NikeProxy(nf);
np.produce();//生产NIKE衣服。。
}
}
懂了么?实际上动态代理和AOP逻辑上和这个是一样的。只不过静态代理只能是针对特定的对象。
2.动态代理:
interface Factory{//还是和刚刚一样
void produce();
}
class NikeFactory implements Factory{//还是和刚刚一样
public void produce(){
System.out.println("生产NIKE衣服。。");
}
}
//来看代理类
class MyInvocationHandler implements InvocationHandler{
Object obj = null;//还是这个代理类对象
//需要一个代理类对象,当然是通过反射的方式获取喽!
public Object getProxy(Object obj){
this.obj = obj;//初始化一下
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this);
}
//实现的方法没记住,粘一下。
//代理类执行被代理类方法时,转换为对此方法的调用。
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {//还记得我上面通过反射操作方法中的注意事项吗?回头看看吧。
return method.invoke(obj, args);//同上,要不你这里理解不了。
}
}
public class TestProxy{
public void main(String[] args){
NikeFactory nf = new NikeFactory();
MyInvocationHandler mih = new MyInvocationHandler();
Object obj = mih.getProxy(nf);//返回的代理类对象
Factory f = (Factory)obj;//实现了Factory接口
f.produce();//是不是在生产NIKE的衣服?
}
}
3.AOP(Aspect Oriented Programming)面向切面编程。到现在为止,这是我见到的第一个面向切面编程的例子,可能只是掌握了其形式,对其内涵还没有理解。会随着以后的学习增加对其的理解。
来看一张图:
其实具体的内容和动态代理没什么两样。代码就不写了。给大家粘出来看看。
interface Human {
void walk();
void fly();
}
class SuperMan implements Human {
@Override
public void walk() {
System.out.println("走走走走走啊走");
}
@Override
public void fly() {
System.out.println("I belive I can fly");
}
}
class HuManUtil {
public void method1() {
System.out.println("method 1 !!!!");
}
public void method2() {
System.out.println("method 2 !!!!");
}
}
// 获取代理对象
class ManInvocationHandler implements InvocationHandler {
Object obj;
public Object getProxy(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
HuManUtil h1 = new HuManUtil();
h1.method1();
Object returnVal = method.invoke(obj, args);
h1.method2();
return returnVal;
}
}
public class TestAOP {
public static void main(String[] args) {
SuperMan sm = new SuperMan();
ManInvocationHandler mih = new ManInvocationHandler();
Object obj = mih.getProxy(sm);
Human proxy = (Human) obj;
proxy.walk();
System.out.println();
proxy.fly();
}
}
标签:javase 记录 reflection 反射 动态代理
原文地址:http://blog.csdn.net/sloverpeng/article/details/44229589