当一个类实现一个接口时,是否会使从该类实例化的对象被视为该接口的对象?
即。在实现Runnable接口的类上,是否会将从该类创建的实例称为Runnable对象?
因此,如果期望Runnable对象引用变量(例如,在方法或构造函数的参数中),为什么我们可以提供该类的实例作为该方法或构造函数的参数是合法的?是因为通过实现接口,类本质上是接口的对象吗?
答案 0 :(得分:5)
实现接口C
的类I
的对象可以被称为该接口的对象,尽管单个对象可以具有许多接口。 Liskov substitution principle要求C
可在需要I
的任何地方使用,因此基本上I
成为C
的合同,代表C
能力的一个子集,适用于某种情况。
例如,当一个对象实现Runnable
时,接口中的run()
方法将类的特定方面呈现给Java类库 - 即,类的对象可以“运行” (通过调用run()
)。 Runnable
的存在允许您独立于Java设计者编写线程的逻辑,Java设计人员独立于实现的逻辑编写其线程执行代码。
答案 1 :(得分:2)
可以引用Runnable,因为Runnable对象必须实现Runnable接口中的所有方法。
这样您就可以在运行时访问所有这些方法。
如果说实现Runnable的类不会以某种方式实现Runnable - 那么会出现编译错误,因为Java Language Specification 7 chapter 8 (classes) - 8.1.5 (superinterfaces)指定:
据说一个类实现了所有的超级接口。
给出的例子如下:
例8.1.5-3。超界面的实现方法
interface Colorable {
void setColor(int color);
int getColor();
}
class Point { int x, y; };
class ColoredPoint extends Point implements Colorable {
int color;
}
此程序导致编译时错误,因为ColoredPoint不是抽象类,但无法提供接口Colorable的方法setColor和getColor的实现。
答案 2 :(得分:2)
如果一个类实现了一个接口,它可以在任何可以使用接口类型的地方使用。例如,如果一个类实现Runnable
,那么该类的实例可以在任何可以使用Runnable
的地方使用。这是多态的一个例子。
例如,这是一个实现Runnable
的类:
public class MyRunner implements Runnable {
public void run() {}
}
您可以使用MyRunner
,如下所示:
MyRunner runner = new MyRunner();
// can assign to a field of type "Runnable" without a cast
Runnable runnable = runner;
// can pass to methods that take a Runnable
Executors.newFixedThreadPool(3).execute(runner);
MyRunner
类被称为Runnable
的实例。你甚至可以通过反思检查这个;
public void runIfIsRunnable(Object object) {
if (object instanceof Runnable) {
Runnable r = (Runnable) object;
r.run();
}
}
使用instanceof通常被认为是代码气味,但在某些情况下它很有用,就像通过反射创建类的实例一样。
答案 3 :(得分:1)
对象继承其父类接口,这些接口中的方法可以在子类中重写。
接口的价值在于它们允许通过接受接口类型作为输入来创建容纳各种对象类作为输入的方法。
实现接口的任何对象实际上都是"接口"能够实现它实现的给定接口。
类的接口实现意味着该类能够执行接口中指定的任何方法。因此,在接口上运行的任何方法都可以在实现接口的东西上运行。
答案 4 :(得分:0)
接口建立一个契约,该对象将包含接口中定义的方法,并且此契约由编译器强制执行。所以编译器会检查这个。
按照惯例,接口以" -ible"是" -able"显示这种行为(虽然这绝不是一个硬性规则)。但最后,对象的类型是java.lang.Object
或它的直接/间接扩展。如果查看任何Javadoc上的继承树,您将看到彼此扩展的类的层次结构以及已知的接口实现类。
因此,人们通常不会将类创建的对象称为接口的对象,而是将类实现类。