我已经读过接口和抽象类之间的区别,但是这个让人困惑。考虑这个接口和类。
interface I {
public int hashCode();
public boolean equals(Object obj);
}
class B implements I {
// Works Fine
}
这里工作正常,我不需要覆盖接口方法,因为Object是B的超类,并且这些方法在其中实现。
现在考虑这些
abstract class A {
public abstract int hashCode();
public abstract boolean equals(Object obj);
}
class C extends A {
// Compile error because methods are not overridden
}
为什么会导致编译错误?这是否意味着Object不是抽象类的超类?或者我错过了一些观点?
答案 0 :(得分:33)
导致编译错误,因为根据定义,抽象函数必须在继承链中实现 downstream 。您已经创建了他们必须在A
的子类中实现的要求。
类C
没有实现这些方法,因此编译失败。
Object
是抽象类的超类 ...但它不是子类,而子类负责实现抽象函数。
相反,如果一个类实现了一个接口,那么该实现可以在该类的继承层次结构中 where 。将这些实现放在超类中并不常见,因为您通常会在超类中声明接口。
在某些用例中,您可能不会像堕落/糟糕的设计那样,或者在阅读语言功能时使用这样的示例。
答案 1 :(得分:6)
正如其他人已经提到的,类A
通过将它们再次声明为抽象来覆盖Object
中的那些方法,因此它强制子类实现它们。
作为对您情况的澄清,请尝试按如下方式定义A
:
abstract class A {
//public abstract int hashCode();
//public abstract boolean equals(Object obj);
}
class C extends A {
// no compile error because no abstract methods have to be overridden
}
在这种情况下,A
和C
都继承了Object
中这些方法的实现,并且没有发生编译错误。
答案 2 :(得分:3)
Object是所有类的超类,抽象与否。
我相信当你将一个类声明为abstract并在其中声明抽象方法时,你强制任何子类实现它们,无论抽象类的超类是否已经实现它们。
这与Object类无关。如果您自己创建所有类,则会得到相同的行为:
public class A {
public int someMethod () {
return 1;
}
}
public abstract class B extends A {
public abstract int someMethod ();
}
public class C extends B {
}
这将给出编译错误The type C must implement the inherited abstract method B.someMethod()
,即使A已经实现了它。
答案 3 :(得分:3)
这是一个奇怪的情况,乍一看你可能会认为这是一个编译器错误来声明抽象类A。
事实上,您可能想要一些(不常见的)原因。例如,如果您想确保使用A类的每个人都实现了自己的equals和hashcode而不是依赖于Object版本,那么您可以这样做。
行为的实际解释是,为了扩展A类,您需要满足A类给您的每个要求。
在这种特殊情况下,A类说子类需要实现这些方法,超类实现它们的事实是无关紧要的,它本身就是在增加一个更具体的需求。
这里的对象没有什么特别之处:
abstract class A {
public abstract int hashCode();
public abstract boolean equals(Object obj);
public void test() {
}
}
abstract class B extends A {
public abstract void test();
}
现在,如果您尝试定义:
class C extends B {
public int hashCode() { return 1; }
public boolean equals(Object ob) { return false; }
}
然后说C is not abstract and does not override abstract method test() in B
。
答案 4 :(得分:1)
您的抽象类只有虚拟方法(没有实现的方法)。这意味着它们存在于类的接口中,因此有人可能会实际调用它们。在您针对hashCode
或equals
的情况下,此类调用将导致运行时错误,因为这些方法未实现。编译器通过引发编译器错误来防止这种情况发生。
答案 5 :(得分:1)
是的,Object是抽象类的超类。您可以使用注释@Override来帮助您。
请参阅以下代码中没有错误:
abstract class A
{
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
}
答案 6 :(得分:0)
每个类都扩展了Object。即使abstract
类扩展了Object,但抽象类不完整。您不能实例化一个抽象类,任何扩展抽象类的类都必须提供所有缺少的方法,或者它也必须声明为abstract。
这会导致编译错误吗?
试一试,看看!
答案 7 :(得分:0)
每个类都扩展了Object 。(所有类的父亲) 这是一个编译错误,因为你必须提供一个抽象类的主体。 而你的抽象类有方法,但没有任何正文。
答案 8 :(得分:0)
每当扩展一个抽象类时,你应该确保抽象类中的所有方法都必须在子类中实现,否则会导致编译错误。
答案 9 :(得分:0)
使用接口/抽象类之前要记住的要点=>
根据定义接口不能扩展类。
所有类(是否抽象)隐式扩展Object
作为父级
如果类明确地扩展了另一个父类,则它将继承Object
的方法
通过该父类的超类。
扩展抽象类的类必须实现所有继承的抽象方法,或者声明为抽象类本身
就您而言,
最初在Object
超类中实现的equals()和hashCode()被覆盖作为抽象类中的抽象方法隐式扩展。
因此,为避免编译错误,您必须在子类中实现继承的抽象方法或将子类本身声明为抽象。 没有别的办法。
答案 10 :(得分:0)
是的..抽象类像 Java 中的任何其他类一样扩展 Java.lang.Object 类。
当一个类没有扩展任何其他类时,编译器在编译期间插入“扩展 java.lang.Object”,这意味着,只有当一个类没有任何其他用户定义的父类时,它才会扩展 Object 类。
abstract class A {
public abstract int hashCode();
public abstract boolean equals(Object obj);
}
class C extends A {
// Compile error because methods are not overridden
}
这里,C 类已经扩展了 A,所以它不会扩展 Object 类。由于您没有提供 equals 方法的实现,您将看到编译错误。
答案 11 :(得分:-2)
是抽象类确实扩展了对象类。它继承了对象类的属性。我们不应该在这里混淆抽象类不能实例化。这将发生在抽象类的子类中,但在抽象类中,我们可以实例化对象类,并且可以覆盖基本实现。因此,对象类可以从抽象类继承。