为什么无法覆盖静态方法?
如果可能,请使用示例。
Parent p = new Child()
,然后p.childOverriddenStaticMethod()
编译器也会Parent.childOverriddenStaticMethod()
通过查看引用类型来解决该问题。
为什么无法覆盖静态方法?
如果可能,请使用示例。
Parent p = new Child()
,然后p.childOverriddenStaticMethod()
编译器也会Parent.childOverriddenStaticMethod()
通过查看引用类型来解决该问题。
Answers:
覆盖取决于拥有类的实例。多态性的目的是可以对一个类进行子类化,并且实现那些子类的对象对于在超类中定义的相同方法(并在子类中被重写)将具有不同的行为。静态方法未与类的任何实例相关联,因此该概念不适用。
影响Java设计的因素有两个。一个是对性能的关注:Smalltalk对其速度太慢提出了很多批评(垃圾回收和多态调用是其中的一部分),Java的创建者决心避免这种情况。另一个决定是Java的目标受众是C ++开发人员。使静态方法按其实际方式工作对C ++程序员来说是很有益的,而且速度非常快,因为不需要等到运行时就确定要调用哪种方法。
obj.staticMethod()
)调用静态方法时会发生这种情况-这是允许的,并使用编译时类型。当静态调用位于类的非静态方法中时,“当前”对象可以是该类的派生类型,但是不考虑在派生类型上定义的静态方法(它们在运行时类型中)等级)。
我个人认为这是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's像普通员工一样获得2%的奖金。但是,如果您删除了“静态”,那么SpecialEmployee将获得3%的奖金。
(诚然,此示例的编码风格很差,因为在现实生活中,您可能希望奖金乘数位于某个地方的数据库中,而不是硬编码。但这只是因为我不想过多地讨论该示例与此无关的代码)。
在我看来,您可能想使getBonusMultiplier静态化似乎很合理。也许您希望能够显示所有类别员工的奖金乘数,而无需在每个类别中都有一个员工实例。搜索此类示例实例的目的是什么?如果我们正在创建一个新的员工类别并且尚未分配任何员工该怎么办?从逻辑上讲,这是一个静态函数。
但这是行不通的。
是的,是的,我可以想到许多方法来重写上述代码以使其工作。我的意思不是说它会产生无法解决的问题,而是会给粗心的程序员带来陷阱,因为这种语言的行为不像我认为的合理人所期望的那样。
也许,如果我尝试为OOP语言编写编译器,我会很快理解为什么很难或不可能实现它以覆盖静态函数。
也许有一些很好的理由说明Java会采取这种方式。谁能指出这种行为的优势,某种行为会因此而变得更加容易?我的意思是,不仅要指向Java语言规范并说“看,这是有据可查的”。我知道。但是,为什么它应该以这种方式表现呢?(除了明显的“使其正常工作太难了” ...)
更新资料
@VicKirk:如果您说这是“错误的设计”,因为它不适合Java处理静态的方式,我的回答是:“当然,嗯。” 正如我在原始帖子中所说,它不起作用。但是,如果您从某种意义上说这是一种错误的设计,那么某种语言在其中起作用就会产生根本性的错误,即像虚拟函数一样可以覆盖静态的语言,那么这将以某种方式引入歧义,或者不可能我会回答:“为什么?这个概念有什么问题?”
我认为我举的例子是很自然的事情。我有一个类,该类的功能不依赖于任何实例数据,并且我可能非常想独立于实例进行调用,并且希望从实例方法内进行调用。为什么这不起作用?多年来,我已经多次遇到这种情况。在实践中,我通过使函数虚拟化来解决它,然后创建一个静态方法,该方法的唯一目的是成为一个静态方法,该方法将调用与虚拟实例一起传递给虚拟方法。那似乎是到达那里的一种非常round回的方式。
someStatic()
A,而B扩展了A,然后B.someMethod()
绑定到A 中的方法。如果我随后将其添加someStatic()
到B,则调用代码仍然会调用,A.someStatic()
直到我重新编译调用代码为止。同样令我惊讶的是,它bInstance.someStatic()
使用的是bInstance 的声明类型,而不是运行时类型,因为它在编译时未链接,因此A bInstance; ... bInstance.someStatic()
如果B.someStatic()存在,则调用A.someStatic()。
简短的答案是:完全有可能,但是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上,是使用Java 1.6在Eclipse上,在Mac上运行的),则会得到:
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()
(通常带有警告)。[ 注意: ObjectClass
是。的编译时类型obj
。]采用。的运行时类型,这些将是以这种方式进行覆盖的不错的选择obj
。
如果这样做的话,将使方法体难以阅读:父类中的静态调用可能会动态地 “重新路由”。为了避免这种情况,我们必须使用类名来调用static方法-这使得调用在编译时类型层次结构(如现在)中更加明显地得以解决。
调用静态方法的其他方式更为棘手:this.staticMethod()
应obj.staticMethod()
与运行时类型的含义相同this
。但是,这可能会给现有程序带来一些麻烦,这些现有程序会调用(显然是本地的)静态方法而不进行修饰(可以说等效于this.method()
)。
那么没有装饰的电话staticMethod()
呢?我建议他们像今天一样做,并使用本地类上下文来决定要做什么。否则会引起极大的混乱。当然,method()
这意味着this.method()
如果method
是非静态方法,并且ThisClass.method()
如果method
是静态方法,则意味着。这是造成混乱的另一个原因。
如果我们更改了此行为(并使静态调用可能动态地非本地调用),则可能需要重新访问和的含义final
,private
并将其protected
作为static
类方法上的限定符。然后,我们所有人都将不得不适应一个事实,即private static
and public final
方法不会被覆盖,因此可以在编译时安全地解决,并且作为本地引用是“安全的”。
其实我们错了。
尽管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
;)
静态方法被JVM视为全局方法,根本没有绑定到对象实例。
从概念上讲,如果可以从类对象中调用静态方法(例如在Smalltalk之类的语言中),则可能是可行的,但Java并非如此。
编辑
您可以重载静态方法,没关系。但是您不能覆盖静态方法,因为class不是一流的对象。您可以在运行时使用反射来获取对象的类,但是获取的对象与类层次结构不平行。
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()
。静态方法未绑定到对象,因此静态方法中this
也没有或的概念super
。静态方法是全局函数。结果,也没有多态性的概念,因此,方法覆盖是没有意义的。
但这可能是可能的,如果MyClass
在运行时是一个对象,您可以在该对象上调用方法,如Smalltalk中一样(或者,正如评论中提到的JRuby,但我对JRuby一无所知)。
哦,是的。还有一件事。您可以通过一个对象调用一个静态方法,obj1.staticMethod()
但是确实MyClass.staticMethod()
要避免使用语法上的糖。通常在现代IDE中会发出警告。我不知道他们为什么允许这个快捷方式。
clazz2 instanceof clazz1
正确使用class2.isAssignableFrom(clazz1)
,您可以改为使用,我相信在您的示例中该返回true。
通过动态分派可以实现方法覆盖,这意味着对象的声明类型并不决定其行为,而是确定其运行时类型:
Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"
即使lassie
和kermit
都被声明为type的对象Animal
,它们的行为(方法.speak()
)也有所不同,因为动态调度只会在运行时(而不是在编译时)将方法调用绑定.speak()
到实现。
现在,这里的static
关键字开始变得有意义了:单词“ static”是“ dynamic”的反义词。因此,您不能覆盖静态方法的原因是因为静态成员上没有动态分派- 因为静态字面意思是“非动态”。如果它们是动态调度的(因此可以被覆盖),则该static
关键字将不再有意义。
是。实际上,Java允许重写静态方法,从理论上讲,如果您不重写Java中的静态方法,那么它将可以编译和平稳运行,但是它将失去多态性,而后者是Java的基本属性。您将无处不在,无法尝试编译和运行。您将得到答案。例如,如果您有动物类和静态方法eat(),并且在其子类中覆盖了该静态方法,则将其称为Dog。然后,无论何时将Java对象的Dog对象分配给Animal Reference并调用eat(),都应该已经调用过Dog的eat(),但是在静态重写中,将会调用Animal的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使用了后期绑定,这意味着仅在运行时才调用方法,而在静态方法中则不会。在静态方法中,编译器会在编译时而不是在运行时调用方法,因此我们根据引用而不是根据对象来获取方法,而引用是根据包含的,因此您可以说实际上它支持静态覆盖,但是从理论上讲,它不支持没错
保留为实例成员保留以支持多态行为。静态类成员不属于特定实例。相反,静态成员属于该类,因此不支持覆盖,因为子类仅继承受保护的实例和公共实例成员,而不继承静态成员。您可能需要定义一个界面并研究工厂和/或策略设计模式,以评估替代方法。
在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风格)的新知识。
好吧……如果您从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,则此行应该与第三行相同,因为我们在运行时类型的对象上以“ SubClass”而不是“ SuperClass”调用“ staticMethod()”。这确认了静态方法始终仅使用其编译时类型信息来解析。
通常,不允许“覆盖”静态方法是没有意义的,因为没有很好的方法来确定在运行时调用哪个方法。以Employee为例,如果我们调用RegularEmployee.getBonusMultiplier()-应该执行哪个方法?
就Java而言,可以想象一种语言定义,只要通过对象实例调用静态方法,就可以“覆盖”静态方法。但是,所有这些操作将是重新实现常规的类方法,从而在没有真正增加任何好处的情况下为该语言添加冗余。
我喜欢Jay的评论(https://stackoverflow.com/a/2223803/1517187),并对其加倍。
我同意这是Java的不良设计。
正如我们在前面的评论中看到的,许多其他语言都支持重写静态方法。我觉得Jay也像我一样从Delphi来到Java。
Delphi(对象Pascal)是第一种实现OOP的语言。
显然,许多人都有使用该语言的经验,因为它是过去编写商业GUI产品的唯一语言。并且-是的,我们可以在Delphi中覆盖静态方法。实际上,Delphi中的静态方法称为“类方法”,而Delphi具有“ Delphi静态方法”的不同概念,即早期绑定的方法。要覆盖必须使用后期绑定的方法,请声明“虚拟”指令。因此,这非常方便且直观,我希望Java能够做到这一点。
重写静态方法有什么用处。您不能通过实例调用静态方法。
MyClass.static1()
MySubClass.static1() // If you overrode, you have to call it through MySubClass anyway.
编辑:看来,通过对语言设计的不幸监督,您可以通过实例调用静态方法。通常没有人这样做。我的错。
variable.staticMethod()
而不是在Class.staticMethod()
哪里variable
声明类型的变量Class
。我同意这是错误的语言设计。
Java中的重写只是意味着将根据对象的运行时类型而不是对象的编译时类型来调用特定方法(对于覆盖的静态方法就是这种情况)。由于静态方法是类方法,因此它们不是实例方法,因此它们与哪个引用指向哪个对象或实例无关,因为静态方法的性质使其属于特定类。您可以在子类中重新声明它,但是该子类对父类的静态方法一无所知,因为正如我所说,它仅特定于已声明其的类。使用对象引用访问它们只是Java设计人员的一种额外的自由,我们当然不应该只在他们限制更多细节和示例时才考虑停止这种实践。 http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html
通过覆盖,您可以实现动态多态。当说覆盖静态方法时,您要使用的单词是矛盾的。
静态说-编译时,覆盖用于动态多态。两者本质上是相反的,因此不能一起使用。
当程序员使用对象并访问实例方法时,就会出现动态多态行为。JRE将根据您使用的对象类型来映射不同类的不同实例方法。
当您说重写静态方法时,我们将使用类名来访问静态方法,该类名将在编译时链接,因此在运行时没有将方法与静态方法链接的概念。因此,术语“覆盖”静态方法本身没有任何意义。
注意:即使您使用对象访问类方法,java编译器仍然足够智能地找到它,并且将执行静态链接。
Box.createBox
更有意义,除了静态比有意义BoxFactory.createBox
,并且在需要进行错误检查构造而不会引发异常时(这是构造函数不能失败,它们只能杀死进程/抛出)是一种不可避免的模式。例外),而静态方法可以在失败时返回null,甚至接受成功/错误回调以编写类似hastebin.com/codajahati.java的内容。
这个问题的答案很简单,标记为static的方法或变量仅属于该类,因此static方法不能在子类中继承,因为它们仅属于超类。
简单的解决方案:使用单例实例。它将允许重写和继承。
在我的系统中,我具有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!";
}
}
Singleton.get()
。注册表只是样板操作,它排除了类上的GC。
静态方法,变量,块或嵌套类属于整个类而不是对象。
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类的static方法的功能。
同样,如果将getVehileNumber()声明为final,则代码将无法编译,因为final关键字限制了程序员重新声明该方法。
public static final int getVehileNumber() {
return VIN; }
总体而言,这取决于软件设计人员在哪里使用静态方法。我个人更喜欢使用静态方法来执行某些操作,而无需创建类的任何实例。其次,要隐藏外界的课堂行为。
这是一个简单的解释。静态方法与类相关联,而实例方法与特定对象相关联。覆盖允许调用与特定对象关联的覆盖方法的不同实现。因此,覆盖甚至不与对象关联而是首先与类本身关联的静态方法是违反直觉的。因此,不能基于调用该对象的对象来覆盖静态方法,它将始终与创建该对象的类相关联。
public abstract IBox createBox();
内部IBox界面如何反直观?Box可以实现IBox来覆盖createBox,并在有效的IBox中创建对象,否则返回null。构造函数无法返回“ null”,因此您被迫(1)使用异常EVERYWHERE(我们现在要做什么),或(2)创建工厂类来实现我之前所说的内容,但对新手或专家都没有意义Java(现在我们也这样做)。静态的未实现方法可以解决此问题。
现在看到上面的答案,每个人都知道我们不能覆盖静态方法,但是不应误解从子类访问静态方法的概念。
如果子类中定义的新静态方法尚未隐藏该静态方法,则可以使用子类引用访问父类的静态方法。
例如,请参见下面的代码:-
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的甲骨文文档和搜索在子类中,你可以做有关的子类的静态方法隐藏的细节。
谢谢
以下代码显示了可能的情况:
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();
}
}
osm
是OverridenStaticMeth
不OverrideStaticMeth
。