
本教程深入探讨java中方法重写(override)与多态(polymorphism)的核心概念。我们将通过实例代码演示如何正确地在父类和子类之间调用方法,并解释多态性在运行时行为中的作用。此外,文章还将解析“类型已定义”和nosuchmethoderror等常见的编译与运行时错误,提供排查思路和最佳实践,帮助开发者构建健壮的java应用。
Java中的方法重写 (Method Overriding)
方法重写是Java面向对象编程中的一个重要特性,它允许子类提供一个与父类中已有的方法具有相同名称、参数列表和返回类型(或其子类型)的实现。当子类对象调用这个方法时,执行的是子类中的实现,而不是父类的实现。
例如,考虑以下两个类:
package revision;
// 父类A
class A {
public void m() {
System.out.println("parent");
}
}
// 子类Prac2,继承自A并重写了m()方法
public class Prac2 extends A {
@Override // 推荐使用@Override注解,编译器会检查是否符合重写规则
public void m() {
System.out.println("child");
}
public static void main(String[] args) {
// 多态性示例
A obj1 = new Prac2(); // obj1是A类型引用,指向Prac2对象
Prac2 obj2 = new Prac2(); // obj2是Prac2类型引用,指向Prac2对象
obj1.m(); // 运行时调用Prac2的m()方法
obj2.m(); // 运行时调用Prac2的m()方法
}
}在上述代码中,Prac2类重写了A类的m()方法。在main方法中,无论obj1(类型为A但指向Prac2实例)还是obj2(类型为Prac2并指向Prac2实例),调用m()方法时,都会执行Prac2类中重写的m()方法,因此输出将是:
child child
这体现了Java的运行时多态性:具体执行哪个方法由对象的实际类型决定,而非引用类型。
立即学习“Java免费学习笔记(深入)”;
正确演示父子类方法调用
如果我们的目标是既调用父类的m()方法,又调用子类的m()方法,那么需要创建父类自身的实例。以下是实现这一目标的示例代码:
package revision;
class A {
public void m() {
System.out.println("parent");
}
}
public class Prac2 extends A {
@Override
public void m() {
System.out.println("child");
}
public static void main(String[] args) {
// 创建父类A的实例
A objParent = new A();
// 创建子类Prac2的实例,并用父类A的引用指向它(多态)
A objChildPoly = new Prac2();
// 创建子类Prac2的实例,并用子类Prac2的引用指向它
Prac2 objChildDirect = new Prac2();
System.out.println("--- 调用父类A的m()方法 ---");
objParent.m(); // 调用A类的m()方法
System.out.println("--- 通过父类引用调用子类Prac2的m()方法 ---");
objChildPoly.m(); // 调用Prac2类的m()方法 (多态)
System.out.println("--- 通过子类引用直接调用子类Prac2的m()方法 ---");
objChildDirect.m(); // 调用Prac2类的m()方法
}
}运行上述代码,将得到以下输出:
--- 调用父类A的m()方法 --- parent --- 通过父类引用调用子类Prac2的m()方法 --- child --- 通过子类引用直接调用子类Prac2的m()方法 --- child
这个示例清晰地展示了如何通过创建不同类型的对象实例来调用父类和子类中相应的方法。
常见编译与运行时错误解析
在Java开发过程中,尤其是在涉及类继承和方法重写时,可能会遇到一些常见的编译或运行时错误。理解这些错误的原因对于快速定位和解决问题至关重要。
1. "The type A is already defined" (类型A已定义)
这个编译错误通常意味着你在同一个作用域内(例如,同一个Java源文件,或者在同一个编译命令中包含的多个源文件)定义了两个或多个同名的类。
可能的原因及解决方案:
-
同一文件中重复定义: 确保一个Java源文件(.java)中,除了公共类(其名称必须与文件名相同)之外,其他非公共类只定义一次。例如,如果你在Prac2.java中定义了public class Prac2,那么其他非公共类(如class A)可以定义在同一个文件中,但不能重复。
// 错误示例:Prac2.java中同时定义了两个A类(假设在不同位置) // class A { ... } // class Prac2 extends A { ... } // class A { ... } // 错误:A已定义 -
多个源文件中定义同名类: 如果你在项目中有两个独立的.java文件(例如A.java和Prac2.java),并且在Prac2.java中也定义了一个class A,那么在编译整个项目时就会出现此错误。
- 解决方案: 确保每个类在整个项目中是唯一的。如果A类是独立的,它应该只在A.java中定义。如果A是Prac2的内部类,则应嵌套定义。通常,一个.java文件只包含一个公共类,且文件名与类名相同。
-
IDE或构建工具配置问题: 有时IDE(如Eclipse, IntelliJ IDEA)或构建工具(如Maven, Gradle)的缓存或配置问题可能导致误报。
- 解决方案: 尝试清理项目、重建项目,或者重启IDE。检查项目的构建路径和模块依赖,确保没有重复的类定义被引入。
2. java.lang.NoSuchMethodError
NoSuchMethodError是一个运行时错误(Error而不是Exception),意味着Java虚拟机(JVM)在运行时尝试调用一个方法,但未能找到该方法的定义。这通常发生在编译时和运行时使用的类版本不一致时。
可能的原因及解决方案:
-
版本不匹配: 你的代码(例如Prac2.class)是根据一个版本的A.class编译的,但在运行时,JVM加载了另一个版本的A.class,而这个运行时版本的A.class中缺少了编译时所依赖的m()方法,或者其签名(方法名、参数类型、返回类型)发生了改变。
- 解决方案: 确保所有相关的.class文件在编译时和运行时都是一致的。检查项目的classpath,确保没有冲突的JAR包或类文件。如果使用了构建工具,确认其依赖管理正确。清理并重新编译整个项目通常能解决这类问题。
- 方法签名不匹配: 虽然在编译时










