站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2SE 专题【高分求教】一个关于反射Proxy类的问题

【高分求教】一个关于反射Proxy类的问题

摘要: 【高分求教】一个关于反射Proxy类的问题


看《core java》中介绍Proxy类,我也试着照着例子自己做了一个程序,算作对java基础阶段学习的总练习。(以后就要开始学习图形界面swing了)


下面是我的代码,比较长,请大家最好还是考到机器上试试吧,分不够再给。:)


import java.util.*;
import java.lang.reflect.*;

public class MainClass {

public static void main(String[] arg){

new MainClass();
}

public MainClass(){

Object[] r = new Object[3];
r[0] = Proxy.newProxyInstance(null, Rechnung.class.getInterfaces(),
new Detect(new Rechnung(new GregorianCalendar(2006, 9, 3), -#34;Brot-#34;, 99.69)));
r[1] = Proxy.newProxyInstance(null, Rechnung.class.getInterfaces(),
new Detect(new Rechnung(new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26)));
r[2] = Proxy.newProxyInstance(null, Rechnung.class.getInterfaces(),
new Detect(new Rechnung(new GregorianCalendar(2006, 9, 4), -#34;Gebuhr-#34;, 120)));

//Arrays.sort(r); 这里不行,会出错!
System.out.println(Arrays.binarySearch(r, new Rechnung(new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26))); // 用binarySearch可以,真是奇怪!

}

private class Detect implements InvocationHandler{

public Detect(Object target){
this.target = target;
}

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

System.out.println(this.target.getClass().toString()+-#34;: -#34;+method.getName()); // 拦截函数调用
return method.invoke(this.target, args);
}
private Object target;
}

}


// 练习Class的几个常用函数:toString(), equals(), hashCode(), clone(), compareTo()

class Rechnung implements Cloneable, Comparable-#60;Rechnung-#62;{

public Rechnung(GregorianCalendar data, String name, double preis){
this.data = data;
this.name = name;
this.preis = preis;
}

@Override public String toString(){
return String.format(-#34;Die Rechnung ist: Date %d, Name %s, Preis %f-#34;,
new Object[]{this.data.get(Calendar.DAY_OF_MONTH), this.name, this.preis});

}

@Override public Rechnung clone() throws CloneNotSupportedException{

Rechnung result = (Rechnung)super.clone();
return result;
}

public int compareTo(Rechnung aRechnung){
// 通过日期来比较大小
if (this.data.before(aRechnung.data))
return -1;
if (this.data.after(aRechnung.data))
return 1;
return 0;
}

@Override public boolean equals(Object o){

if (o == null) return false;
if (this == o) return true;
if (o.getClass() == this.getClass()){
Rechnung r = (Rechnung)o;
return (r.data.equals(this.data) -#38;-#38;
r.name.equals(this.name) -#38;-#38;
r.preis == this.preis);
}
return false;
}

@Override public int hashCode(){

return (11 * this.data.toString().hashCode() +
13 * this.name.hashCode() +
17 * (int)Math.round(this.preis));
}

private GregorianCalendar data;
private String name;
private double preis;
}


如果将注释去掉,错误提示如下:

class Rechnung: compareTo
Exception in thread -#34;main-#34; java.lang.reflect.UndeclaredThrowableException
at $Proxy0.compareTo(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at MainClass.-#60;init-#62;(MainClass.java:22)
at MainClass.main(MainClass.java:9)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at MainClass$Detect.invoke(MainClass.java:37)
... 5 more
Caused by: java.lang.ClassCastException: $Proxy0
at Rechnung.compareTo(MainClass.java:1)
... 10 more



关注


我用jdk5.0调试没有任何问题啊!你用的是不是jdk1.42
运行结果为;class Rechnung: compareTo
1



恩,我用jdk1.5也可以


啥问题?


不是的,大家没有理解我的意思,我用的也是jdk5,运行也没有问题,那是因为我把有问题的语句给注释掉了。。。大家试试:

//Arrays.sort(r); 这里不行,会出错!
System.out.println(Arrays.binarySearch(r, new Rechnung(new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26))); // 用binarySearch可以,真是奇怪!

改成

Arrays.sort(r); 这里不行,会出错!
// System.out.println(Arrays.binarySearch(r, new Rechnung(new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26))); // 用binarySearch可以,真是奇怪!

就不行了,同样的设计,为什么binarySearch没问题,到了sort就出问题了?我想问的就是这个。两者不是都调用了compareTo()吗?谢谢


public int compareTo(Rechnung aRechnung){
。。。
}
你把它改为public int compareTo(Object obj){
if(obj instance of Rechnung){
Rechnung aRechnung = (Rechnung)obj;
}else{
//throw exception??
}
...
}
试试!应该是这个地方出的错,类转换报错!-:)


呵呵,还有一点就是,Arrays.sort(Object[])方法会调用clone方法,而binarySearch则不会,你再检查一下clone的实现,本人没使用过jdk1.5。


嗯,sort中的clone也是数组的clone,应该不会有影响的。看来,还是compareTo中的问题。


kuangjz(阿旷) 指出的问题的点是对的,但修改方案好像行不通。因为使用了泛型,在 Rechnung 已经不能再定义 public int compareTo(Object obj) 了,只能定义 public int compareTo(Rechnung aRechnung)。


由于proxy产生的代理类是实现Rechnung的所有接口的类,但它不是Rechnung的子类,因此,compareTo报错就是肯定的了,解决方案,将Rechnung声明为接口。


在 Arrays.sort() 的执行过程中,会调用 obj1.compareTo(obj2),其中 obj1 是 Rechnung 对象(其实原本也是代理对象,但在你的 Detect.invoke 中被调换成 this.target 了),而 obj2 是代理对象,从而产生 ClassCastException。

在 Arrays.binarySearch() 中,虽然也调用了 obj1.compareTo(obj2),但其中的 obj2 是一个天生的 Rechnung 对象,所以不会出错。

解决的办法是,自己定义一个 interface,让代理对象能够实现这个 interface,通过这个 interface 实现你需要的比较功能。下一个帖子我会给出我修改后的程序代码。


几处修改:
1. 定义了 interface IRechnung extends Comparable-#60;IRechnung-#62;,通过它实现比较功能;
2. 把 Proxy.newProxyInstance() 的第一个参数改成 MainClass.class.getClassLoader()。唯一的原因是我不想在另一个 .java 里写 IRechnung 了;
3. 去掉了其它一些跟这个问题不直接相关的代码,使得看起来清楚一点。

package test;

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

public class MainClass {

public static void main(String[] arg) {
new MainClass();
}

public MainClass() {
Object[] r = new Object[3];
r[0] = Proxy.newProxyInstance(MainClass.class.getClassLoader(), Rechnung.class.getInterfaces(), new Detect(new Rechnung(
new GregorianCalendar(2006, 9, 3), -#34;Brot-#34;, 99.69)));
r[1] = Proxy.newProxyInstance(MainClass.class.getClassLoader(), Rechnung.class.getInterfaces(), new Detect(new Rechnung(
new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26)));
r[2] = Proxy.newProxyInstance(MainClass.class.getClassLoader(), Rechnung.class.getInterfaces(), new Detect(new Rechnung(
new GregorianCalendar(2006, 9, 4), -#34;Gebuhr-#34;, 120)));

Arrays.sort(r); //这里已经不会出错了 :)
System.out.println(Arrays.binarySearch(r, new Rechnung(new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26)));
}

private class Detect implements InvocationHandler {
public Detect(Object target) {
this.target = target;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(this.target.getClass().toString() + -#34;: -#34; + method.getName()); // 拦截函数调用
return method.invoke(this.target, args);
}

private Object target;
public Object getTarget() { return target; }
}
}

// 练习Class的几个常用函数:toString(), equals(), hashCode(), clone(), compareTo()
interface IRechnung extends Comparable-#60;IRechnung-#62; {
public GregorianCalendar getData();
}

class Rechnung implements Cloneable, IRechnung {
public Rechnung(GregorianCalendar data, String name, double preis) {
this.data = data;
this.name = name;
this.preis = preis;
}

@Override
public Rechnung clone() throws CloneNotSupportedException {
Rechnung result = (Rechnung) super.clone();
return result;
}

public int compareTo(IRechnung aRechnung) {
// 通过日期来比较大小
if (this.data.before(aRechnung.getData()))
return -1;
if (this.data.after(aRechnung.getData()))
return 1;
return 0;
}

private GregorianCalendar data;
private String name;
private double preis;

public GregorianCalendar getData() { return data; }
}



package csdn.basic;

import java.util.*;
import java.lang.reflect.*;

public class MainClass {

public static void main(String[] arg) {

new MainClass();
}

public MainClass() {

Object[] r = new Object[3];
r[0] = Proxy.newProxyInstance(null, Rechnung.class.getInterfaces(),
new Detect(new Rechnung(new GregorianCalendar(2006, 9, 3),
-#34;Brot-#34;, 99.69)));
r[1] = Proxy.newProxyInstance(null, Rechnung.class.getInterfaces(),
new Detect(new Rechnung(new GregorianCalendar(2006, 9, 1),
-#34;Bier-#34;, 1.26)));
r[2] = Proxy.newProxyInstance(null, Rechnung.class.getInterfaces(),
new Detect(new Rechnung(new GregorianCalendar(2006, 9, 4),
-#34;Gebuhr-#34;, 120)));
//String s = (String) new Object();
Arrays.sort(r); //这里不行,会出错!
System.out.println(Arrays.binarySearch(r, new Rechnung(
new GregorianCalendar(2006, 9, 1), -#34;Bier-#34;, 1.26))); // 用binarySearch可以,真是奇怪!

}

private class Detect implements InvocationHandler {
private Object target;

public Detect(Object target) {
this.target = target;
}

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

System.out.println(this.target.getClass().toString() + -#34;: -#34;
+ method.getName()); // 拦截函数调用
return method.invoke(this.target, args);
}

}

}

// 练习Class的几个常用函数:toString(), equals(), hashCode(), clone(), compareTo()

class Rechnung implements Cloneable, Comparable-#60;Object-#62; {

public Rechnung(GregorianCalendar data, String name, double preis) {
this.data = data;
this.name = name;
this.preis = preis;
}

@Override
public String toString() {
return String.format(-#34;Die Rechnung ist: Date %d, Name %s, Preis %f-#34;,
new Object[] { this.data.get(Calendar.DAY_OF_MONTH), this.name,
this.preis });

}

@Override
public Rechnung clone() throws CloneNotSupportedException {

Rechnung result = (Rechnung) super.clone();
return result;
}

public int compareTo(Object aRechnung) {
// 通过日期来比较大小
if (aRechnung instanceof Rechnung) {
Rechnung aRechnung1 = (Rechnung) (aRechnung);
if (this.data.before(aRechnung1.data))
return -1;
if (this.data.after(aRechnung1.data))
return 1;
}
return 0;

}

@Override
public boolean equals(Object o) {

if (o == null)
return false;
if (this == o)
return true;
if (o.getClass() == this.getClass()) {
Rechnung r = (Rechnung) o;
return (r.data.equals(this.data) -#38;-#38; r.name.equals(this.name) -#38;-#38; r.preis == this.preis);
}
return false;
}

@Override
public int hashCode() {

return (11 * this.data.toString().hashCode() + 13
* this.name.hashCode() + 17 * (int) Math.round(this.preis));
}

private GregorianCalendar data;

private String name;

private double preis;
}



maquan(-#39;ma:kju)读代码还是很仔细的!


hehe, 以前光看别人用 Proxy,自己没用过。这次借楼主这个题目,自己也学习一把 ^_^


interpb 这个方法恐怕不行吧。你这样虽然 compareTo() 不会报错了,但总是返回 0,已经没有比较的功能了。


关键是 动态代理生成的代理类不是被代理类的子类

所以比较的时候 实际上上几个代理类的对象在比较

不能按照被代理类的属性来比较

所以楼主用这个例子来研究动态代理不是很恰当


谢谢大家那么关注,那么认真帮我改代码。我刚才又仔细看了看,发现几个问题还是不太明白。

一个是关于binarySearch(),好像采用的是二分法查找把,可是这种算法必须对排好序的数组操作才行,为什么我看不到它其中有排序的算法或者调用了其他排序函数呢?

还有一个问题就是sort(),我发现代码中一开始就是一句:Object[] aux = (Object[])a.clone(); 我觉得就是因为它,才使得我的代码出了问题。现在我的问题是,这样算不算多态呢?

Object[] aux = (Object[])a.clone();与
Object[] aux = a.clone();两者之间是不是不一样?前者是截断,后者是多态?既然是截断,java这样设计又是为了什么?自定义类不能用Arrays.sort(),那Arrays.sort()难道只能给Object类数组排序吗?好奇怪的设计,Object[] aux = a.clone(); 不行吗? 谢谢。


binarySearch你需要仔细研究,sort中的clone方法只是对数组使用,clone的浅调用,就是说clone一个数组,但是数组中保存的是指向其它对象的指针,具体的对象并没有被clone,这是clone的深度调用方法,你可以查阅相关文档。clone方法返回的是Object,因此需要类型转换使用(Object[]),跟多态无关。


原来类反射还有这么多学问,学习了!


↑返回目录
前一篇: 我想在body的onload事件中写一个function,让页面上所有的表格里的数据都变成可编辑状态,怎么做啊??
后一篇: 请问什么是字符的宽度与高度?