Tim*_*the 347 java superclass
我读了这个问题并认为如果有人可以写的话很容易解决(不是没有它可以解决):
@Override
public String toString() {
return super.super.toString();
}
Run Code Online (Sandbox Code Playgroud)
我不确定它在许多情况下是否有用,但我想知道为什么它不是,如果这样的东西存在于其他语言中.
你们有什么感想?
编辑: 澄清:是的,我知道,这在Java中是不可能的,我不会真的错过它.这不是我期望的工作,并且惊讶于编译错误.我刚才有了这个想法并想讨论它.
Jon*_*eet 466
它违反了封装.您不应该绕过父类的行为.有时候能够绕过你自己班级的行为(特别是在同一个方法中)而不是你父母的行为是有意义的.例如,假设我们有一个基础"项目集合",一个表示"红色项目集合"的子类,以及表示"大红色项目集合"的子类.有:有意义:
public class Items
{
public void add(Item item) { ... }
}
public class RedItems extends Items
{
@Override
public void add(Item item)
{
if (!item.isRed())
{
throw new NotRedItemException();
}
super.add(item);
}
}
public class BigRedItems extends RedItems
{
@Override
public void add(Item item)
{
if (!item.isBig())
{
throw new NotBigItemException();
}
super.add(item);
}
}
Run Code Online (Sandbox Code Playgroud)
没关系 - RedItems总是可以确信它包含的项目都是红色的.现在假设我们都能够调用super.super.add():
public class NaughtyItems extends RedItems
{
@Override
public void add(Item item)
{
// I don't care if it's red or not. Take that, RedItems!
super.super.add(item);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以添加任何我们喜欢的内容,并且不变量RedItems就会被破坏.
那有意义吗?
Mic*_*ers 68
我认为Jon Skeet有正确的答案.我想补充一点,您可以通过强制转换来从超类的超类访问阴影变量this:
interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
int x = 3;
void test() {
System.out.println("x=\t\t" + x);
System.out.println("super.x=\t\t" + super.x);
System.out.println("((T2)this).x=\t" + ((T2)this).x);
System.out.println("((T1)this).x=\t" + ((T1)this).x);
System.out.println("((I)this).x=\t" + ((I)this).x);
}
}
class Test {
public static void main(String[] args) {
new T3().test();
}
}
Run Code Online (Sandbox Code Playgroud)
产生输出:
x= 3 super.x= 2 ((T2)this).x= 2 ((T1)this).x= 1 ((I)this).x= 0
(来自JLS的例子)
但是,这不适用于方法调用,因为方法调用是根据对象的运行时类型确定的.
小智 39
我认为以下代码允许在大多数情况下使用super.super ... super.method().(即使这样做很可取)
简而言之
用法:
public class A {
public void doThat() { ... }
}
public class B extends A {
public void doThat() { /* don't call super.doThat() */ }
}
public class C extends B {
public void doThat() {
Magic.exec(A.class, this, "doThat");
}
}
public class Magic {
public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
String methodOfParentToExec) {
try {
Type type = oneSuperType.newInstance();
shareVars(oneSuperType, instance, type);
oneSuperType.getMethod(methodOfParentToExec).invoke(type);
shareVars(oneSuperType, type, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
Class<?> loop = clazz;
do {
for (Field f : loop.getDeclaredFields()) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(target, f.get(source));
}
loop = loop.getSuperclass();
} while (loop != Object.class);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 11
我没有足够的声誉来评论,所以我会将其添加到其他答案中.
Jon Skeet以一个美丽的榜样出色地回答.Matt B有一个观点:并非所有超类都有超级.如果你打电话给一个没有超级超级的super,你的代码就会破坏.
面向对象编程(Java是)是关于对象而不是函数.如果您想要面向任务的编程,请选择C++或其他.如果你的对象不适合它的超级类,那么你需要将它添加到"祖父母类",创建一个新类,或找到它适合的另一个超类.
就个人而言,我发现这个限制是Java最大的优势之一.与我使用的其他语言相比,代码有点僵硬,但我总是知道会发生什么.这有助于Java的"简单和熟悉"目标.在我看来,调用super.super并不简单或熟悉.也许开发人员也有同样的感受?
这样做有一些很好的理由.您可能有一个子类,其子方法实现不正确,但父方法正确实现.因为它属于第三方库,您可能无法/不愿意更改源.在这种情况下,您希望创建一个子类,但重写一个方法来调用super.super方法.
正如其他一些海报所示,可以通过反射来做到这一点,但应该可以做类似的事情
(SuperSuperClass this).theMethod();
我正在处理这个问题 - 快速解决方法是将超类方法复制并粘贴到子类方法中:)
除了其他人提出的非常好的观点之外,我认为还有另一个原因:如果超类没有超类怎么办?
由于每个类自然地扩展(至少)Object,所以super.whatever()总是引用超类中的方法.但是,如果你的课程只延伸了Object- 那会super.super是什么意思呢?应该如何处理这种行为 - 编译错误,NullPointer等?
我认为不允许这样做的主要原因是它违反了封装,但这也可能是一个小原因.
我认为,如果您覆盖一个方法并想要它的所有超类版本(例如 for equals),那么您实际上总是希望首先调用直接超类版本,如果需要,哪个版本将依次调用其超类版本。
我认为调用某个方法的任意超类版本几乎没有意义(如果有的话。我想不出它的情况)。我不知道这在 Java 中是否可行。可以用 C++ 完成:
this->ReallyTheBase::foo();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
155797 次 |
| 最近记录: |