【转贴】java overriding vs hiding

本文探讨了Java中方法覆盖与方法隐藏的区别,通过实例解释了为何静态方法不能被覆盖,而实例方法可以。并说明了如何正确调用类方法。
导读:

注意一个原则:
动态绑定的时候,对静态方法的绑定只依据变量的声明类型。


Can I override a static method?
  Many people have heard that you can't override a static method. This is true - you can't. However it is possible to write code like this:class Foo {

public static void method() {

System.out.println("in Foo");

}

}

class Bar extends Foo {

public static void method() {

System.out.println("in Bar");

}

}This compiles and runs just fine. Isn't it an example of a static method overriding another static method? The answer is no - it's an example of a static method hidinganother static method. If you try to override a static method, the compiler doesn't actually stop you - it just doesn't do what you think it does.

   So what's the difference?

  Briefly, when you overridea method, you still get the benefits of run-time polymorphism, and when you hide, you don't. So what does that mean? Take a look at this code:class Foo {

public static void classMethod() {

System.out.println("classMethod() in Foo");

}

public void instanceMethod() {

System.out.println("instanceMethod() in Foo");

}

}

class Bar extends Foo {

public static void classMethod() {

System.out.println("classMethod() in Bar");

}

public void instanceMethod() {

System.out.println("instanceMethod() in Bar");

}

}



class Test {

public static void main(String[] args) {

Foo f = new Bar();

f.instanceMethod();

f.classMethod();

}

}If you run this, the output isinstanceMethod() in Bar

classMethod() in FooWhy do we get instanceMethod from Bar, but classMethod() from Foo? Aren't we using the same instance f to access both of these? Yes we are - but since one is overriding and the other is hiding, we see different behavior.

  Since instanceMethod() is (drum roll please...) an instance method, in which Bar overridesthe method from Foo, at run time the JVM uses the actualclass of the instance f to determine which method to run. Although f was declaredas a Foo, the actual instance we created was a new Bar(). So at runtime, the JVM finds that f is a Bar instance, and so it calls instanceMethod() in Bar rather than the one in Foo. That's how Java normally works for instance methods.

  With classMethod() though. since (ahem) it's a classmethod, the compiler and JVM don't expect to need an actual instance to invoke the method. And even if you provide one (which we did: the instance referred to by f) the JVM will never look at it. The compiler will only look at the declared typeof the reference, and use that declared type to determine, at compile time, which method to call. Since f is declared as type Foo, the compiler looks at f.classMethod() and decides it means Foo.classMethod. It doesn't matter that the instance reffered to by f is actually a Bar - for static methods, the compiler only uses the declared type of the reference. That's what we mean when we say a static method does not have run-time polymorphism.

  Because instance methods and class methods have this important difference in behavior, we use different terms - "overriding" for instance methods and "hiding" for class methods - to distinguish between the two cases. And when we say you can't override a static method, what that means is that even if you write code that lookslike it's overriding a static method (like the first Foo and Bar at the top of this page) - it won't behavelike an overridden method.

   So what about accessing a static method using an instance?

  It's possible in Java to write something like:f.classMethod();] where f is an instance of some class, and classMethod() is a class method (i.e. a static method) of that class. This is legal, but it's a bad idea because it creates confusion. The actual instancef is not really important here. Only the decleared typeof f matters. That is, what class is f declared to be? Since classMethod() is static, the class of f (as determined by the compiler at compile time) is all we need.

  Rather than writing:f.classMethod();It would be better coding style to write either:Foo.classMethod();orBar.classMethod(); That way, it is crystal clear which class method you would like to call. It is also clear that the method you are calling is indeed a class method.

  Barring that, you could always come up with this monstrosity:f.getClass().getMethod("classMethod", new Class[]).invoke(f, new Object[]);



本文转自

http://faq.javaranch.com/view?OverridingVsHiding
### 使用 JavaPoet 实现 MethodSpec 方法重写(OverridingJavaPoet 是 Square 开发的一个用于生成 Java 源代码的 Java API,它广泛用于注解处理器、代码生成工具 AOP 框架中。通过 `MethodSpec` 可以构建方法定义,包括方法体、参数、注解等。在 JavaPoet 中实现方法重写(Overriding)的关键在于构建与父类方法签名一致的 `MethodSpec`,并将其添加到子类中。 #### 方法重写的构建流程 在 JavaPoet 中,重写方法的过程包括以下几个关键步骤: - 使用 `MethodSpec.overriding()` 构建一个基于父类方法的 `MethodSpec.Builder`。 - 通过 `addStatement()` 或 `addCode()` 添加方法体。 - 将构建好的 `MethodSpec` 添加到子类的 `TypeSpec` 中。 #### 示例代码 以下是一个使用 JavaPoet 生成子类并重写父类方法的完整示例。假设存在一个父类 `Animal`,其中包含一个 `speak()` 方法: ```java public class Animal { public void speak() { System.out.println("Animal speaks"); } } ``` 使用 JavaPoet 生成子类 `Dog` 并重写 `speak()` 方法: ```java import com.squareup.javapoet.*; import javax.lang.model.element.Modifier; import java.io.IOException; import java.lang.reflect.Method; public class MethodOverrideExample { public static void main(String[] args) throws IOException, NoSuchMethodException { // 获取父类方法 Method methodToOverride = Animal.class.getMethod("speak"); // 构建重写方法 MethodSpec speakMethod = MethodSpec.overriding(methodToOverride) .addStatement("System.out.println($S)", "Dog barks") .build(); // 构建子类 TypeSpec dogClass = TypeSpec.classBuilder("Dog") .superclass(Animal.class) .addMethod(speakMethod) .build(); // 构建 Java 文件 JavaFile javaFile = JavaFile.builder("com.example", dogClass) .build(); // 输出 Java 文件 javaFile.writeTo(System.out); } } ``` 生成的 Java 代码如下: ```java package com.example; class Dog extends com.example.Animal { @Override public void speak() { System.out.println("Dog barks"); } } ``` #### 注意事项 - `MethodSpec.overriding(Method)` 方法会自动继承父类方法的名称、参数、返回类型访问权限。 - 如果需要添加注解(如 `@Override`),可以通过 `addAnnotation(Override.class)` 显式添加。 - 在注解处理器或 AOP 工具中,JavaPoet 常用于在编译期生成代码,实现如日志注入、性能监控等功能[^1]。 ### 相关问题 1. 如何在 JavaPoet 中生成带注解的方法? 2. JavaPoet 是否支持生成泛型方法? 3. 如何使用 JavaPoet 动态生成接口实现类? 4. JavaPoet 与注解处理器结合使用的最佳实践有哪些? 5. 如何在 JavaPoet 中构建构造函数?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值