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方法无疑啊,怎么会不认???
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方法无疑啊,怎么会不认???
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;
}
你那么写肯定不是重写原来可以传递进所有Object类型及其子类型的
现在传递的只能是VO类型的
怎么可能是重写了呢?
return true;
}
public boolean add(String o) {
return true;
}
你会很明显的看到第一个方法左边有个绿色的裤衩,跟你的三个小裤衩一样的,呵呵,把鼠标移动过去看看说明是什么
overrides java.util.ArrayList
第二个就没有因此从这个方面看也能看出第二个方法根本不是重写
public boolean add(VO o){
return super.add(o);
}
}class VO{
}
public boolean add(Object o) {——这应该叫重写
return true;
}
public boolean add(String o) {——这应该叫重载
return true;
}
不过即使是重载也应当可以正常工作的,这个倒和重写、重载概念无关。既然我是重载方法,那更应该识别。
楼上的高手:为什么改用1.5jdk就没有这个问题了?这是jdk的bug么?
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
}可以看到,泛型机制作用下,程序的可靠性和可理解性都更高。
子类中的方法和父类中被覆盖的方法签名一定要精确一致,不存在什么用参数类型的子类型去覆盖的这种做法。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()。
重载的概念更明确,那为什么我调用mylist.add(VO vo)方法的时候直接去调了父类也就是arraylist的add方法?
bug挺正常,jsk1.4中在某些机器上使用String.split()方法不正常就是bug。
我试试hh写的代码先。
而不是你所写的匿名类
而这时 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)
然后 再具体分发到方法
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)方法没有被调用,所以,这很可能是匿名内部类固有的一个局限。
谢谢楼主的发现。
{
if(newer instanceof VO)
this.add((VO)newer);
else
super.add(newer);
}
这么容易就让你发现bug
那sun的开发人员不是太垃圾了?
我还不是很懂你说的意思,你说的是在编译后发生的事情,我疑惑的是为什么到了运行时仍然会有问题。你说的引用类型的问题是编译后的问题,到了运行时即使是匿名内部类jre也应该识别正确的引用类型——那就是子类——这才叫动态绑定、否则还谈什么多态?我的代码说明匿名内部类对父类方法重写可以重载就不行这是不对的,既然重写的方法可以在运行时动态绑定到子类方法为什么重载的就绑定不到?给人的感觉是编译器和jre不一致。都是内部类、匿名不匿名不应该影响行为。对于引用类型使用父类和使用子类这种情况在.net中有所改进,.net做了明确的语法语义区分:在写父类的时候可以用override修饰字来修饰方法表示该方法可以由子类重写、在写子类的时候可以直接重写这个方法也可以用new(此new非彼new)修饰字来修饰这个方法、new修饰字表示子类重新定义了这个方法而不重写父类方法。这么做以后在你使用这对父子类的时候如果用子类类型引用来接收对象则调用子类方法、如果用父类类型引用来接收对象则调用父类方法、互不影响。这一点在java中我还不知道能不能实现、也简单、做个测试就知道。“匿名内部类的实例不可能拥有自己的类型,而永远都是父类的类型。”——这不是真理,只是编译器的局限。
举例: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,你无法将它声明为它的“直接类”的类型,这是因为这个“直接类”是没有名字的。这不是什么语言或编译器的局限,这是匿名内部类本身的局限,或者更准确地说,是它的一个特点。不知楼主这下是否明白了。
所以声明的时候得用ArrayList(或者其父类/借口)这样,这个声明的引用怎么知道实现了public boolean add(VO newer)的实现啊(它不知道它指向的是一个自定义的实现了public boolean add(VO newer)的子类啊)
,所以匹配到了ArrayList中的public boolean add(Object object)了
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 {}得出的结论是重写发生在父子类之间、而重载应该只在一个类内。谢谢大家帮我补习一下基础。
基础很重要、今天再次固本培源,分大家均分。
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(); //报错,无法使用
}
}
结论:匿名内部类不能重载,至于什么原因,愿听高手解答!!
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()如果再理解不了 那还是转行吧
只能是父类或者接口的引用,来生成对象
@SuppressWarnings("unused")
是没有被使用而出的警告;
@SuppressWarnings("serial")
是没有生成其序列ID而出的警告;
大哥这2种注释 貌似有什么大哎吗?static ArrayList<? extends Object> list =
new ArrayList<Vo1>(){
..........................
};你不以ArrayList或者更广的类型的引用来得到这个对象,(我们这里讨论的是匿名内部类)你说怎么得到对象,这个对象连类名都没有,何来他本类的引用??不能得到他自己的类的引用来生成自身对象,怎么调用他的重载方法,本人比较蠢,没听说过。。
还请楼上的高手请解答?或者你写一个匿名内部类可以重载的例子,只要能写出来,我就服!写不出来,还请大哥以后发贴时,思考下再反驳人家的观点
——我的代码有点陷阱在里面,可能会误导你。没仔细看你的回帖,但是我的代码的问题和内部类无关、和匿名内部类也无关,纯粹是关于重写、重载的适用场景的。你要是混淆进匿名内部类的概念很容易搞混乱。“tmd越学越弱不懂的太多了”没有走过这个陷阱所以他显得不那么弱智。
我的结论是重写发生在父子类之间、而重载应该只在一个类内。其实这是一个初学java时的基础,不过学java的过程好像就是这样,刚开始学的面向对象、基本语法、多线程等等看似基础的东东才是做一个架构师必须深刻理解并反复实践的,反而是后来的jsp、struts、spring...就是个工具。
什么叫不可以重载?
不能通过编译那叫不可以
只不过对父类的持有者隐藏了重载的方法 这叫不可以重载?
只不过不能调用而已完全可以通过别的方法来达到重载的目的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) //是不是重载出来的? 只不过你不能直接调用而已
{
}
};
如果你的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的设计师的口味果然与众不同
* 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);
}
}
泛型的加入根本就没有破坏java的原有体系 完全的无缝
ms的设计师的设计 完全就是为了满足个人便利