Java基础加强 (七)

2014-11-24 09:56:18 · 作者: · 浏览: 1
Annotation 类型被定义为运行时 Annotation 后, 该注释才是运行时可见, 当 class 文件被载入时保存在 class 文件中的 Annotation 才会被虚拟机读取

(3)程序可以调用 AnnotationElement 对象的如下方法来访问 Annotation 信息

26、动态代理

(1)明确两个概念:

代理对象存在的价值:主要用于拦截对真实业务对象的访问。

代理对象有什么方法?

(2)现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。

(3)如何编写生成代理对象的类,两个要素:

代理谁

如何生成代理对象

(4)代理谁?

设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象。

(5)如何生成代理对象?

设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)

(6)Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:

1.生成代理对象使用哪个类装载器

2.生成哪个对象的代理对象,通过接口指定

3.生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。

(7)初学者必须理解,或不理解必须记住的2件事情:

Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。

由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。

package com.itheima.proxy;


public class SpringBrother implements Human {


public void sing(float money) {

System.out.println("拿到"+money+"钱,开唱");

}


public void dance(float money) {

System.out.println("拿到"+money+"钱,开跳");

}


public void eat() {

System.out.println("吃饭");

}


}


package com.itheima.proxy;


public interface Human {

void sing(float money);

void dance(float money);

void eat();

}

package com.itheima.proxy;


import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;


public class Client {


public static void main(String[] args) {

final Human h = new SpringBrother();


//动态得到代理人

/**

* loader:代理人使用的类加载器。与被代理人h使用的是一样的

* interfaces:代理人要实现的接口。与被代理人h所实现的接口是一样的

* InvocationHandler h:策略设计模式。具体该怎么代理?

*/

Human proxyHuman = (Human)Proxy.newProxyInstance(h.getClass().getClassLoader(), h.getClass().getInterfaces(), new InvocationHandler() {

//具体怎么代理:具体代理策略

/**

* 调用被代理人的任何方法都会执行该方法

* proxy:代理对象的引用

* method:当前执行的是什么方法

* args:当前执行的方法需要的参数

*/

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

// System.out.println("被代理了");

if("sing".equals(method.getName())){

//判断出场费

float money = (Float)args[0];

if(money>=10000){

return method.invoke(h, money/2);

}

return null;

}else if("dance".equals(method.getName())){

//判断出场费

float money = (Float)args[0];

if(money>=20000){

return method.invoke(h, money/2);

}

return null;


}else{

return method.invoke(h, args);

}

}

});


proxyHuman.sing(20000);

proxyHuman.dance(30000);

proxyHuman.eat();

}


}


27、动态代理应用

(1)在动态代理技术里,由于不管用户调用代理对象的什么方法,都是调用开发人员编写的处理器的invoke方法(这相当于invoke方法拦截到了代理对象的方法调用)。

(2)并且,开发人员通过invoke方法的参数,还可以在拦截的同时,知道用户调用的是什么方法,因此利用这两个特性,就可以实现一些特殊需求,例如:拦截用户的访问请求,以检查用户是否有访问权限、动态为某个对象添加额外的功能。

28、类加载器

(1)类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象

(2)当 JVM 启动时,会形成由三个类加载器组成的初始类加载器层次结构:


29、bootstrap classloader

(1)bootstrap classloader:引导(也称为原始)类加载器,它负责加载Java的核心类。这个加载器的是非常特殊的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM自身实现的。可以通过执行以下代码来获得bootstrap classloader加载了那些核心类库:


因为JVM在启动的时候就自动加载它们,所以不需要在系统属性CLASSPATH中指定这些类库


30、extension classloader

extension classloader -扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中的JAR包。这为引入除Java核心类以外的新功能提供了一个标准机制。因为默认的扩展目录对所有从同一个JRE中启动的JVM都是通用的,所以放入这个目录的 JAR类包对所有的JVM和system classloader都是可见的。

31、system classloader

(1)system classloader - 系统(也称为应用)类加载器,它负责在JVM被启动时,加载来自在