arraylist中add方法签名如下:
public boolean add(Object o)我使用内部匿名类继承了arraylist并重写了其add方法,代码如下:(在arraylist上附加的功能很简单,就是我向arraylist中添加VO对象、添加时我根据添加新对象newer的Key属性判断、如果集合中已有这个Key的旧对象older则比较newer和older的Id,仅保留Id较大者,较小者如果是newer则不予添加如果是older则将其剔除)
ArrayList mylist = new ArrayList(){
private HashMap myUil = new HashMap();
public boolean add(Object o){
VO newer = (VO)o;
VO older = (VO)myUil.get(newer.getKey());
if(older!=null){
if(newer.getId()>older.getId()){
myUil.remove(older.getKey());
this.remove(older.getKey());
}else return false;
}
myUil.put(newer.getKey(), newer);
return super.add(newer);
}
public void remove(String Key){
Iterator e = iterator();
int i = 0;
    while (e.hasNext()) {
     VO older = (VO)e.next();
if (older.getKey().equals(Key)) {
    super.remove(i);
    return;
}
i++;
    }
}
public String toString(){
return "myUil.size()=" + myUil.size() + "@list.size()=" + super.size();
}
};
以上代码工作正常,但是我觉得在add方法中接收Object参数我还得转成VO对象太麻烦,所以把add方法签名直接改为:
public boolean add(VO newer)
并将强制转换:VO newer = (VO)o; 去掉了,但是这样改以后在调用mylist.add(VO vo)方法的时候直接去调了父类也就是arraylist的add方法,导致我附加的功能失效。想来想去想不明白原因,比较郁闷,我觉得即使是:public boolean add(VO newer)这样的方法声明返回类型一样传参一样(VO类型也是Object啊)应该是重写了父类arrayist的add方法无疑啊,怎么会不认???

解决方案 »

  1.   

    我试了,没你说的失效情况阿。
    public class Main {

    public static void main(String[] args)
    {
    Mylist list = new Mylist();
    list.add(new MyObject());
    } }
    class Mylist extends ArrayList{ public boolean add(MyObject o)
    {
    System.out.println(o.i);
    return super.add(o);

    }
    }
    class MyObject{
    public int i = 10;
    }
    上面的程序会打印10阿。
    除非像下面这样,才会调原来的方法,什么都不打印阿:
    public class Main {

    public static void main(String[] args)
    {
    Mylist list = new Mylist();
    list.add((Object)new MyObject());
    } }
    class Mylist extends ArrayList{ public boolean add(MyObject o)
    {
    System.out.println(o.i);
    return super.add(o);

    }
    }
    class MyObject{
    public int i = 10;
    }
      

  2.   

    重写必须参数类型一样
    你那么写肯定不是重写原来可以传递进所有Object类型及其子类型的
    现在传递的只能是VO类型的
    怎么可能是重写了呢?
      

  3.   

    如果你用eclipse开发那你在你的类里面写两个方法 public boolean add(Object o) {
    return true;
    }

    public boolean add(String o) {
    return true;
    }
    你会很明显的看到第一个方法左边有个绿色的裤衩,跟你的三个小裤衩一样的,呵呵,把鼠标移动过去看看说明是什么
    overrides java.util.ArrayList 
    第二个就没有因此从这个方面看也能看出第二个方法根本不是重写
      

  4.   

    改用1.5jdk就没有这个问题了class Mylist extends ArrayList<VO>{
        public boolean add(VO o){
            
            return super.add(o);
        }
    }class VO{
        
    }
      

  5.   

    hh:你说的是真的假的,我这里怎么就不行呢?回头试试你的。李逵:我靠你说的是真的耶,eclipse自动识别override,override是重写,否则就是重载。我的概念里面覆盖就是重写也可以叫覆写、你的概念里面把重载当成了覆盖:
    public boolean add(Object o) {——这应该叫重写
            return true;
        }
    public boolean add(String o) {——这应该叫重载
            return true;
        }
    不过即使是重载也应当可以正常工作的,这个倒和重写、重载概念无关。既然我是重载方法,那更应该识别。
    楼上的高手:为什么改用1.5jdk就没有这个问题了?这是jdk的bug么?
      

  6.   

    楼上的高手:class   Mylist   extends   ArrayList <VO > 这种写法是传说中的泛型么?
      

  7.   

    如果hh说的是真的,那么说明java匿名类有这个bug、因为你用的是普通内部类、我用的是内部匿名类。
      

  8.   

    楼主好可爱,eclipse一直都有这个功能啊!记得netbeans也有,jb没用过不清楚。关于术语翻译的问题:相信是李逵搞错了。一般的中英文对照如下:override -> 重写,覆写,覆盖
    overload -> 重载基本上没有把overload译做“重写”的。to 楼主:java 1.5加入了泛型机制,自动识别元素类型。比如非泛型环境下的代码如下:List list = new ArrayList();
    list.add("Hello");
    list.add("world");
    list.add(new Integer(100));   // 这行代码工作正常Iterator it = list.iterator();
    while(it.hasNext()) {
      String s = (String) it.next();   // 但是这里会出错,因为new Integer(100)不是String
      // do something with s
    }泛型环境下的等价代码则是:List<String> list = new ArrayList<String>();
    list.add("Hello");
    list.add("world");
    // list.add(new Integer(100));   // 这行代码将不能编译,因为list被限制为只能存放String对象Iterator<String> it = list.iterator();   //这里得到的迭代器也是String元素的迭代器
    while(it.hasNext()) {
      String s = it.next();   // 由于编译器确保了集合里的元素都是String,这里就不再存在强制转型了
      // do something with s
    }可以看到,泛型机制作用下,程序的可靠性和可理解性都更高。
      

  9.   

    楼主的问题是个最基本的方法覆盖问题,和是否匿名内部类无关。
    子类中的方法和父类中被覆盖的方法签名一定要精确一致,不存在什么用参数类型的子类型去覆盖的这种做法。p.s. 不要动不动就怀疑java会有这样那样的bug,如果是那样的话,java早就不存在了。import java.util.*;
    public class Test {
    void f() {
    ArrayList mylist = new ArrayList() {   // 匿名内部类
    public boolean add(String s) {
    return true;
    }
    };
    }

    class MyArrayListInner extends ArrayList {   // 内部类
    public boolean add(String s) {
    return true;
    }
    }

    }class MyArrayList extends ArrayList {   // 普通类
    public boolean add(String s) {
    return true;
    }
    }上面的代码中没有一个add()方法可以覆盖ArrayList中的add()。
      

  10.   

    谢谢,那么我写的add方法签名: public   boolean   add(VO   newer) 应该是对arraylist中add方法的一种重载。
    重载的概念更明确,那为什么我调用mylist.add(VO vo)方法的时候直接去调了父类也就是arraylist的add方法?
    bug挺正常,jsk1.4中在某些机器上使用String.split()方法不正常就是bug。
    我试试hh写的代码先。
      

  11.   

    因为你的mylist的持有者是ArrayList 
    而不是你所写的匿名类
    而这时 mylist是看不到 也 无法知道 你有add(Vo vo)的方法存在 
    (你用eclipse的时候  代码自动完成的时候你就可以看到 mylist只能.add(Object o))
    所以在方法绑定的时候mylist 会绑定ArrayList的add(Object o)
    然后采用动态绑定到你的匿名类
    你可以在
    匿名类中加
    public       boolean       add(Object      newer)
    {
       if(newer instanceof VO)
          this.add(newer);
       else
          super.add(newer);
    }这样在调用 mylist.add() 的时候就会动态绑定到子类的add(Object newer)
    然后 再具体分发到方法
      

  12.   

    对不起,可能我前面没仔细分析楼主的问题。下面是我重新写的测试代码:
    import java.util.*;
    public class Test {

    ArrayList mylist = new ArrayList() {   // 匿名内部类
    public boolean add(VO v) {
    System.out.println("A VO has been added.");
    return true;
    }
    };

    class MyArrayListInner extends ArrayList {   // 内部类
    public boolean add(VO v) {
    System.out.println("A VO has been added.");
    return true;
    }
    }

    public boolean myAdd(VO v) {
    // mylist.add(v);    // 若使用这句则不能打印"A VO has been added."
    new MyArrayListInner().add(v);   // 使用这句可以
    return true;
    }    // 初步结论是,匿名内部类中的方法不能实现重载

    public static void main(String[] args) {
    new Test().myAdd(new VO());
    }}class VO {
    }运行上例可以看出,匿名内部类中的方法确实不能正确实现重载,至于这是一个bug还是一个限制性的规定,还无法下结论。
    至少,我在eclipse中运行该例时,eclipse给出了警告,提醒我匿名内部类中的add(VO v)方法没有被调用,所以,这很可能是匿名内部类固有的一个局限。
    谢谢楼主的发现。
      

  13.   

    纠正一下 上面个写错的地方public               boolean               add(Object             newer) 

          if(newer   instanceof   VO) 
                this.add((VO)newer); 
          else 
                super.add(newer); 
      

  14.   

    啊,刚刚看了楼上insiku的回复,豁然开朗了。谢谢~~~~~ 
      

  15.   

    不要动不动就bug
    这么容易就让你发现bug 
    那sun的开发人员不是太垃圾了?
      

  16.   

    谢谢“别给我分”替我做的测试。TO: tmd越学越弱不懂的太多了
    我还不是很懂你说的意思,你说的是在编译后发生的事情,我疑惑的是为什么到了运行时仍然会有问题。你说的引用类型的问题是编译后的问题,到了运行时即使是匿名内部类jre也应该识别正确的引用类型——那就是子类——这才叫动态绑定、否则还谈什么多态?我的代码说明匿名内部类对父类方法重写可以重载就不行这是不对的,既然重写的方法可以在运行时动态绑定到子类方法为什么重载的就绑定不到?给人的感觉是编译器和jre不一致。都是内部类、匿名不匿名不应该影响行为。对于引用类型使用父类和使用子类这种情况在.net中有所改进,.net做了明确的语法语义区分:在写父类的时候可以用override修饰字来修饰方法表示该方法可以由子类重写、在写子类的时候可以直接重写这个方法也可以用new(此new非彼new)修饰字来修饰这个方法、new修饰字表示子类重新定义了这个方法而不重写父类方法。这么做以后在你使用这对父子类的时候如果用子类类型引用来接收对象则调用子类方法、如果用父类类型引用来接收对象则调用父类方法、互不影响。这一点在java中我还不知道能不能实现、也简单、做个测试就知道。“匿名内部类的实例不可能拥有自己的类型,而永远都是父类的类型。”——这不是真理,只是编译器的局限。
      

  17.   

    “给人的感觉是编译器和jre不一致。”——不应该这么说、应该说编译器和jre在内部匿名类上犯同一个错误。都是内部类匿名和不匿名的行为不一致!
      

  18.   

    呵呵。本以为楼主是来结贴的。没想到你还是没明白。首先,你应该明白一个基本常识:对象向上转型以后,会隐藏其父类中没有的接口(公共方法)。
    举例:class Base {
    void f() { }
    }class Inherited extends Base {
    void f() { }
    void g() { }
    }public class Test {
    public static void main(String[] args) {
    Inherited i1 = new Inherited();
    i1.f(); // 没有问题
    i1.g(); // 也没有问题 Base i2 = new Inherited();
    i2.f(); // 没有问题
    i2.g();   // 编译错误!无法访问g(),应为i2向上转型为Base,而g()不是Base的接口之一,从而被隐藏。
    }
    }现在回到匿名内部类。
    举例:import java.util.*;
    public class Test {
    public static void main(String[] args) {
    class ArrayListInner extends ArrayList {
    void f() { }
    }
    ArrayListInner list1 = new ArrayListInner();

    ArrayList list2 = new ArrayList() {
    void f() { }
    };

    // list1是一般内部类的实例,而list2是匿名内部类的实例

    list1.f();  // 可以访问f()
    list2.f();  // 编译错误!不可以访问f()
    }
    }上面的原因很明显。list2被声明为ArrayList类型,但f()并不是ArrayList的接口,所以被隐藏了。而list1是ArrayListInner类型的,具有ArrayListInner类的所有接口,包括f()。对于list2,你无法将它声明为它的“直接类”的类型,这是因为这个“直接类”是没有名字的。这不是什么语言或编译器的局限,这是匿名内部类本身的局限,或者更准确地说,是它的一个特点。不知楼主这下是否明白了。
      

  19.   

    你用了匿名内部类
    所以声明的时候得用ArrayList(或者其父类/借口)这样,这个声明的引用怎么知道实现了public   boolean   add(VO   newer)的实现啊(它不知道它指向的是一个自定义的实现了public   boolean   add(VO   newer)的子类啊)
    ,所以匹配到了ArrayList中的public   boolean   add(Object  object)了
      

  20.   

    让我们抛开匿名的问题,看看如下最简单的代码:
    import java.util.*;
    public class TestTmd {
        
        class MyArrayListInner extends ArrayList {//内部类(其实内不内部类都一样)
            public boolean add(Object v) {——这样写可以打印(这是重写)
                   //public boolean add(VO v) {——这样写不会打印(这是重载、其实不应该这么做)             System.out.println("A VO has been added.");
                return true;
            }
        }
        
        public void myAdd(VO v) {
         ArrayList inner = new MyArrayListInner();
                    inner.add(v);
        }
        
        public static void main(String[] args) {
         new TestTmd().myAdd(new VO());
        }
    }
    class VO {}得出的结论是重写发生在父子类之间、而重载应该只在一个类内。谢谢大家帮我补习一下基础。
      

  21.   

    在用spring写框架代码的时候遇到过这个问题,未及整理。因为spring几乎全部是用父类甚至接口引用接收子类实例(由spring在运行时注入),这个问题其实与内部类无关,而是关于重写、重载的适用场景的。
    基础很重要、今天再次固本培源,分大家均分。
      

  22.   

    顶“别给我分”的结论
     public boolean myAdd(VO v) {
            // mylist.add(v);    // 若使用这句则不能打印"A VO has been added."
            new MyArrayListInner().add(v);   // 使用这句可以
            return true;
        }    // 初步结论是,匿名内部类中的方法不能实现重载
    我有如下代码测试:package alltest;import java.util.ArrayList;class Vo{

    }@SuppressWarnings("serial")
    public class ArrayListTest {

    static ArrayList<Vo> list = new ArrayList<Vo>(){
                    @Override
    public boolean add(Vo v){
    System.out.println("my add method overload");
    return true;
    }
    }; public static void main(String[] args) {
    Vo o = new Vo();
    list.add(o);
    }}OutPut:
    my add method overload注:JDK1.5
    真的不能重载吗?上面的例子只能证明可以Override
    声明为范性也是Override不是OverLoad我采用JDK1。5以上的范性进行重写,对add,get进行重写,证明OverLoad:package alltest;import java.util.ArrayList;
    class Vo1{

    }@SuppressWarnings({ "serial", "unchecked" })
    public class ArrayListTest2 {

    static ArrayList<? extends Object> list = 
    new ArrayList<Vo1>(){

    @SuppressWarnings("unused")
    public boolean add(){
    System.out.println("My add Method is transfered");
    return true;
    }
    public void get(){
    System.out.println("My get Method is transfered");
    }
    };
    public static void main(String[] args) {
    /**
     * The method get(int) in the type 
     * ArrayList<capture#2-of ? extends Object> 
     * is not applicable for the arguments ()
     */
    list.add();  //报错,无法使用
    list.get();  //报错,无法使用

    }
    }
    结论:匿名内部类不能重载,至于什么原因,愿听高手解答!!
      

  23.   

    ...................................to
    GODProbe 
    重载是没有动态绑定的  
    回去研究下方法调用的相关过程就知道了
    to
    sharpyuce 
    不是不能重载  只是你的匿名类对象的持有者是其父类
    其父类的方法表中 不存在你所新添加的方法 所以当然不允许你调用
    另: 不要把所有的警告都@SuppressWarnings 掉   这是不好的习惯
    例:class A
    {
       public void methodA()
       {}
    }class B extends A
    {
       public void methodA()
       {}   public void methodB()
       {}
    }class C extends A
    {
       public void methodA()
       {}
       
       public void methodC()
       {}
    }public void testMethod(A a)
    {
       a.methodA();    //  row 1
       a.methodB();    //  row 2
       a.methodC();    //  row 3
    }以上为大概的类结构
    row 1   row 2   row 3 的写法正确吗?row 2   row 3 肯定是错的
    虽然你传给testMethod(A a)方法的参数可能是B对象 或者 是C对象
    其内部确实存在methodB() 或者 methodC() 方法
    但是参数的持有者是A 它不能保证你传过来的对象中一定存在methodB() 或者 methodC()如果再理解不了  那还是转行吧
      

  24.   

    对于引用类型使用父类和使用子类这种情况在.net中有所改进,.net做了明确的语法语义区分:在写父类的时候可以用override修饰字来修饰方法表示该方法可以由子类重写、在写子类的时候可以直接重写这个方法也可以用new(此new非彼new)修饰字来修饰这个方法、new修饰字表示子类重新定义了这个方法而不重写父类方法。这么做以后在你使用这对父子类的时候如果用子类类型引用来接收对象则调用子类方法、如果用父类类型引用来接收对象则调用父类方法、互不影响。==================MS的设计师的口味果然与众不同
      

  25.   

    匿名内部类连类名都没有。怎么去让他以自己本身的引用,来生成对象啊
    只能是父类或者接口的引用,来生成对象
    @SuppressWarnings("unused")
    是没有被使用而出的警告;
    @SuppressWarnings("serial")
    是没有生成其序列ID而出的警告;
    大哥这2种注释 貌似有什么大哎吗?static ArrayList<? extends Object> list = 
            new ArrayList<Vo1>(){
                ..........................
             };你不以ArrayList或者更广的类型的引用来得到这个对象,(我们这里讨论的是匿名内部类)你说怎么得到对象,这个对象连类名都没有,何来他本类的引用??不能得到他自己的类的引用来生成自身对象,怎么调用他的重载方法,本人比较蠢,没听说过。。
    还请楼上的高手请解答?或者你写一个匿名内部类可以重载的例子,只要能写出来,我就服!写不出来,还请大哥以后发贴时,思考下再反驳人家的观点
      

  26.   

    “to GODProbe 重载是没有动态绑定的 回去研究下方法调用的相关过程就知道了”——不必研究,想想不就知道?重载就没有必要动态绑定。你说的方法调用相关过程是个什么过程?好人做到底,大牛、继续启蒙启蒙我们这帮菜鸟啊。to:蠢人学编程
    ——我的代码有点陷阱在里面,可能会误导你。没仔细看你的回帖,但是我的代码的问题和内部类无关、和匿名内部类也无关,纯粹是关于重写、重载的适用场景的。你要是混淆进匿名内部类的概念很容易搞混乱。“tmd越学越弱不懂的太多了”没有走过这个陷阱所以他显得不那么弱智。
    我的结论是重写发生在父子类之间、而重载应该只在一个类内。其实这是一个初学java时的基础,不过学java的过程好像就是这样,刚开始学的面向对象、基本语法、多线程等等看似基础的东东才是做一个架构师必须深刻理解并反复实践的,反而是后来的jsp、struts、spring...就是个工具。
      

  27.   

    to sharpyuce 
    什么叫不可以重载?
    不能通过编译那叫不可以
    只不过对父类的持有者隐藏了重载的方法  这叫不可以重载?
    只不过不能调用而已完全可以通过别的方法来达到重载的目的class A
    {
       public void methodA(Object o)
       {}
    }A a = new A
    {
       public void methodA(Object o)
       { 
          if(o instanceof String)
             methodA((String)o);
          else if(o instanceof Integer)
             methodA((Integer)o);
          else
             super.methodA(o);
       }   public void methodA(String s)   //是不是重载出来的?   3个methodA的存在 难道不是重载???
       {
       }   public void methodA(Integer i) //是不是重载出来的?  只不过你不能直接调用而已 
       {
       }
    };
      

  28.   

    楼主的问题貌似在这里:ArrayList   mylist   =   new   ArrayList(){ 
      

  29.   

    to:蠢人学编程
    如果你的jdk1.5的测试代码真的输出那个结果:
    import java.util.ArrayList;
    class Vo{}
    @SuppressWarnings("serial")
    public class ArrayListTest {
        static ArrayList<Vo> list = new ArrayList<Vo>(){
                    @Override
            public boolean add(Vo v){
                System.out.println("my add method overload");
                return true;
            }
        };
        public static void main(String[] args) {
            Vo o = new Vo();
            list.add(o);
        }
    }
    OutPut:
    my add method overload
    看来sun的工程师用泛型改进了这个问题。
    “tmd 越学越弱 不懂的太多了”可能会说:sun的设计师的口味果然与众不同
      

  30.   

    /*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package test5;import java.util.ArrayList;
    import java.util.List;/**
     *
     * @author hadeslee
     */
    public class Test1 {
        public Test1() {    }
        public static void main(String[] args) throws Exception {
                List<Test1> list=new ArrayList<Test1>(){
                    public boolean add(Test1 t){
                        System.out.println("添加了:"+t);
                        return super.add(t);
                    }
                };
                Test1 t=new Test1();
                list.add(t);
                
        }
    }
      

  31.   

    GODProbe 莫非你认为sun用泛型来修正了这个所谓的bug?
    泛型的加入根本就没有破坏java的原有体系 完全的无缝
    ms的设计师的设计 完全就是为了满足个人便利