2012-06-26 73 views
2

我只是想知道结果会是什么,如果我子类延伸Thread一类,我写了下面的代码和测试:重写run()方法

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(); 
    }  
} 

,其结果是:

线程0 B中
线程1

但我不明白为什么是两个线程s是否被创建?

回答

3

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

这是由于构造函数链。

2

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

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

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

,因为你是在A()构造开始他们两个线程开始:

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

,你是构建两个对象 - 一个A和延伸A一个B

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

默认情况下,当你说new B(),因为它没有一个无参数的构造函数,它会调用苏佩的无参数的构造函数rclass。所以它会调用启动线程的A构造函数。见Java documentation here。引用:

您不必为您的课程提供任何构造函数,但是在做这些时必须小心。编译器自动为任何没有构造函数的类提供一个无参数的默认构造函数。这个默认构造函数将调用超类的无参构造函数。在这种情况下,如果超没有一个无参数的构造函数,因此你必须确认它的编译器会抱怨。如果你的类没有明确的超类,那么它有对象的隐式父类,其中确实有一个无参数的构造函数。

另外,在构造函数中启动一个线程并不是一个好习惯。当你这样做时,可能会发生一些线程竞争条件。这是更好的调用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(); 
2

A延伸ThreadB延伸A,所以当你创建的A实例和B一个实例,您已经创建的Thread两个实例。

注意,它通常优选延长Thread,而是要只是实施Runnable - 然后传递RunnableThread(Runnable)构造。从设计的角度来看,这最终会变得更清晰 - 你并不是真的想要改变线程行为,你只是给它一个不同的任务来执行。

(这也是通常最好使用java.util.concurrent中,而不是直接在第一时间创建线程的设施,但我们去...)越来越创建

1

2个线程,因为你是问为它通过运行以下行:

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