重写Thread子类中的run()方法

时间:2012-06-26 13:32:11

标签: java inheritance class-hierarchy

我只是想知道如果我继承了一个扩展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

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

5 个答案:

答案 0 :(得分:3)

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

这是由于构造函数链接。

答案 1 :(得分:2)

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

public static void main(String[] args) {
    A a = new A(); // #1
    B b = new B(); // #2
}

答案 2 :(得分:2)

  

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

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

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

并且您正在构建两个对象 - AB扩展A

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

默认情况下,当你说new B()因为它没有no-arg构造函数时,它会调用超类的no-arg构造函数。所以它将调用启动线程的A构造函数。见Java documentation here。引用:

  

您不必为您的班级提供任何构造函数,但在执行此操作时必须小心。编译器自动为没有构造函数的任何类提供无参数的默认构造函数。此默认构造函数将调用超类的无参数构造函数。在这种情况下,如果超类没有无参数构造函数,编译器将会抱怨,因此您必须验证它是否存在。如果你的类没有显式的超类,那么它有一个隐式的超类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();

答案 3 :(得分:2)

A扩展ThreadB扩展A,因此当您创建A的实例和B的实例时,已经创建了Thread的两个实例。

请注意,通常首选来扩展Thread,而是实现Runnable - 然后传递RunnableThread(Runnable)构造函数。从设计的角度来看,这最终变得更加清晰 - 你并没有真正尝试改变线程行为,你只是给它一个不同的任务来执行。

(通常最好使用java.util.concurrent中的工具而不是直接创建线程,但我们去......)

答案 4 :(得分:1)

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

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