为什么 Java 不允许重写静态方法?

发布于 2024-08-20 20:45:11 字数 39 浏览 7 评论 0原文

为什么不能重写静态方法?

如果可能,请使用示例。

Why is it not possible to override static methods?

If possible, please use an example.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(22

轮廓§ 2024-08-27 20:45:11

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

Java 的设计有两个考虑因素影响了这一点。其中之一是对性能的担忧:Smalltalk 受到了很多批评,认为它太慢(垃圾收集和多态调用是其中的一部分),而 Java 的创建者决心避免这种情况。另一个决定是 Java 的目标受众是 C++ 开发人员。让静态方法按照其实际方式工作有利于 C++ 程序员熟悉,而且速度也非常快,因为无需等到运行时才确定要调用哪个方法。

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.

囍笑 2024-08-27 20:45:11

我个人认为这是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");
    }
}

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

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

在我看来,您可能希望将 getBonusMultiplier 设为静态,这似乎很合理。也许您希望能够显示所有员工类别的奖金乘数,而不需要每个类别中都有一个员工实例。搜索此类示例实例的意义何在?如果我们正在创建一个新的员工类别,但尚未分配任何员工,该怎么办?从逻辑上讲,这是一个静态函数。

但这不起作用。

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

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

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

更新

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

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

Personally I think this is a flaw in the design of Java. Yes, yes, I understand that non-static methods are attached to an instance while static methods are attached to a class, etc etc. Still, consider the following code:

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

This code will not work as you might expect. Namely, SpecialEmployee's get a 2% bonus just like regular employees. But if you remove the "static"s, then SpecialEmployee's get a 3% bonus.

(Admittedly, this example is poor coding style in that in real life you would likely want the bonus multiplier to be in a database somewhere rather than hard-coded. But that's just because I didn't want to bog down the example with a lot of code irrelevant to the point.)

It seems quite plausible to me that you might want to make getBonusMultiplier static. Perhaps you want to be able to display the bonus multiplier for all the categories of employees, without needing to have an instance of an employee in each category. What would be the point of searching for such example instances? What if we are creating a new category of employee and don't have any employees assigned to it yet? This is quite logically a static function.

But it doesn't work.

And yes, yes, I can think of any number of ways to rewrite the above code to make it work. My point is not that it creates an unsolvable problem, but that it creates a trap for the unwary programmer, because the language does not behave as I think a reasonable person would expect.

Perhaps if I tried to write a compiler for an OOP language, I would quickly see why implementing it so that static functions can be overriden would be difficult or impossible.

Or perhaps there is some good reason why Java behaves this way. Can anyone point out an advantage to this behavior, some category of problem that is made easier by this? I mean, don't just point me to the Java language spec and say "see, this is documented how it behaves". I know that. But is there a good reason why it SHOULD behave this way? (Besides the obvious "making it work right was too hard"...)

Update

@VicKirk: If you mean that this is "bad design" because it doesn't fit how Java handles statics, my reply is, "Well, duh, of course." As I said in my original post, it doesn't work. But if you mean that it is bad design in the sense that there would be something fundamentally wrong with a language where this worked, i.e. where statics could be overridden just like virtual functions, that this would somehow introduce an ambiguity or it would be impossible to implement efficiently or some such, I reply, "Why? What's wrong with the concept?"

I think the example I give is a very natural thing to want to do. I have a class that has a function that does not depend on any instance data, and which I might very reasonably want to call independent of an instance, as well as wanting to call from within an instance method. Why should this not work? I've run into this situation a fair number of times over the years. In practice I get around it by making the function virtual, and then creating a static method whose only purpose in life is to be a static method that passes the call on to the virtual method with a dummy instance. That seems like a very roundabout way to get there.

追星践月 2024-08-27 20:45:11

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

下面是一些代码,说明了 Java 中的当前状态

File 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();
  }
}

File 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.

Here, the only 可能令人惊讶的情况(以及问题所涉及的情况)出现第一种情况:

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

以及最后情况:

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

使用对象实例进行调用

静态调用在编译时解析,而非静态方法调用在运行时解析。请注意,虽然静态方法是(从父级)继承的,但它们不会(由子级)重写。如果您另有预期,这可能会令人惊讶。

从对象方法内部调用

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

更改规则

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

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

主要考虑因素是我们需要决定哪个静态方法调用应该执行此操作。

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

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

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

那么朴素的调用staticMethod()又如何呢?我建议他们像今天一样,使用当地的班级背景来决定要做什么。否则就会造成极大的混乱。当然,如果 method 是非静态方法,那么 method() 就意味着 this.method(),并且 ThisClass .method() 如果 method 是静态方法。这是另一个混​​乱的根源。

其他考虑因素

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

The short answer is: it is entirely possible, but Java doesn't do it.

Here is some code which illustrates the current state of affairs in Java:

File 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();
  }
}

File 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();
  }
}

If you run this (I did it on a Mac, from Eclipse, using Java 1.6) you get:

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.

Here, the only cases which might be a surprise (and which the question is about) appear to be the first case:

"The run-time type is not used to determine which static methods are called, even when called with an object instance (obj.staticMethod())."

and the last case:

"When calling a static method from within an object method of a class, the static method chosen is the one accessible from the class itself and not from the class defining the run-time type of the object."

Calling with an object instance

The static call is resolved at compile-time, whereas a non-static method call is resolved at run-time. Notice that although static methods are inherited (from parent) they are not overridden (by child). This could be a surprise if you expected otherwise.

Calling from within an object method

Object method calls are resolved using the run-time type, but static (class) method calls are resolved using the compile-time (declared) type.

Changing the rules

To change these rules, so that the last call in the example called Child.printValue(), static calls would have to be provided with a type at run-time, rather than the compiler resolving the call at compile-time with the declared class of the object (or context). Static calls could then use the (dynamic) type hierarchy to resolve the call, just as object method calls do today.

This would easily be doable (if we changed Java :-O), and is not at all unreasonable, however, it has some interesting considerations.

The main consideration is that we need to decide which static method calls should do this.

At the moment, Java has this "quirk" in the language whereby obj.staticMethod() calls are replaced by ObjectClass.staticMethod() calls (normally with a warning). [Note: ObjectClass is the compile-time type of obj.] These would be good candidates for overriding in this way, taking the run-time type of obj.

If we did it would make method bodies harder to read: static calls in a parent class could potentially be dynamically "re-routed". To avoid this we would have to call the static method with a class name -- and this makes the calls more obviously resolved with the compile-time type hierarchy (as now).

The other ways of invoking a static method are more tricky: this.staticMethod() should mean the same as obj.staticMethod(), taking the run-time type of this. However, this might cause some headaches with existing programs, which call (apparently local) static methods without decoration (which is arguably equivalent to this.method()).

So what about unadorned calls staticMethod()? I suggest they do the same as today, and use the local class context to decide what to do. Otherwise great confusion would ensue. Of course it means that method() would mean this.method() if method was a non-static method, and ThisClass.method() if method were a static method. This is another source of confusion.

Other considerations

If we changed this behaviour (and made static calls potentially dynamically non-local), we would probably want to revisit the meaning of final, private and protected as qualifiers on static methods of a class. We would then all have to get used to the fact that private static and public final methods are not overridden, and can therefore be safely resolved at compile-time, and are "safe" to read as local references.

尸血腥色 2024-08-27 20:45:11

其实我们错了。
尽管默认情况下 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

;)

Actually we were wrong.
Despite Java doesn't allow you to override static methods by default, if you look thoroughly through documentation of Class and Method classes in Java, you can still find a way to emulate static methods overriding by following workaround:

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());
    }
}

Resulting output:

0.02
0.02
0.02
0.03

what we were trying to achieve :)

Even if we declare third variable Carl as RegularEmployee and assign to it instance of SpecialEmployee, we will still have call of RegularEmployee method in first case and call of SpecialEmployee method in second case

RegularEmployee Carl = new SpecialEmployee();

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

just look at output console:

0.02
0.03

;)

臻嫒无言 2024-08-27 20:45:11

静态方法被 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 中发出警告。我不知道他们为什么允许这条捷径。

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.

弃爱 2024-08-27 20:45:11

方法重写是通过动态分派实现的,这意味着对象的声明类型无法确定它的行为,而是它的运行时类型:

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

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

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

Method overriding is made possible by dynamic dispatching, meaning that the declared type of an object doesn't determine its behavior, but rather its runtime type:

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

Even though both lassie and kermit are declared as objects of type Animal, their behavior (method .speak()) varies because dynamic dispatching will only bind the method call .speak() to an implementation at run time - not at compile time.

Now, here's where the static keyword starts to make sense: the word "static" is an antonym for "dynamic". So the reason why you can't override static methods is because there is no dynamic dispatching on static members - because static literally means "not dynamic". If they dispatched dynamically (and thus could be overriden) the static keyword just wouldn't make sense anymore.

奶茶白久 2024-08-27 20:45:11

是的。实际上Java允许重写静态方法,理论上是不行的,如果你在Java中重写静态方法,那么它会顺利编译和运行,但它会失去Java的基本属性多态性。您会到处读到不可能尝试自己编译和运行。你会得到答案的。例如,如果您有 Animal 类和静态方法 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
但结果不同,因为为了支持多态性,Java 使用了后期绑定,这意味着方法仅在运行时调用,而静态方法则不然。在静态方法中,编译器在编译时而不是运行时调用方法,因此我们根据引用而不是根据包含引用的对象获取方法,这就是为什么您可以说实际上它支持静态覆盖,但理论上它不支持't。

Yes. Practically Java allows overriding static method, and No theoretically if you Override a static method in Java then it will compile and run smoothly but it will lose Polymorphism which is the basic property of Java. You will Read Everywhere that it is not possible to try yourself compiling and running. you will get your answer. e.g. If you Have Class Animal and a static method eat() and you Override that static method in its Subclass lets called it Dog. Then when wherever you Assign a Dog object to an Animal Reference and call eat() according to Java Dog's eat() should have been called but in static Overriding Animals' eat() will Be Called.

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

According to Polymorphism Principle of Java, the Output Should be Dog Eating.
But the result was different because to support Polymorphism Java uses Late Binding that means methods are called only at the run-time but not in the case of static methods. In static methods compiler calls methods at the compile time rather than the run-time, so we get methods according to the reference and not according to the object a reference a containing that's why You can say Practically it supports static overring but theoretically, it doesn't.

-残月青衣踏尘吟 2024-08-27 20:45:11

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

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

由于两者之间的这种差异;虚拟方法始终具有对上下文对象的引用(即 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 风格)的新知识。

In Java (and many OOP languages, but I cannot speak for all; and some do not have static at all) all methods have a fixed signature - the parameters and types. In a virtual method, the first parameter is implied: a reference to the object itself and when called from within the object, the compiler automatically adds this.

There is no difference for static methods - they still have a fixed signature. However, by declaring the method static you have explicitly stated that the compiler must not include the implied object parameter at the beginning of that signature. Therefore, any other code that calls this must must not attempt to put a reference to an object on the stack. If it did do that, then the method execution would not work since the parameters would be in the wrong place - shifted by one - on the stack.

Because of this difference between the two; virtual methods always have a reference to the context object (i.e. this) so then it is possible to reference anything within the heap that belong to that instance of the object. But with static methods, since there is no reference passed, that method cannot access any object variables and methods since the context is not known.

If you wish that Java would change the definition so that a object context is passed in for every method, static or virtual, then you would in essence have only virtual methods.

As someone asked in a comment to the op - what is your reason and purpose for wanting this feature?

I do not know Ruby much, as this was mentioned by the OP, I did some research. I see that in Ruby classes are really a special kind of object and one can create (even dynamically) new methods. Classes are full class objects in Ruby, they are not in Java. This is just something you will have to accept when working with Java (or C#). These are not dynamic languages, though C# is adding some forms of dynamic. In reality, Ruby does not have "static" methods as far as I could find - in that case these are methods on the singleton class object. You can then override this singleton with a new class and the methods in the previous class object will call those defined in the new class (correct?). So if you called a method in the context of the original class it still would only execute the original statics, but calling a method in the derived class, would call methods either from the parent or sub-class. Interesting and I can see some value in that. It takes a different thought pattern.

Since you are working in Java, you will need to adjust to that way of doing things. Why they did this? Well, probably to improve performance at the time based on the technology and understanding that was available. Computer languages are constantly evolving. Go back far enough and there is no such thing as OOP. In the future, there will be other new ideas.

EDIT: One other comment. Now that I see the differences and as I Java/C# developer myself, I can understand why the answers you get from Java developers may be confusing if you are coming from a language like Ruby. Java static methods are not the same as Ruby class methods. Java developers will have a hard time understanding this, as will conversely those who work mostly with a language like Ruby/Smalltalk. I can see how this would also be greatly confusing by the fact that Java also uses "class method" as another way to talk about static methods but this same term is used differently by Ruby. Java does not have Ruby style class methods (sorry); Ruby does not have Java style static methods which are really just old procedural style functions, as found in C.

By the way - thanks for the question! I learned something new for me today about class methods (Ruby style).

ぃ弥猫深巷。 2024-08-27 20:45:11

好吧...如果您从重写方法在 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();
    // ...
}
}

输出:-
超类:静态方法内部
超类:静态方法内部
SubClass: inside staticMethod

请注意输出的第二行。如果 staticMethod 被重写,则这一行应该与第三行相同,因为我们在运行时类型的对象上调用“staticMethod()”作为“子类”而不是“超类”。这证实了静态方法始终仅使用其编译时类型信息来解析。

Well... the answer is NO if you think from the perspective of how an overriden method should behave in Java. But, you don't get any compiler error if you try to override a static method. That means, if you try to override, Java doesn't stop you doing that; but you certainly don't get the same effect as you get for non-static methods. Overriding in Java simply means that the particular method would be called based on the run time type of the object and not on the compile time type of it (which is the case with overriden static methods). Okay... any guesses for the reason why do they behave strangely? Because they are class methods and hence access to them is always resolved during compile time only using the compile time type information. Accessing them using object references is just an extra liberty given by the designers of Java and we should certainly not think of stopping that practice only when they restrict it :-)

Example: let's try to see what happens if we try overriding a static method:-

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();
    // ...
}
}

Output:-
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

Notice the second line of the output. Had the staticMethod been overriden this line should have been identical to the third line as we're invoking the 'staticMethod()' on an object of Runtime Type as 'SubClass' and not as 'SuperClass'. This confirms that the static methods are always resolved using their compile time type information only.

无人问我粥可暖 2024-08-27 20:45:11

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

静态表示-编译时,重写用于动态多态性。
两者性质相反,不能同时使用。

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

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

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

By overriding, you achieve dynamic polymorphism.
When you say overriding static methods, the words you are trying to use are contradictory.

Static says - compile time, overriding is used for dynamic polymorphism.
Both are opposite in nature, and hence can't be used together.

Dynamic polymorphic behavior comes when a programmer uses an object and accessing an instance method. JRE will map different instance methods of different classes based on what kind of object you are using.

When you say overriding static methods, static methods we will access by using the class name, which will be linked at compile time, so there is no concept of linking methods at runtime with static methods. So the term "overriding" static methods itself doesn't make any meaning.

Note: even if you access a class method with an object, still java compiler is intelligent enough to find it out, and will do static linking.

长不大的小祸害 2024-08-27 20:45:11

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

I like and double Jay's comment (https://stackoverflow.com/a/2223803/1517187).
I agree that this is the bad design of Java.
Many other languages support overriding static methods, as we see in previous comments.
I feel Jay has also come to Java from Delphi like me.
Delphi (Object Pascal) was one of the languages implementing OOP before Java and one of the first languages used for commercial application development.
It is obvious that many people had experience with that language since it was in the past the only language to write commercial GUI products. And - yes, we could in Delphi override static methods. Actually, static methods in Delphi are called "class methods", while Delphi had the different concept of "Delphi static methods" which were methods with early binding. To override methods you had to use late binding, declare "virtual" directive. So it was very convenient and intuitive and I would expect this in Java.

别理我 2024-08-27 20:45:11

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

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

In general it doesn't make sense to allow 'overriding' of static methods as there would be no good way to determine which one to call at runtime. Taking the Employee example, if we call RegularEmployee.getBonusMultiplier() - which method is supposed to be executed?

In the case of Java, one could imagine a language definition where it is possible to 'override' static methods as long as they are called through an object instance. However, all this would do is to re-implement regular class methods, adding redundancy to the language without really adding any benefit.

别把无礼当个性 2024-08-27 20:45:11

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

overriding is reserved for instance members to support polymorphic behaviour. static class members do not belong to a particular instance. instead, static members belong to the class and as a result overriding is not supported because subclasses only inherit protected and public instance members and not static members. You may want to define an inerface and research factory and/or strategy design patterns to evaluate an alternate approach.

我是有多爱你 2024-08-27 20:45:11

通过重写,我们可以根据对象类型创建多态性。静态方法与对象没有关系。所以java不支持静态方法重写。

By overriding we can create a polymorphic nature depending on the object type. Static method has no relation with object. So java can not support static method overriding.

于我来说 2024-08-27 20:45:11

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

Overriding in Java simply means that the particular method would be called based on the runtime type
of the object and not on the compile-time type of it (which is the case with overridden static methods). As static methods are class methods they are not instance methods so they have nothing to do with the fact which reference is pointing to which Object or instance, because due to the nature of static method it belongs to a specific class. You can redeclare it in the subclass but that subclass won't know anything about the parent class' static methods because, as I said, it is specific to only that class in which it has been declared. Accessing them using object references is just an extra liberty given by the designers of Java and we should certainly not think of stopping that practice only when they restrict it
more details and example
http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html

狼性发作 2024-08-27 20:45:11

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

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

编辑:看来,由于语言设计中的一个不幸的疏忽,您可以通过实例调用静态方法。一般来说没有人这样做。我的不好。

What good will it do to override static methods. You cannot call static methods through an instance.

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

EDIT : It appears that through an unfortunate oversight in language design, you can call static methods through an instance. Generally nobody does that. My bad.

〆凄凉。 2024-08-27 20:45:11

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

Answer of this question is simple, the method or variable marked as static belongs to the class only, So that static method cannot be inherited in the sub class because they belong to the super class only.

往事随风而去 2024-08-27 20:45:11

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

在我的系统中,我有 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!";
  }

}

Easy solution: Use singleton instance. It will allow overrides and inheritance.

In my system, I have SingletonsRegistry class, which returns instance for passed Class. If instance is not found, it is created.

Haxe language class:

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

}
未央 2024-08-27 20:45:11

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

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

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

A Static method, variable, block or nested class belongs to the entire class rather than an object.

A Method in Java is used to expose the behaviour of an Object / Class. Here, as the method is static (i.e, static method is used to represent the behaviour of a class only.) changing/ overriding the behaviour of entire class will violate the phenomenon of one of the fundamental pillar of Object oriented programming i.e, high cohesion. (remember a constructor is a special kind of method in Java.)

High Cohesion - One class should have only one role. For example: A car class should produce only car objects and not bike, trucks, planes etc. But the Car class may have some features(behaviour) that belongs to itself only.

Therefore, while designing the java programming language. The language designers thought to allow developers to keep some behaviours of a class to itself only by making a method static in nature.


The below piece code tries to override the static method, but will not encounter any compilation error.

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

This is because, here we are not overriding a method but we are just re-declaring it. Java allows re-declaration of a method (static/non-static).

Removing the static keyword from getVehileNumber() method of Car class will result into compilation error, Since, we are trying to change the functionality of static method which belongs to Vehicle class only.

Also, If the getVehileNumber() is declared as final then the code will not compile, Since the final keyword restricts the programmer from re-declaring the method.

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

Overall, this is upto software designers for where to use the static methods.
I personally prefer to use static methods to perform some actions without creating any instance of a class. Secondly, to hide the behaviour of a class from outside world.

长亭外,古道边 2024-08-27 20:45:11

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

Here is a simple explanation. A static method is associated with a class while an instance method is associated with a particular object. Overrides allow calling the different implementation of the overridden methods associated with the particular object. So it is counter-intuitive to override static method which is not even associated with objects but the class itself in the first place. So static methods cannot be overridden based on what object is calling it, it will always be associated with the class where it was created.

泪痕残 2024-08-27 20:45:11

现在看到上面的答案每个人都知道我们不能重写静态方法,但是人们不应该误解从子类访问静态方法的概念。

如果父类的静态方法没有被子类中定义的新静态方法隐藏,我们可以通过子类引用来访问该静态方法。

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

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 文档 并搜索 您可以在子类中执行哪些操作了解有关在子类中隐藏静态方法的详细信息。

谢谢

Now seeing above answers everyone knows that we can't override static methods, but one should not misunderstood about the concept of accessing static methods from subclass.

We can access static methods of super class with subclass reference if this static method has not been hidden by new static method defined in sub class.

For Example, see below code:-

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");
    // }
}

Output:-

SuperClass saying Hello

See Java oracle docs and search for What You Can Do in a Subclass for details about hiding of static methods in sub class.

Thanks

巡山小妖精 2024-08-27 20:45:11

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

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();

}   

} 

The following code shows that it is possible:

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();

}   

} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文