【Java】方法隐藏 vs 方法重写

变量隐藏

在当前作用域中创建一个变量,这个变量与外部作用域中的某个变量重名,导致使用该名称时默认指向当前作用域中的变量,这种现象就称为变量隐藏

局部变量 a 被类变量 a 隐藏。

public class Main {
	private static int a = 3;
	public static void main(String[] args) {
		int a = 4;
		System.out.println(a); // == 4
	}
}

A 中的 i 被 B 中的 i 隐藏。

class A {
	public int i = 22;
}

class B extends A {
	public int i = 33;
}

System.out.println(new B().i); // == 33

方法隐藏

方法隐藏也是类似的东西。
类 A 中的 foo() 方法被类 B 中的 foo() 方法隐藏。

public class A {
	public static void foo() { }
}

public class B extends A {
	public static void foo() { }
}

方法重写和方法隐藏的区别:

  1. 被重写的方法会被覆盖掉,而被隐藏的方法不会。
  2. 只能对实例方法重写,只能对静态方法隐藏。
  3. 重写是动态绑定(late binding),即运行时确定;而隐藏是静态绑定(early binding),即编译时确定。

class A {
	public void message() { System.out.println("From A"); }
	public static void messageStatic() { System.out.println("Static From A"); }
}

class B extends A {
	public void message() { System.out.println("From B"); }
	public static void messageStatic() { System.out.println("Static From B"); }
}

class C extends A {
	@Override
	public void message() { System.out.println("From C"); }
	public static void messageStatic() { System.out.println("Static From C"); }
}


// 重写
(new B()).message(); // == from B
(new C()).message(); // == from C

// 即使强制转换为父类,调用的依旧是子类重写的版本
((A)new B()).message(); // == from B
((A)new C()).message(); // == from C

// 隐藏
B.messageStatic(); // == Static From B
C.messageStatic(); // == Static From C

// 转换为父类后调用的就是父类的版本
((A)new B()).messageStatic(); // == Static From A
((A)new C()).messageStatic(); // == Static From A

参考

Overriding vs Hiding Java - Confused - StackOverflow
Variable and Method Hiding in Java

<think>好的,我现在需要帮助用户了解在Java中正确重写方法签名的规则示例。首先,我得回忆一下Java方法重写的基本概念。重写发生在子类继承父类的时候,子类提供一个与父类方法有相同签名的方法实现。 接下来,用户提到的是方法签名的规则,所以我需要明确哪些部分构成方法签名。通常,方法签名包括方法名、参数类型列表以及返回类型(在协变返回类型的情况下可以不同)。不过,Java中严格的方法重写要求返回类型必须兼容,参数列表必须完全相同。 然后,我需要考虑用户可能的疑问点,比如访问修饰符的限制。父类的方法如果是public,子类重写时不能缩小访问权限,比如改为private,这会导致编译错误。但反过来,扩大访问权限是可以的,比如从protected改为public。 异常处理也是一个重点。重写方法不能抛出比父类方法更宽泛的检查异常,或者新的检查异常,但可以抛出不抛出异常,或者抛出非检查异常(RuntimeException等)。这点可能需要用例子来说明。 然后是@Override注解的使用,虽然这不是强制的,但加上这个注解可以让编译器检查是否正确重写了父类的方法,避免因为拼写错误或参数不匹配导致的问题。引用中提到的Google Java Style Guide的Javadoc格式示例,可能文档注释有关,但用户的问题更关注方法签名本身,所以可能需要提到在重写时保持或完善Javadoc注释。 用户提供的引用里有关于继承super关键字的例子,比如“Inheritance 2: Extends with Overriding (Example VengefulSLList) keyword super call superclass’s method.”这说明用户可能对如何在子类中调用父类方法感兴趣,所以应该在示例中包含使用super调用父类方法的例子。 另外,引用中提到规则的应用场景设置,这可能某些代码规范或静态检查工具相关,但核心还是方法签名的规则。需要确保覆盖所有关键点:方法名、参数列表、返回类型、访问修饰符、异常、静态方法不能重写等。 可能的误区包括认为参数列表顺序不影响,但实际上参数类型顺序必须完全一致。还有协变返回类型的情况,即子类方法可以返回父类方法返回类型的子类,这是允许的,但需要明确说明。 现在需要组织这些点,用清晰的规则示例来展示。每个规则后面跟一个例子,代码示例用正确的格式,行内公式用$...$,独立公式不需要,但代码块需要用```java标注。同时,生成相关问题,帮助用户进一步学习。 最后,检查是否有遗漏的规则,比如静态方法不能被重写,只能被隐藏;final方法不能被重写重写方法可以使用@Override注解等。确保所有引用适当,比如引用[^2]关于继承super的使用,引用[^1]关于代码风格中的Javadoc示例,可能在示例中加入Javadoc注释,但用户的问题可能更关注方法签名本身。</think>### Java方法重写的签名规则与示例 在Java中,方法重写(Override)需要严格遵循以下规则,确保子类方法与父类方法在签名类型上保持兼容: --- #### 一、核心规则 1. **方法签名必须完全一致** 包括方法名、参数类型及顺序。例如: ```java // 父类 class Animal { public void move(int meters) { /*...*/ } } // 子类正确重写 class Dog extends Animal { @Override public void move(int meters) { /*...*/ } // ✅ 参数类型名称一致 } ``` 2. **返回类型协变(Covariant Return Types)** 子类方法的返回类型可以是父类方法返回类型的子类: ```java class Fruit {} class Apple extends Fruit {} class Farm { Fruit harvest() { return new Fruit(); } } class AppleFarm extends Farm { @Override Apple harvest() { return new Apple(); } // ✅ 返回子类类型 } ``` 3. **访问修饰符不能更严格** 子类方法的访问权限必须 ≥ 父类方法(例如父类为 `protected`,子类可为 `public`,但不可为 `private`): ```java class Parent { protected void save() { /*...*/ } } class Child extends Parent { @Override public void save() { /*...*/ } // ✅ 权限扩大 // ❌ private void save() 会编译错误 } ``` 4. **异常限制** 子类方法不能抛出比父类方法**更宽泛的检查异常**,但可以不抛出异常或抛出非检查异常(如 `RuntimeException`): ```java class Database { void connect() throws SQLException { /*...*/ } } class LocalDB extends Database { @Override void connect() throws SQLException { /*...*/ } // ✅ 相同异常 // @Override void connect() throws Exception {} ❌ 更宽泛 } ``` 5. **静态方法不能被重写** 若父类方法为 `static`,子类中同名方法隐藏(Hide)父类方法,而非重写: ```java class Calculator { static void printType() { System.out.println("Calculator"); } } class ScientificCalculator extends Calculator { static void printType() { System.out.println("Scientific"); } // ❌ 隐藏而非重写 } ``` --- #### 二、附加要求 - **使用 `@Override` 注解** 显式声明方法重写,编译器会检查签名是否符合规范[^1]: ```java class Child extends Parent { @Override // 若签名不匹配会报错 public void method() { /*...*/ } } ``` - **调用父类方法** 可通过 `super` 关键字调用父类被重写方法: ```java class VengefulSLList<T> extends SLList<T> { @Override public T removeLast() { T item = super.removeLast(); // 调用父类实现 // 自定义逻辑... return item; } } ``` --- #### 三、常见错误示例 ```java class Parent { void process(String input) { /*...*/ } } class Child extends Parent { // ❌ 错误1:参数类型不匹配(String vs int) void process(int input) { /*...*/ } // ❌ 错误2:返回类型不兼容(void vs String) String process(String input) { /*...*/ } // ❌ 错误3:访问权限更严格(public → private) private void process(String input) { /*...*/ } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值