局部类访问外部final变量

在局部类, 我们要更新封闭作用域用的变量, 这一般来说是不容易做到了. 因为局部类要访问封闭作用域的类, 要用final去修饰封闭作用域的变量.
例子: 想统计一下在排序过程中调用 compareTo方法的次数

int count = 0;
Date[] dates = new Date[100];
for(int i=0; i < dates.length; i++){
dates[i] = new Date(){
public int compareTo(Date other){
count++; //ERROR
return super.compareTo(other);
}
};
}


由于清楚知道counter需要更新, 所以不能将counter声明为final,由于Integer对象是不可变的, 所以也不能用Integer代替它. 补救的方法是使用一个长度为1的数组

final int[] counter = new int[1];
for(int i=0; i<dates.length; i++){
dates[i] = new Date(){
public int compareTo(){
counter[0]++;
return super.compareTo(other);
}
};
}


这里数组变量仍然被声明为final , 但是这仅仅表示 不可以让它引用另外一个数组. 数组中数据元素可以自由地更改.

===========================================
内部类特殊的语法规则.

/**
* 外部类
*/
class TalkingClock{
private int interval;
private boolean beep;

public TalkingClock(int interval, boolean beep){
this.interval = interval;
this.beep = beep;
}

public void start(){
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}

/**
* 内部类,这里用的是public修饰符
*/
public class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
Date now = new Date();
System.out.println("At the tone, the time is " + now);
if(beep){
Toolkit.getDefaultToolkit().beep();
}
}
}

}


使用外围类引用的语法表达式
[b]OuterClass.this[/b]
表示外围类似引用.
可以像下面这样编写TimePrinter内部类似的actionPerformed方法.

public void actonPerformed(ActionEvent event){
if(TalkingClock.this.beep) Toolkit.getDefaultToolkit().beep();
}

反过来,可以采用下列语法格式更加明确地编写内部对象的构造器
outerObject.new InnerClass(construction parameters)
例如,

ActionListener listener = this.new TimePrinter();

在这里, 最新构造的TimePrinter对象的外围类引用被设置为创建内部类对象的方法中this引用. 这是一种很常见的情况. 通常this限定词是多余的. 不过,可以通过命名将外围类引用设置为其它对象. 例如, 如果TimePrinter是一个公有内部类, 对于任意的语音时钟都可以构造一个TimePrinter

TalkingClock jabberer = new TalkingClock(1000, true);
TalkingClock.TimePrinter listener = jabberer.new TimePrinter(); //注意这一行


在外围类的作用域之外, 可以这样引用内部类
[b]OuterClass.InnerClass[/b]

=====================
有时候,使用内部类只是为了把一个类隐藏在另外 一个类的内部,并不需要内部类引用外围类对象. 为此,可以将内部类声明为static 以便取消产生的引用.


=====================代理
代理类具有下列方法:
. 指定接口所需要的全部方法
. Object类的全部方法,例如: toString, equals等

调用处理器(invocationhandler)是实现了InvocationHandler接口的类对象
无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的调用参数 . 调用处理器必须给出处理调用的方式.

创建一个代理对象,要使用Proxy类的newProxyInstance方法. 三个参数:
1. 类加载器, 用null表示默认的类加载器
2. 一个Class对象数组,每个元素都是需要实现的接口
3. 一个调用处理器

使用代理的原因有很多, 例如:
1. 路由对远程服务器的方法调用
2. 在程序运行期间,将用户接口事件与动作关联起来.
3. 为调试跟踪方法调用.

代理对象属于在运行时定义的类(它有一个名字,如$Proxy). 对这个调用的方法都会转为调用代理对象处理器的 invoke方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Random;

/**
* 代理
*/
public class ProxyTest {

public static void main(String[] args) {
Object[] elements = new Object[1000];

for(int i=0 ; i < elements.length; i++){
Integer value = i+1;
InvocationHandler handler = new TraceHandler(value);
elements[i] = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
}

//要查找的内容
Integer key = new Random().nextInt(elements.length) + 1;

//查找
int result = Arrays.binarySearch(elements, key);

//把查找到的对象打印出来
if(result >= 0){
System.out.println(elements[result]);
}
}
}

//调用处理器
class TraceHandler implements InvocationHandler{
private Object target;

public TraceHandler(Object t){
target = t;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print(target);

System.out.print("." + method.getName() + "(");
if(args != null){
for(int i=0; i<args.length; i++){
System.out.print(args[i]);
if(i < args.length -1) System.out.print(",");
}
}
System.out.println(")");

return method.invoke(proxy, args);
}
}


[b]代理类的特性[/b]
代理类是在程序运行过程中创建的, 然而,一旦被创建,就变成常规类,与虚拟机中的任何其他类没有区别

所有的代理类都扩展Proxy类, 一个代理类只有一个实例域---调用处理器,它定义在Proxy的超类中.为了履行代理对象的职责, 所需要的任务附加数据都必须存储在调用处理器中.

所有的代理方法都一样, 这个方法仅仅调用了调用处理器的invoke. Object类中的其它方法(如clone和getClass没有被重新定义)

没有定义代理类的名字, sun虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名.

对于特定的类加载器和预设的一组接口来说, 只能有一个代理类, 也就是说, 如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话, 那么只能得到同一个类的两个对象 , 也可以利用getProxyClass方法获得这个类
Class proxyClass = Proxy.getProxyClass(null, interfaces);

代理类一定是public 和final . 如果代理类实现的所有接口都是public, 代理类就不属于某个特定的包, 否则,所有非公有的接口都必须属于同一个包. 同时, 代理类也属于这个包.

调用Proxy类中的isProxyClass方法检测一个特定的Class是否代理一个代理类.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值