567

为什么不能覆盖静态方法?

如果可能,请举个例子。

4

22 回答 22

513

Overriding depends on having an instance of a class. The point of polymorphism is that you can subclass a class and the objects implementing those subclasses will have different behaviors for the same methods defined in the superclass (and overridden in the subclasses). A static method is not associated with any instance of a class so the concept is not applicable.

There were two considerations driving Java's design that impacted this. One was a concern with performance: there had been a lot of criticism of Smalltalk about it being too slow (garbage collection and polymorphic calls being part of that) and Java's creators were determined to avoid that. Another was the decision that the target audience for Java was C++ developers. Making static methods work the way they do had the benefit of familiarity for C++ programmers and was also very fast, because there's no need to wait until runtime to figure out which method to call.

于 2010-02-08T17:12:17.810 回答
194

个人认为这是Java设计的一个缺陷。是的,是的,我知道非静态方法附加到实例,而静态方法附加到类等。不过,请考虑以下代码:

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

此代码不会像您预期的那样工作。即,SpecialEmployee 与普通员工一样获得 2% 的奖金。但是,如果您删除“静态”,则 SpecialEmployee 将获得 3% 的奖金。

(诚​​然,这个例子的编码风格很差,在现实生活中,你可能希望奖金乘数在某个数据库中而不是硬编码。但这只是因为我不想让这个例子陷入困境。与该点无关的代码。)

对我来说,您可能希望将 getBonusMultiplier 设为静态似乎很合理。也许您希望能够显示所有员工类别的奖金乘数,而无需在每个类别中都有员工的实例。搜索这样的示例实例有什么意义?如果我们正在创建一个新的员工类别并且还没有任何员工分配给它怎么办?这在逻辑上是一个静态函数。

但它不起作用。

是的,是的,我可以想出很多方法来重写上面的代码以使其工作。我的观点不是它创造了一个无法解决的问题,而是它为粗心的程序员创造了一个陷阱,因为这种语言的行为并不像我认为一个理性的人所期望的那样。

也许如果我尝试为 OOP 语言编写编译器,我很快就会明白为什么实现它以便可以覆盖静态函数是困难的或不可能的。

或者也许有一些很好的理由说明 Java 的这种行为方式。任何人都可以指出这种行为的一个优势,某种类型的问题会因此变得更容易吗?我的意思是,不要只指向 Java 语言规范并说“看,这是记录它的行为方式”。我知道。但是有充分的理由为什么它应该这样做吗?(除了明显的“让它正常工作太难了”......)

更新

@VicKirk:如果你的意思是这是“糟糕的设计”,因为它不适合 Java 处理静态的方式,我的回答是,“嗯,当然。” 正如我在原始帖子中所说,它不起作用。但是,如果您的意思是从某种意义上说这是一种糟糕的设计,那么这种工作的语言会存在根本性的错误,即静态可以像虚函数一样被覆盖,那么这会以某种方式引入歧义,或者不可能有效地实施或类似的,我回答,“为什么?这个概念有什么问题?”

我认为我给出的例子是一件很自然的事情。我有一个类,它的函数不依赖于任何实例数据,并且我可能非常合理地希望独立于实例调用它,并且希望从实例方法中调用它。为什么这不起作用?这些年来,我已经多次遇到这种情况。在实践中,我通过将函数设为虚拟来解决它,然后创建一个静态方法,其生命中的唯一目的是成为一个静态方法,将调用传递给具有虚拟实例的虚拟方法。这似乎是一种非常迂回的到达那里的方式。

于 2010-02-08T18:14:23.610 回答
45

简短的回答是:完全有可能,但 Java 没有这样做。

下面是一些说明Java现状的代码:

文件Base.java

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

文件Child.java

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

如果你运行它(我是在 Mac 上,从 Eclipse,使用 Java 1.6 运行的)你会得到:

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

在这里,唯一可能令人惊讶的案例(以及问题所在)似乎是第一个案例:

“运行时类型不用于确定调用哪些静态方法,即使使用对象实例 ( obj.staticMethod()) 调用也是如此。”

最后一种情况:

“从类的对象方法中调用静态方法时,选择的静态方法是类本身可访问的方法,而不是定义对象运行时类型的类。”

使用对象实例调用

静态调用在编译时解析,而非静态方法调用在运行时解析。请注意,尽管静态方法是(从父级)继承的,但它们不会(被子级)覆盖。如果您有其他预期,这可能是一个惊喜。

从对象方法中调用

对象方法调用使用运行时类型解析,但静态()方法调用使用编译时(声明)类型解析。

改变规则

要更改这些规则,以便示例中的最后一次调用调用Child.printValue(),静态调用必须在运行时提供类型,而不是编译器在编译时使用对象的声明类(或语境)。然后,静态调用可以使用(动态)类型层次结构来解析调用,就像今天的对象方法调用一样。

这很容易实现(如果我们更改 Java :-O),并且一点也不不合理,但是,它有一些有趣的考虑。

主要考虑的是我们需要决定哪些静态方法调用应该这样做。

目前,Java 在语言中有这种“怪癖”,即obj.staticMethod()调用被调用替换ObjectClass.staticMethod()(通常带有警告)。[注意ObjectClassobj.obj

如果我们这样做了,它会使方法体更难阅读:父类中的静态调用可能会被动态地“重新路由”。为了避免这种情况,我们必须使用类名调用静态方法——这使得调用更明显地通过编译时类型层次结构解决(就像现在一样)。

调用静态方法的其他方法更棘手:this.staticMethod()应该与 相同obj.staticMethod(),采用运行时类型this. 但是,这可能会给现有程序带来一些麻烦,这些程序调用(显然是本地的)静态方法而没有修饰(可以说等同于this.method())。

那么朴素的电话staticMethod()呢?我建议他们像今天一样做,并使用本地类上下文来决定做什么。否则会产生很大的混乱。当然,method()这意味着this.method()ifmethod是一个非静态方法,并且ThisClass.method()ifmethod是一个静态方法。这是另一个混​​乱的来源。

其他注意事项

如果我们改变了这种行为(并且使静态调用可能动态地非本地调用),我们可能想要重新审视final,private和作为类方法的protected限定符的含义。static然后我们都必须习惯这样一个事实,即private staticpublic final方法不会被覆盖,因此可以在编译时安全地解析,并且可以“安全”地作为本地引用读取。

于 2012-10-10T11:19:07.020 回答
26

其实我们错了。
尽管默认情况下 Java 不允许您覆盖静态方法,但如果您仔细阅读 Java 中的 Class 和 Method 类的文档,您仍然可以通过以下解决方法找到模拟静态方法覆盖的方法:

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

结果输出:

0.02
0.02
0.02
0.03

我们想要达到的目标:)

即使我们将第三个变量 Carl 声明为 RegularEmployee 并将其分配给 SpecialEmployee 的实例,我们仍然会在第一种情况下调用 RegularEmployee 方法,在第二种情况下调用 SpecialEmployee 方法

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

看看输出控制台:

0.02
0.03

;)

于 2013-02-20T12:43:53.540 回答
19

Static methods are treated as global by the JVM, there are not bound to an object instance at all.

It could conceptually be possible if you could call static methods from class objects (like in languages like Smalltalk) but it's not the case in Java.

EDIT

You can overload static method, that's ok. But you can not override a static method, because class are no first-class object. You can use reflection to get the class of an object at run-time, but the object that you get does not parallel the class hierarchy.

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

You can reflect over the classes, but it stops there. You don't invoke a static method by using clazz1.staticMethod(), but using MyClass.staticMethod(). A static method is not bound to an object and there is hence no notion of this nor super in a static method. A static method is a global function; as a consequence there is also no notion of polymorphism and, therefore, method overriding makes no sense.

But this could be possible if MyClass was an object at run-time on which you invoke a method, as in Smalltalk (or maybe JRuby as one comment suggest, but I know nothing of JRuby).

Oh yeah... one more thing. You can invoke a static method through an object obj1.staticMethod() but that really syntactic sugar for MyClass.staticMethod() and should be avoided. It usually raises a warning in modern IDE. I don't know why they ever allowed this shortcut.

于 2010-02-08T17:12:55.053 回答
16

动态调度使方法覆盖成为可能,这意味着对象的声明类型并不决定其行为,而是决定其运行时类型:

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"

尽管lassiekermit都被声明为 type 的对象Animal,但它们的行为(方法.speak())会有所不同,因为动态调度只会在运行时将方法调用绑定.speak()到实现,而不是在编译时。

现在,这里是static关键字开始有意义的地方:“静态”这个词是“动态”的反义词。所以你不能覆盖静态方法的原因是因为静态成员没有动态调度 -因为静态字面意思是“非动态”。如果它们是动态调度的(因此可以被覆盖),那么static关键字就不再有意义了。

于 2012-09-20T05:20:18.057 回答
14

是的。实际上Java允许覆盖静态方法,理论上如果你在Java中覆盖静态方法,它会编译和运行顺利,但它会失去Java的基本属性多态性。您将在各处阅读到无法尝试自己编译和运行。你会得到你的答案。例如,如果您有类 Animal 和一个静态方法 eat(),并且您在其子类中重写该静态方法,则将其称为 Dog。然后,当您将 Dog 对象分配给动物引用并根据 Java Dog 的eat() 调用eat() 时,应该调用但在静态覆盖动物的eat() 中将被调用。

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

根据 Java 的多态性原理,输出应该是Dog Eating.
但是结果是不同的,因为为了支持多态性,Java 使用了后期绑定,这意味着方法仅在运行时被调用,而不是在静态方法的情况下。在静态方法中,编译器在编译时而不是运行时调用方法,所以我们根据引用而不是根据对象获取方法,引用 a 包含这就是为什么你可以说实际上它支持静态覆盖,但理论上,它不不。

于 2017-10-29T10:33:16.573 回答
7

在 Java(和许多 OOP 语言,但我不能代表所有人;有些根本没有静态)中,所有方法都有一个固定的签名 - 参数和类型。在虚方法中,第一个参数是隐含的:对对象本身的引用,当从对象内部调用时,编译器会自动添加this.

静态方法没有区别——它们仍然有一个固定的签名。但是,通过声明静态方法,您已明确声明编译器不得在该签名的开头包含隐含的对象参数。因此,调用 this 的任何其他代码都不得尝试将对对象的引用放在堆栈上。如果它确实这样做了,那么方法执行将不起作用,因为参数将位于错误的位置 - 移位了 - 在堆栈上。

由于两者之间的这种差异;虚拟方法总是引用上下文对象(即this),因此可以引用堆中属于该对象实例的任何内容。但是对于静态方法,由于没有传递引用,因此该方法无法访问任何对象变量和方法,因为上下文是未知的。

如果您希望 Java 更改定义以便为每个方法(静态或虚拟)传递对象上下文,那么您本质上将只有虚拟方法。

正如有人在对该操作的评论中所问的那样 - 您想要此功能的原因和目的是什么?

我不太了解Ruby,正如OP提到的那样,我做了一些研究。我看到在 Ruby 中,类确实是一种特殊的对象,可以创建(甚至是动态地)新方法。类是 Ruby 中的完整类对象,它们不在 Java 中。这只是您在使用 Java(或 C#)时必须接受的。这些不是动态语言,尽管 C# 正在添加某些形式的动态语言。实际上,Ruby 没有我能找到的“静态”方法——在这种情况下,这些是单例类对象上的方法。然后,您可以使用新类覆盖此单例,并且前一个类对象中的方法将调用新类中定义的方法(对吗?)。因此,如果您在原始类的上下文中调用方法,它仍然只会执行原始静态,但是调用派生类中的方法,会调用父类或子类的方法。有趣,我可以从中看到一些价值。它需要不同的思维模式。

由于您使用的是 Java,因此您需要适应这种做事方式。他们为什么这样做?好吧,可能是为了根据可用的技术和理解来提高当时的性能。计算机语言在不断发展。回到足够远的地方,没有像OOP这样的东西。未来,还会有其他新的想法。

编辑:另一条评论。现在我看到了差异,并且作为我自己的 Java/C# 开发人员,我可以理解为什么如果您来自像 Ruby 这样的语言,您从 Java 开发人员那里得到的答案可能会令人困惑。Javastatic方法与 Rubyclass方法不同。Java 开发人员将很难理解这一点,相反,那些主要使用 Ruby/Smalltalk 之类的语言工作的人也一样。我可以看到,Java 也使用“类方法”作为另一种谈论静态方法的方式,但 Ruby 使用不同的术语。Java 没有 Ruby 风格的类方法(抱歉);Ruby 没有 Java 风格的静态方法,它们实际上只是旧的过程风格的函数,就像在 C 中发现的那样。

顺便说一句 - 谢谢你的问题!今天我学到了一些关于类方法(Ruby 风格)的新知识。

于 2010-03-04T15:33:57.947 回答
6

嗯……如果你从 Java 中被覆盖的方法应该如何表现的角度来思考,答案是否定的。但是,如果您尝试覆盖静态方法,则不会出现任何编译器错误。这意味着,如果您尝试覆盖,Java 不会阻止您这样做;但你肯定不会得到与非静态方法相同的效果。Java 中的覆盖仅仅意味着特定方法将根据对象的运行时类型而不是编译时类型来调用(这是覆盖静态方法的情况)。好吧......任何猜测他们为什么表现奇怪的原因?因为它们是类方法,因此在编译时总是只使用编译时类型信息来解决对它们的访问。

示例:让我们尝试看看如果我们尝试覆盖静态方法会发生什么:-

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

输出:-
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

注意输出的第二行。如果 staticMethod 被覆盖,这一行应该与第三行相同,因为我们在运行时类型的对象上调用“staticMethod()”作为“SubClass”而不是“SuperClass”。这证实了静态方法总是只使用它们的编译时类型信息来解析。

于 2013-01-14T11:28:41.170 回答
6

为实例成员保留覆盖以支持多态行为。静态类成员不属于特定实例。相反,静态成员属于该类,因此不支持覆盖,因为子类仅继承受保护和公共实例成员,而不是静态成员。您可能希望定义接口和研究工厂和/或策略设计模式来评估替代方法。

于 2010-02-08T17:24:09.003 回答
6

我喜欢并加倍 Jay 的评论 ( https://stackoverflow.com/a/2223803/1517187 )。
我同意这是 Java 的糟糕设计。
正如我们在之前的评论中看到的,许多其他语言支持覆盖静态方法。我觉得 Jay 也像我一样从 Delphi 来到 Java。
Delphi(Object Pascal)是在 Java 之前实现 OOP 的语言之一,也是最早用于商业应用程序开发的语言之一。
很明显,很多人都使用过这种语言,因为过去它是编写商业 GUI 产品的唯一语言。而且 - 是的,我们可以在 Delphi 中覆盖静态方法。实际上,Delphi 中的静态方法称为“类方法”,而 Delphi 有不同概念的“Delphi 静态方法”,它们是具有早期绑定的方法。要覆盖必须使用后期绑定的方法,请声明“虚拟”指令。所以它非常方便和直观,我希望在 Java 中做到这一点。

于 2013-02-20T11:10:35.180 回答
5

通过覆盖,您可以实现动态多态性。当您说覆盖静态方法时,您尝试使用的词是矛盾的。

静态说 - 编译时,覆盖用于动态多态性。两者性质相反,因此不能一起使用。

当程序员使用对象并访问实例方法时,就会出现动态多态行为。JRE 将根据您使用的对象类型映射不同类的不同实例方法。

当你说覆盖静态方法时,我们会通过类名来访问静态方法,类名会在编译时链接,所以没有运行时链接方法与静态方法的概念。所以术语“覆盖”静态方法本身没有任何意义。

注意:即使你使用一个对象访问一个类方法,java 编译器仍然有足够的智能找到它,并且会进行静态链接。

于 2013-12-12T07:13:53.243 回答
5

通过覆盖,我们可以根据对象类型创建多态性。静态方法与对象无关。所以java不能支持静态方法覆盖。

于 2013-02-20T14:10:31.553 回答
5

一般来说,允许“覆盖”静态方法是没有意义的,因为没有好的方法来确定在运行时调用哪个方法。以 Employee 为例,如果我们调用 RegularEmployee.getBonusMultiplier() - 应该执行哪个方法?

在 Java 的情况下,可以想象一种语言定义,只要通过对象实例调用静态方法,就可以“覆盖”它们。然而,这一切只会重新实现常规的类方法,为语言增加冗余,而不会真正增加任何好处。

于 2010-02-08T19:19:09.690 回答
3

Java 中的覆盖仅仅意味着特定方法将基于对象的运行时类型而不是它的编译时类型被调用(这是覆盖静态方法的情况)。由于静态方法是类方法,它们不是实例方法,因此它们与引用指向哪个对象或实例这一事实无关,因为由于静态方法的性质,它属于特定类。您可以在子类中重新声明它,但该子类对父类的静态方法一无所知,因为正如我所说,它仅特定于声明它的那个类。使用对象引用访问它们只是 Java 设计者给予的额外自由,我们当然不应该只在他们限制更多细节和示例时才考虑停止这种做法 http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html

于 2014-09-04T14:30:10.590 回答
3

重写静态方法有什么好处。您不能通过实例调用静态方法。

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

编辑:似乎通过语言设计中的不幸疏忽,您可以通过实例调用静态方法。一般没有人这样做。我的错。

于 2010-02-08T17:31:09.990 回答
2

这个问题的答案很简单,标记为静态的方法或变量只属于类,因此静态方法不能在子类中继承,因为它们只属于超类。

于 2015-06-29T19:41:47.560 回答
1

简单的解决方案:使用单例实例。它将允许覆盖和继承。

在我的系统中,我有 SingletonsRegistry 类,它返回传递的类的实例。如果未找到实例,则创建它。

Haxe语言类:

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
  }

}
于 2014-03-28T15:43:05.850 回答
1

静态方法、变量、块或嵌套类属于整个类而不是对象。

Java中的方法用于公开对象/类的行为。在这里,由于方法是静态的(即,静态方法仅用于表示类的行为。)更改/覆盖整个类的行为将违反面向对象编程的基本支柱之一的现象,即高内聚. (请记住,构造函数是 Java 中的一种特殊方法。)

高凝聚力——一个班级应该只有一个角色。例如:一个汽车类应该只产生汽车对象,而不是自行车、卡车、飞机等。但是汽车类可能有一些只属于它自己的特征(行为)。

因此,在设计java编程语言时。语言设计者认为允许开发人员仅通过使方法本质上为静态来将类的某些行为保留给自身。


下面的代码尝试覆盖静态方法,但不会遇到任何编译错误。

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

这是因为,这里我们没有覆盖一个方法,而只是重新声明它。Java 允许重新声明方法(静态/非静态)。

从 Car 类的 getVehileNumber() 方法中删除 static 关键字将导致编译错误,因为我们试图更改仅属于 Vehicle 类的静态方法的功能。

此外,如果 getVehileNumber() 被声明为final,那么代码将无法编译,因为 final 关键字限制了程序员重新声明该方法。

public static final int getVehileNumber() {
return VIN;     }

总的来说,这取决于软件设计人员在哪里使用静态方法。我个人更喜欢使用静态方法来执行一些操作,而无需创建任何类的实例。其次,向外界隐藏一个类的行为。

于 2016-09-12T08:00:59.530 回答
1

这是一个简单的解释。静态方法与类相关联,而实例方法与特定对象相关联。覆盖允许调用与特定对象关联的覆盖方法的不同实现。因此,重写静态方法是违反直觉的,该方法甚至与对象无关,而是首先与类本身相关联。因此,静态方法不能根据调用它的对象而被覆盖,它将始终与创建它的类相关联。

于 2016-05-27T20:37:26.760 回答
0

现在看到上面的答案大家都知道我们不能覆盖静态方法,但是不要误解从子类访问静态方法的概念

如果这个静态方法没有被子类中定义的新静态方法隐藏,我们可以使用子类引用访问超类的静态方法。

例如,请参见下面的代码:-

public class StaticMethodsHiding {
    public static void main(String[] args) {
        SubClass.hello();
    }
}


class SuperClass {
    static void hello(){
        System.out.println("SuperClass saying Hello");
    }
}


class SubClass extends SuperClass {
    // static void hello() {
    // System.out.println("SubClass Hello");
    // }
}

输出:-

SuperClass saying Hello

有关在子类中隐藏静态方法的详细信息,请参阅Java oracle 文档并搜索您可以在子类中做什么。

谢谢

于 2017-02-24T08:30:32.090 回答
-3

以下代码表明这是可能的:

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

} 
于 2012-06-07T04:17:03.397 回答