是的,Thread 实现了Runnable。
正如 API 引用所述,可运行接口旨在为希望在活动时执行代码的对象提供通用协议。
您会感到困惑,因为在 Java 中有两种方法可以实现这种并发:
- 你可以扩展一个
Thread类覆盖默认的run方法,然后以类似于new MyThread().start()的方式调用线程
- 你可以编写一个实现
Runnable接口的类并以类似的方式启动它:new Thread(new MyRunnable()).start()
这些方法相同。事实上,Thread 类的run 方法通常调用附加到线程的Runnable 对象的run 方法,如果有,则返回。
拥有Runnable 接口有什么需要?它很有用,因为它声明了一个让类被视为具有特定特征的协议。
这与Comparable 接口或Serializable 接口相同,但在这里你实际上有一个方法可以覆盖(public void run()),而例如Serializable 只是你赋予你的类的一个特征。
最后一个例子是TimerTask 实现了Runnable。 TimerTask 与 Timer 类一起用于执行延迟或周期性任务,因此 timertask 也可以运行是有意义的,因此 Timer 可以使用该方法启动任务。
编辑:因为您似乎对接口的有用性感到困惑,所以您必须认为:Java 是一种静态类型语言。这是什么意思?这意味着它需要在编译期间了解有关类型的所有信息,才能保证不会抛出运行时类型错误。
好的,现在假设 Java API 支持一个 hipotetically 类来绘制形状。因此,您可以为形状编写自己的类,然后将它们提供给这个类(我们称之为ShapeDrawer)。
ShapeDrawer 需要知道如何绘制您传递给它的形状,唯一的方法是确定每个Shape 对象必须有一个名为@987654344 的方法@,以便ShapeDrawer 可以在您附加到它的每个Shape 上调用此方法,而无需了解更多信息。
所以你声明一个接口
public interface Shape
{
public void drawMe();
}
这些类可以被视为Shape。如果一个类是Shape,您可以毫无问题地将它传递给您的ShapeDrawer 类:
class ShapeDrawer
{
public void addShape(Shape shape) { ... }
public void drawShapes()
{
for (Shape s : shapes)
s.drawMe();
}
}
所以编译器很高兴,因为在添加形状时,您添加了 implements Shape 的类,您的类确切地知道如何绘制这些形状,并且开发人员很高兴,因为您将对象的 通用协议 与他们的具体实现。
这是一种契约,如果你想要一个能够被ShapeManager 绘制的Triangle 类,你必须声明该方法,以便你可以调用例如
shapeDrawerInstance.addShape(new Triangle())