`
polygoncell
  • 浏览: 55396 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

小心重写方法,正确实现多态

阅读更多

这是我今天在工作中碰到的问题,是关于继承和多态的。同事对项目中的一项基础功能进行了重构,可是当我们从CVS服务器上更新了项目源代码并编译了之后,发现这项功能已不能正常工作了。先撇开这个同事所犯的错误(对代码进行重构后没有测试他的新代码就上传到了CVS服务器上)不说,在这里我就说说这个问题所带出来的JAVA konwhow.

由于我们的项目比较复杂,我在这里采取比较简单的例子来讲解这个问题。首先,我们有2个类:supper.TestSupper.java 和sub.TestSub.java。他们的代码是这样的:

package supper;

public class TestSupper {    
    String getString()
    {
        return "This is supper class.";
    }
}
-----------------------------------
package sub;

import supper.TestSupper;

public class TestSub extends TestSupper {
  public String getString(){
        return "This is sub class.";
    }
}

十分简单,第一眼看上去,你会觉得TestSub继承了TestSupper并且重写getString()方法。
现在我们写一个测试程序:
package supper;

import sub.TestSub;

public class Test {
    public static void main(String[] args) {
        TestSupper test = new TestSub();
        System.out.println(test.getString());
    }
}

请注意啊!测试程序和TestSupper在同一个包里。从理论上说,这个测试程序应该输出“This is sub class”,因为test的实体是一个TestSub对象而不是TestSupper。所以,当我们调用test.getString()时,真正被调用的应该是TestSub里的getString()。可是事实如何呢?输出是"This is supper class."!为什么会这样的?

原因很简单,因为在TestSupper里方法getString()的标签(signature)是"default",是默认的不用写出来。这导致这个方法只能在这个包里面可见。TestSub虽然继承了TestSupper,却没有办法“看见”getString()方法,因为TestSub在另外一个包里。所以当我们在测试程序里调用test.getString(),程序首先会寻找TestSub中是否重写了这个方法,在这里请一定要注意标签是default的,当然是没有发现。结果程序就会调用父类的相应方法,故父类中的结果就被输出了。

解决的办法很简单,但凡是要被重写的方法一定不能定义成“default”,最少要定义成"protected”.

如果你是在使用Eclipse的话,你可以在eclipse中进行设置,把这种情况视为Error就可以避免这种错误的产生。
方法是:window ->preferences -> style ->methods overridden but not pachage visible这项选为Error。我用的是eclipse3.0。

后话
别看这是个很小的问题,而且很简单,一看就明白,可是当系统出现了问题,而你要在几百个类中寻找到问题所在的时候,这种不易察觉的错误绝对是致命的。寻找这个错误花了我们2个人天!可怕吧!

分享到:
评论

相关推荐

    src01 Object

    ### Java.lang.Object 类详解 #### 一、概述 在Java编程语言中,`java.lang.Object`类是所有类的根类。这意味着每一个类都直接或间接地继承...此外,了解如何适当地重写这些方法对于实现定制化的行为也是必不可少的。

    提高C#编程水平不可不读的50个要诀.txt

    覆写基类的方法是实现多态的关键。通过覆写,子类可以提供针对特定上下文的实现,从而增强程序的灵活性和可扩展性。 #### 17. 使用委托进行回调 委托是一种引用方法的类型,可用于实现回调机制。通过委托,可以将...

    Java编写中容易搞错的一些东西.rar

    如果比较的是对象,"=="只是检查两个引用是否指向同一个实例,而equals()默认行为也是这样,但可以通过重写来实现特定的比较逻辑。 5. **数组与集合的区别**:数组长度固定,一旦创建不能更改,适合存储固定数量的...

    c++试题,欢迎学习

    当一个基类中的成员函数被声明为`virtual`时,其派生类可以重写这个函数来提供不同的实现。这样,在通过基类指针或引用调用该成员函数时,实际执行的是指向的对象所属类型的函数版本,从而实现了动态绑定。 - **...

    C++99个常见错误

    9. **多态与虚函数**:如果要实现多态,记得声明至少一个虚函数。不声明虚函数会导致无法调用派生类的重写方法。 10. **异常处理**:不妥善处理异常可能导致程序崩溃。考虑使用`try-catch`来捕获和处理异常。 11. ...

    Java语言的26个细节

    Java中的`equals`方法是用于对象比较的核心方法,其正确实现至关重要。Java规范中定义了`equals`方法应遵循的五项基本原则:自反性、对称性、传递性、一致性以及非空性。然而,即使遵循这些原则,重写`equals`方法时...

    C++面试常见问题

    1. **封装**:将数据和操作数据的方法捆绑在一起,对外隐藏内部实现细节。 2. **继承**:支持类之间的继承关系,可以重用和扩展已有类的功能。 3. **多态**:通过继承和虚函数机制,同一个接口可以表示多种不同的...

    c++经典例题

    虚函数允许子类重写父类的行为,当使用指针或引用调用虚函数时,实际上调用的是指向或引用的派生类对象的方法,而非基类的方法。 ### 9. 抽象类与纯虚函数 抽象类是一种包含至少一个纯虚函数的类,不能实例化。...

    搜狗2013校园招聘研发类笔试题高清扫描版

    通过这种方式,可以通过指向基类的指针调用派生类中的重写版本,实现了运行时多态。 ### 内存管理 #### 1. 动态内存分配 题目中的一个例子是在主函数中使用`new`操作符动态创建了一个`Child`类的对象,并通过一个...

    ocaml reference manual

    - **多态**:通过虚拟方法实现多态性,允许子类重写父类的方法。 **3.6 私有方法** - **封装**:通过私有方法来隐藏对象内部的实现细节。 **3.7 类接口** - **接口定义**:类似于签名,用于定义类提供的公共方法...

    南京大学软件学院c++试题

    - **一般虚函数**: 可以提供默认实现,派生类可以选择重写。 - **非虚函数**: 接口和实现都必须继承,不能被覆盖。 #### 七、C++程序设计的原则 1. **尽可能使用const**: 限制变量的修改,增加程序的可读性和安全...

    指针和引用的区别1

    C++的多态机制主要通过虚函数实现,它允许子类重写父类的方法,使得指向子类对象的父类指针能够调用子类的实现。虚函数必须在基类中声明,并且在派生类中可选地重新定义。这样,即使在不知道对象实际类型的情况下,...

    知名IT公司C++经典面试题

    当一个类的成员函数被声明为`virtual`时,该函数可以在派生类中重写,从而实现运行时的多态。这意呸着在运行时,可以通过基类指针或引用调用派生类的成员函数,而不是编译时确定的函数版本。 - **虚函数**:在基类...

    C++新手笔记

    这是实现多态和回调功能的强大工具。 #### vector `vector<bool>`是一个特例,它的行为不同于其他类型的`vector`。为了节省空间,它使用位级存储,但这导致了一些非直观的行为,比如迭代器的行为。 #### iterator...

    Python3里的super()和__class__使用介绍

    现在,如果我们想定义一个新的类C,它继承自B,并且想使用A中的方法m而不是B中重写的版本,我们可以使用`super()`来实现这一点,因为`super()`会遵循Python的MRO来找到并调用正确的方法。例如: ```python class A:...

    (转)一个优秀的C++学习笔记

    - **普通虚拟函数**:允许子类重写父类的方法,实现多态。 - **纯虚函数**:必须在派生类中实现,否则派生类也将成为抽象类。 - **重载函数**:允许在同一作用域内定义多个同名函数,但参数列表必须不同。 - **...

    30道 C++ 常见面试题

    - **多态**:允许子类对象被当作父类对象使用,即同一接口可以有不同的实现。 #### 4. 子类析构时是否要调用父类的析构函数? - **答案**:是的,子类析构时通常需要调用父类的析构函数。这通常通过将父类的析构...

    C/C++笔试题

    用于实现方法的多态性。 - **重写(Overriding)**:子类重新定义父类中的方法。用于实现继承中的多态性。 #### 19. 静态成员变量 静态成员变量属于整个类,而不是类的某个实例。这意味着所有对象共享同一个静态...

Global site tag (gtag.js) - Google Analytics