2

我只是想知道如果我对一个扩展的类进行子类化Thread并编写以下代码并进行测试,结果会是什么:

class A extends Thread {
    public A() {
        this.start();
    }
    public void run() {
        System.out.println(" in A " + Thread.currentThread().getName());
    }
}

class B extends A {
    public void run() {
        System.out.println(" in B " + Thread.currentThread().getName());
    }
}

public class OverrideRun {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
    }    
}

结果是:

在 A Thread-0
中在 B Thread-1 中

但我不明白为什么要创建两个线程?

4

5 回答 5

3

这是因为该B b = new B();语句不调用 class 的参数参数,B并且不调用 class 的参数参数构造函数(默认)A

这是由于构造函数链接。

于 2012-06-26T13:34:46.767 回答
2

那是因为在这里创建了两个线程(从 继承的两个对象Thread):

public static void main(String[] args) {
    A a = new A(); // #1
    B b = new B(); // #2
}
于 2012-06-26T13:34:54.100 回答
2

但我不明白为什么要创建两个线程?

启动了两个线程,因为您在构造函数中启动它们A()

public A() {
    this.start();
}

并且您正在构建两个对象 - anA和 a Bwhich extends A

    A a = new A();
    B b = new B();

默认情况下,当你说它new B()没有无参数构造函数时,它会调用超类的无参数构造函数。所以它将调用A启动线程的构造函数。请参阅此处的 Java 文档。去引用:

您不必为您的类提供任何构造函数,但这样做时必须小心。编译器会自动为任何没有构造函数的类提供无参数的默认构造函数。此默认构造函数将调用超类的无参数构造函数。在这种情况下,如果超类没有无参数构造函数,编译器会报错,因此您必须验证它是否存在。如果你的类没有显式的超类,那么它有一个 Object 的隐式超类,它确实有一个无参数的构造函数。

顺便说一句,在它的构造函数中启动一个线程并不是一个好习惯。执行此操作时可能会发生一些线程竞争情况。a.start()打电话后打电话要好得多new A()Runnable此外,定义一个实现而不是扩展的类是一种更好的模式Thread。所以你的代码应该是:

class A implements Runnable() {
     public A() {
         // don't start it here
     }
     public void run() {
         ...
     }
}
...

Thread a = new Thread(new A());
a.start();
Thread b = new Thread(new B());
b.start();
于 2012-06-26T13:35:04.877 回答
2

Aextends ThreadBextends A,所以当你创建一个实例A和一个实例时B,你已经创建了两个实例Thread

请注意,通常最好不要扩展Thread,而是实现Runnable- 然后将其传递RunnableThread(Runnable)构造函数。从设计的角度来看,这最终会变得更干净——你并不是真的试图改变线程行为,你只是给它一个不同的任务来执行。

(通常最好使用 java.util.concurrent 中的设施,而不是一开始就直接创建线程,但是我们开始了......)

于 2012-06-26T13:35:11.483 回答
1

正在创建 2 个线程,因为您通过运行以下行来请求它:

    A a = new A();
    B b = new B();
于 2012-06-26T13:36:08.403 回答