为什么Java不允许覆盖静态方法?

时间:2010-02-08 17:08:52

标签: java static override static-methods

为什么无法覆盖静态方法?

如果可能,请使用示例。

21 个答案:

答案 0 :(得分:465)

覆盖取决于拥有一个类的实例。多态性的一点是,您可以对类进行子类化,并且实现这些子类的对象将对超类中定义的相同方法具有不同的行为(并在子类中重写)。静态方法与类的任何实例都没有关联,因此该概念不适用。

推动Java设计的两个因素影响了这一点。一个是对性能的担忧:有很多人批评Smalltalk关于它太慢(垃圾收集和多态调用是其中的一部分)而Java的创建者决心避免这种情况。另一个决定是Java的目标受众是C ++开发人员。使静态方法的工作方式与C ++程序员熟悉,并且速度非常快,因为没有必要等到运行时才能找出要调用的方法。

答案 1 :(得分:171)

我个人认为这是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处理静态的方式,我的回答是,“好吧,当然。”正如我在原帖中所说,它不起作用。但是,如果你的意思是设计不好,那么这种语言会有一些根本性的错误,即静态可以像虚函数一样被覆盖,这会以某种方式引入歧义或者不可能我回答说:“为什么?这个概念出了什么问题?”

我认为我给出的例子是一件很自然的事情。我有一个类,它有一个不依赖于任何实例数据的函数,我可能非常合理地想要独立于实例调用,以及想要在实例方法中调用。为什么这不起作用?这些年来,我经常遇到这种情况。在实践中,我通过使函数虚拟化来创建静态方法,然后创建一个静态方法,其生命中唯一的目的是将静态方法传递给具有虚拟实例的虚方法。这似乎是一种非常迂回的方式来实现目标。

答案 2 :(得分:38)

简短的回答是:它完全有可能,但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())调用也是如此。”

最后案例:

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

使用对象实例

进行调用

静态调用在编译时解析,而非静态方法调用在运行时解析。请注意,虽然静态方法是继承的(来自父级),但它们不是重写(通过子级)。如果你不这么想的话,这可能是一个惊喜。

从对象方法中调用

使用运行时类型解析

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

更改规则

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

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

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

目前,Java在obj.staticMethod()调用被ObjectClass.staticMethod()调用替换的语言中具有这种“怪癖”(通常带有警告)。 [注意: ObjectClassobj的编译时类型。]这些是以这种方式覆盖的良好候选者,采用{{1的运行时类型}}

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

调用静态方法的其他方法更棘手:obj应与this.staticMethod()相同,采用运行时类型obj.staticMethod()。但是,这可能会导致现有程序出现一些令人头疼的问题,这些程序调用(显然是本地的)静态方法而没有装饰(可以说相当于this)。

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

其他考虑因素

如果我们改变了这种行为(并使静态调用可能是动态非本地的),我们可能希望重新审视finalprivateprotected作为限定词{{}}的含义{1}}类的方法。然后我们都必须习惯这样的事实:staticprivate static方法没有被覆盖,因此可以在编译时安全地解析,并且作为本地引用读取是“安全的”。

答案 3 :(得分:22)

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

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

答案 4 :(得分:17)

静态方法被JVM视为全局方法,根本没有绑定到对象实例。

如果你可以从类对象中调用静态方法(比如像Smalltalk这样的语言),概念上是可行的,但在Java中并非如此。

修改

你可以重载静态方法,没关系。但是你不能覆盖一个静态方法,因为类不是第一类对象。您可以使用反射在运行时获取对象的类,但是您获得的对象与类层次结构不平行。

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

你可以反思这些课程,但它会在那里停止。您不能使用clazz1.staticMethod()调用静态方法,而是使用MyClass.staticMethod()。静态方法没有绑定到对象,因此静态方法中没有thissuper的概念。静态方法是一个全局函数;因此,也没有多态性的概念,因此,方法覆盖是没有意义的。

但如果MyClass是运行时调用方法的对象,那么这可能是可能的,就像在Smalltalk中一样(或者JRuby可能就像一条评论所暗示的那样,但我对JRuby一无所知)。

噢,是的......还有一件事。您可以通过对象obj1.staticMethod()调用静态方法,但这应该是MyClass.staticMethod()的真正语法糖,应该避免。它通常会在现代IDE中引发警告。我不知道为什么他们允许这种捷径。

答案 5 :(得分:13)

dynamic dispatching使得方法覆盖成为可能,这意味着对象的声明类型不确定其行为,而是确定其运行时类型:

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

即使lassiekermit都声明为Animal类型的对象,但它们的行为(方法.speak())会有所不同,因为动态调度只会bind方法在运行时调用.speak()到实现 - 而不是在编译时。

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

答案 6 :(得分:8)

是。实际上Java允许重写静态方法,理论上如果你在Java中覆盖静态方法然后它将编译并运行顺利,但它将失去多态性,这是Java的基本属性。您将在任何地方阅读,无法尝试自己编译和运行。你会得到你的答案。例如如果你有类动物和一个静态方法eat(),你覆盖它的子类中的静态方法让它叫做Dog。然后,无论你将Dog对象分配给Animal Reference并根据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 但结果不同,因为支持Polymorphism Java使用Late Binding,这意味着只在运行时调用方法,而在静态方法的情况下不调用。在静态方法中编译器在编译时调用方法而不是运行时,所以我们根据引用获取方法而不是根据对象引用包含这就是为什么你可以说实际上它支持静态覆盖但理论上它没有“T

答案 7 :(得分:5)

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

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

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

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

正如有人在评论中提到的那样 - 你想要这个功能的原因和目的是什么?

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

由于您使用的是Java,因此需要适应这种做法。为什么他们这样做?那么,可能是基于可用的技术和理解来提高当时的性能。计算机语言在不断发展。回去够远,没有OOP这样的东西。将来会有其他新想法。

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

中所见

顺便说一下 - 谢谢你的提问!我今天为我学习了一些关于类方法的新东西(Ruby风格)。

答案 8 :(得分:5)

嗯......如果你从一个重写方法应该如何在Java中运行的角度思考,答案是否定的。但是,如果尝试覆盖静态方法,则不会出现任何编译器错误。这意味着,如果你试图覆盖,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'。这确认了静态方法总是仅使用它们的编译时类型信息来解析。

答案 9 :(得分:4)

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

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

答案 10 :(得分:4)

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

答案 11 :(得分:4)

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

答案 12 :(得分:4)

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

答案 13 :(得分:2)

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

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

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

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

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

答案 14 :(得分:2)

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

答案 15 :(得分:2)

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

答案 16 :(得分:1)

覆盖静态方法有什么用呢?您无法通过实例调用静态方法。

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.
编辑:看来,通过对语言设计的不幸疏忽,您可以通过实例调用静态方法。一般没有人这样做。我的坏。

答案 17 :(得分:1)

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

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

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!";
  }

}

答案 18 :(得分:1)

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

答案 19 :(得分:1)

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

Java中的方法用于公开Object / Class的行为。这里,因为方法是静态(即,静态方法仅用于表示类的行为。)更改/覆盖整个类的行为将违反现象面向对象编程的基本支柱之一,即高内聚。 (记住构造函数是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;     }

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

答案 20 :(得分:-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();

}   

}