为什么是 super.super.method(); Java中不允许?
我读了
@Override
public String toString() {
return super.super.toString();
}
我不确定它在很多情况下是否有用,但我想知道为什么 事实并非如此,如果其他语言中也存在类似的情况。
你们有什么感想?
编辑: 澄清一下:是的,我知道,这在 Java 中是不可能的,而且我并不真正怀念它。 这不是我期望的工作,并且很惊讶收到编译器错误。 我只是有这个想法并想讨论它。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
我认为以下代码允许在大多数情况下使用 super.super...super.method() 。
(即使这样做很丑)
简而言之,
用法:
I think the following code allow to use super.super...super.method() in most case.
(even if it's uggly to do that)
In short
Usage :
我没有足够的声誉来发表评论,因此我会将其添加到其他答案中。
乔恩·斯基特(Jon Skeet)的回答非常出色,并举了一个很好的例子。 Matt B 有一个观点:并非所有超类都有超类。 如果您调用没有超级的超级的超级,您的代码将会崩溃。
面向对象编程(Java 就是这样)是关于对象的,而不是函数。 如果您想要面向任务的编程,请选择 C++ 或其他语言。 如果你的对象不适合它的超类,那么你需要将它添加到“祖父母类”,创建一个新类,或者找到另一个它适合的超类。
就我个人而言,我发现这个限制是 Java 最大的优势之一。 与我使用过的其他语言相比,代码有些僵化,但我总是知道会发生什么。 这有助于实现 Java 的“简单且熟悉”的目标。 在我看来,调用 super.super 并不简单也不熟悉。 或许开发商也有同感?
I don't have enough reputation to comment so I will add this to the other answers.
Jon Skeet answers excellently, with a beautiful example. Matt B has a point: not all superclasses have supers. Your code would break if you called a super of a super that had no super.
Object oriented programming (which Java is) is all about objects, not functions. If you want task oriented programming, choose C++ or something else. If your object doesn't fit in it's super class, then you need to add it to the "grandparent class", create a new class, or find another super it does fit into.
Personally, I have found this limitation to be one of Java's greatest strengths. Code is somewhat rigid compared to other languages I've used, but I always know what to expect. This helps with the "simple and familiar" goal of Java. In my mind, calling super.super is not simple or familiar. Perhaps the developers felt the same?
这样做有一些充分的理由。 您可能有一个子类,该子类的方法实现不正确,但父类方法实现正确。 因为它属于第三方库,所以您可能无法/不愿意更改源。 在这种情况下,您想要创建一个子类,但重写一个方法来调用 super.super 方法。
正如其他一些海报所示,可以通过反射来做到这一点,但应该可以做类似
(SuperSuperClass this).theMethod(); 的
事情。 我现在正在处理这个问题 - 快速解决方法是将超类方法复制并粘贴到子子类方法中:)
There's some good reasons to do this. You might have a subclass which has a method which is implemented incorrectly, but the parent method is implemented correctly. Because it belongs to a third party library, you might be unable/unwilling to change the source. In this case, you want to create a subclass but override one method to call the super.super method.
As shown by some other posters, it is possible to do this through reflection, but it should be possible to do something like
(SuperSuperClass this).theMethod();
I'm dealing with this problem right now - the quick fix is to copy and paste the superclass method into the subsubclass method :)
除了其他人提出的非常好的观点之外,我认为还有另一个原因:如果超类没有超类怎么办?
由于每个类自然地扩展(至少)
Object
,因此super.whatever()
将始终引用超类中的方法。 但是,如果您的类仅扩展Object
呢?那么super.super
会指代什么呢? 应该如何处理该行为 - 编译器错误、空指针等?我认为不允许这样做的主要原因是它违反了封装,但这也可能是一个小原因。
In addition to the very good points that others have made, I think there's another reason: what if the superclass does not have a superclass?
Since every class naturally extends (at least)
Object
,super.whatever()
will always refer to a method in the superclass. But what if your class only extendsObject
- what wouldsuper.super
refer to then? How should that behavior be handled - a compiler error, a NullPointer, etc?I think the primary reason why this is not allowed is that it violates encapsulation, but this might be a small reason too.
我认为,如果您覆盖一个方法并想要它的所有超类版本(例如
equals
),那么您实际上总是希望首先调用直接超类版本,哪个版本将调用如果需要的话,依次调用其超类版本。我认为调用某个方法的任意超类版本几乎没有意义(如果有的话。我想不出它的情况)。 我不知道这在 Java 中是否可行。 可以用 C++ 完成:
I think if you overwrite a method and want to all the super-class version of it (like, say for
equals
), then you virtually always want to call the direct superclass version first, which one will call its superclass version in turn if it wants.I think it only makes rarely sense (if at all. i can't think of a case where it does) to call some arbitrary superclass' version of a method. I don't know if that is possible at all in Java. It can be done in C++:
猜测是因为它不经常使用。 我看到使用它的唯一原因是如果您的直接父母覆盖了某些功能并且您试图将其恢复为原始状态。
在我看来,这违反了面向对象的原则,因为类的直接父类应该比祖父母与你的类的关系更密切。
At a guess, because it's not used that often. The only reason I could see using it is if your direct parent has overridden some functionality and you're trying to restore it back to the original.
Which seems to me to be against OO principles, since the class's direct parent should be more closely related to your class than the grandparent is.
当您无法更改基类的代码时,调用 super.super.method() 是有意义的。 当您扩展现有库时,通常会发生这种情况。
首先问问自己,为什么要延长这门课? 如果答案是“因为我无法更改它”,那么您可以在应用程序中创建精确的包和类,并重写顽皮的方法或创建委托:
例如,您可以创建 org.springframework.test.context.junit4 .SpringJUnit4ClassRunner 类在您的应用程序中,因此该类应该在 jar 中的真实类之前加载。 然后重写方法或构造函数。
注意:这绝对是黑客行为,强烈不建议使用,但它确实有效! 使用这种方法是危险的,因为类加载器可能会出现问题。 此外,每次更新包含被覆盖类的库时,这都可能会导致问题。
Calling of super.super.method() make sense when you can't change code of base class. This often happens when you are extending an existing library.
Ask yourself first, why are you extending that class? If answer is "because I can't change it" then you can create exact package and class in your application, and rewrite naughty method or create delegate:
For instance, you can create org.springframework.test.context.junit4.SpringJUnit4ClassRunner class in your application so this class should be loaded before the real one from jar. Then rewrite methods or constructors.
Attention: This is absolute hack, and it is highly NOT recommended to use but it's WORKING! Using of this approach is dangerous because of possible issues with class loaders. Also this may cause issues each time you will update library that contains overwritten class.
@Jon Skeet 很好的解释。
在我看来,如果有人想要调用 super.super 方法,那么一定是想要忽略直接父级的行为,但想要访问祖父级的行为。
这可以通过实例化来实现。 如下代码所示
,这是驱动程序类,
其输出将是
B 类 printClass 行为在这种情况下将被忽略。
我不确定这是否是实现 super.super 的理想或良好实践,但它仍然有效。
@Jon Skeet Nice explanation.
IMO if some one wants to call super.super method then one must be want to ignore the behavior of immediate parent, but want to access the grand parent behavior.
This can be achieved through instance Of. As below code
Here is driver class,
Output of this will be
Class B printClass behavior will be ignored in this case.
I am not sure about is this a ideal or good practice to achieve super.super, but still it is working.
查看 这个 Github 项目,尤其是 objectHandle 变量。 该项目展示了如何实际准确地调用孙子的祖父母方法。
以防万一链接被破坏,这里是代码:
快乐编码!!!!
Look at this Github project, especially the objectHandle variable. This project shows how to actually and accurately call the grandparent method on a grandchild.
Just in case the link gets broken, here is the code:
Happy Coding!!!!
如果可能的话,我会将 super.super 方法体放在另一个方法中
或者如果你无法更改 super-super 类,你可以尝试这样做:
在这两种情况下,
结果都是“我是超级超级”
I would put the super.super method body in another method, if possible
Or if you cannot change the super-super class, you can try this:
In both cases, the
results to "I am super super"
使用反射至少可以获得超类的超类的类,尽管不一定是它的实例; 如果这可能有用,请考虑 http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
It would seem to be possible to at least get the class of the superclass's superclass, though not necessarily the instance of it, using reflection; if this might be useful, please consider the Javadoc at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
跑步:
A
构建成功(总时间:0 秒)
run:
A
BUILD SUCCESSFUL (total time: 0 seconds)
当架构要在代表多个派生类实现的通用 CustomBaseClass 中构建通用功能时,我遇到过类似的情况。
但是,我们需要规避特定派生类的特定方法的通用逻辑。 在这种情况下,我们必须使用 super.super.methodX 实现。
我们通过在 CustomBaseClass 中引入一个布尔成员来实现这一点,该成员可用于有选择地推迟自定义实现并在需要时屈服于默认框架实现。
然而,通过在框架和应用程序中遵循良好的架构原则,我们可以通过使用 hasA 方法而不是 isA 方法轻松避免这种情况。 但在任何时候,期望设计良好的架构都不太现实,因此需要摆脱可靠的设计原则并引入这样的黑客。
只是我的2分钱...
I have had situations like these when the architecture is to build common functionality in a common CustomBaseClass which implements on behalf of several derived classes.
However, we need to circumvent common logic for specific method for a specific derived class. In such cases, we must use a super.super.methodX implementation.
We achieve this by introducing a boolean member in the CustomBaseClass, which can be used to selectively defer custom implementation and yield to default framework implementation where desirable.
However, with good architecture principles followed in framework as well as app, we could avoid such situations easily, by using hasA approach, instead of isA approach. But at all times it is not very practical to expect well designed architecture in place, and hence the need to get away from solid design principles and introduce hacks like this.
Just my 2 cents...
IMO,这是在 Java 中实现 super.super.sayYourName() 行为的一种简洁方法。
输出:
请求撒谎:d.sayYourName(true) 返回 Grandma Fedora
请求不要说谎:d.sayYourName(false) 返回小女孩玛莎
IMO, it's a clean way to achieve
super.super.sayYourName()
behavior in Java.Output:
Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha
我认为这是一个破坏继承协议的问题。
通过扩展一个类,您遵守/同意其行为、功能
当调用
super.super.method()
时,您想打破自己的服从协议。您不能从超类中挑选。
然而,可能会出现这样的情况:您觉得需要调用
super.super.method()
- 通常是一个糟糕的设计标志,在您的代码或您继承的代码中!如果super和super super类无法重构(一些遗留代码),那么选择组合而不是继承。
封装破坏是指通过破坏封装的代码来@Override某些方法。
设计为不被覆盖的方法被标记
最终。
I think this is a problem that breaks the inheritance agreement.
By extending a class you obey / agree its behavior, features
Whilst when calling
super.super.method()
, you want to break your own obedience agreement.You just cannot cherry pick from the super class.
However, there may happen situations when you feel the need to call
super.super.method()
- usually a bad design sign, in your code or in the code you inherit !If the super and super super classes cannot be refactored (some legacy code), then opt for composition over inheritance.
Encapsulation breaking is when you @Override some methods by breaking the encapsulated code.
The methods designed not to be overridden are marked
final.
在 C# 中,您可以像这样调用任何祖先的方法:
您也可以在 Delphi 中执行此操作:
但在 Java 中,您只能通过某些设备来实现这种集中。 一种可能的方法是:
objC.DoIt() 结果输出:
In C# you can call a method of any ancestor like this:
Also you can do this in Delphi:
But in Java you can do such focus only by some gear. One possible way is:
objC.DoIt() result output:
这很容易做到。 例如:
B 的 C 子类和 A 的 B 子类。例如,这三个类都有方法 methodName()。
运行 C 类输出将是:
A级
C类
代替输出:
A级
B级
C级
It is simply easy to do. For instance:
C subclass of B and B subclass of A. Both of three have method methodName() for example.
Run class C Output will be:
Class A
Class C
Instead of output:
Class A
Class B
Class C
如果您认为需要超类,则可以在该类的变量中引用它。 例如:
应该打印出:
If you think you are going to be needing the superclass, you could reference it in a variable for that class. For example:
Should print out:
输出: 打印在 GrandDad 中
Output: Printed in the GrandDad
关键字 super 只是调用超类中方法的一种方式。
在 Java 教程中:https://docs.oracle.com/javase /tutorial/java/IandI/super.html
如果您的方法重写了其超类的方法之一,则可以通过使用关键字 super 来调用被重写的方法。
不要相信这是超级对象的引用!!! 不,它只是调用超类中方法的关键字。
下面是一个示例:
当您调用
cat.doSth()
时,Animal
类中的方法doSth()
将打印this< /code> 它是一只猫。
The keyword super is just a way to invoke the method in the superclass.
In the Java tutorial:https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super.
Don't believe that it's a reference of the super object!!! No, it's just a keyword to invoke methods in the superclass.
Here is an example:
When you call
cat.doSth()
, the methoddoSth()
in classAnimal
will printthis
and it is a cat.它违反了封装性。 您不应该能够绕过父类的行为。 有时能够绕过您自己的类的行为(特别是在同一方法中)而不是您父类的行为是有意义的。 例如,假设我们有一个基础“项目集合”,一个代表“红色项目集合”的子类以及代表“大红色项目集合”的子类。 这是有道理的:
没关系 - RedItems 始终可以确信它包含的项目都是红色的。 现在假设我们能够调用super.super.add():
现在我们可以添加任何我们喜欢的内容,并且
RedItems
中的不变量被破坏了。那有意义吗?
It violates encapsulation. You shouldn't be able to bypass the parent class's behaviour. It makes sense to sometimes be able to bypass your own class's behaviour (particularly from within the same method) but not your parent's. For example, suppose we have a base "collection of items", a subclass representing "a collection of red items" and a subclass of that representing "a collection of big red items". It makes sense to have:
That's fine - RedItems can always be confident that the items it contains are all red. Now suppose we were able to call super.super.add():
Now we could add whatever we like, and the invariant in
RedItems
is broken.Does that make sense?
我认为乔恩·斯基特有正确的答案。 我想补充一点,您可以通过转换
this
: 来访问超类的超类中的隐藏变量:这会产生输出:(
来自 JLS)
但是,这不起作用对于方法调用,因为方法调用是根据对象的运行时类型确定的。
I think Jon Skeet has the correct answer. I'd just like to add that you can access shadowed variables from superclasses of superclasses by casting
this
:which produces the output:
(example from the JLS)
However, this doesn't work for method calls because method calls are determined based on the runtime type of the object.