黑马程序员技术交流社区

标题: 有一个讲解不太明白,求大神帮我理清思路 [打印本页]

作者: syb012    时间: 2015-11-10 17:57
标题: 有一个讲解不太明白,求大神帮我理清思路
本帖最后由 syb012 于 2015-11-10 17:59 编辑

复制代码
来源于阳哥视频第14天最后一个关于面试题的视频
  1. public class TreadTest {

  2.         public static void main(String[] args)
  3.         {
  4.                 new Thread(new Runnable()
  5.                 {
  6.                         public void run()
  7.                         {
  8.                                 System.out.println("Runnable...run");
  9.                         }
  10.                 })
  11.                 {
  12.                         public void run()
  13.                         {
  14.                                 System.out.println("subThread...run");
  15.                         }
  16.                 }.start();//以子类为主。为什么?。自己的理解:如果不以子类为主,这个语句将不通顺,父类对象后无法再加大括号。
  17.         }

  18. }
复制代码






感觉我自己的理解还是不太对,为什么要以子类为主呢?如果把它分开写可以吗?

这个代码还可以写成:
  1. class R implements Runnable
  2. {
  3.         public void run()
  4.         {
  5.                 System.out.println("Runnable...run");
  6.         }
  7. }

  8. public class ThreadTest2
  9. {

  10.         public static void main(String[] args)
  11.         {
  12.                 R r=new R();
  13.                 new Thread(r)
  14.                 {
  15.                         public void run()
  16.                         {
  17.                                 System.out.println("subThread...run");
  18.                         }
  19.                 }.start();
  20.         }        
  21. }
复制代码

这是,有一个问题,如果以子类为主,那么可以理解成在主函数中创建了一个对象,这个对象是线程子类的对象,并且在建立子类对象的时候进行了参数传递,传递了任务对象r。

但是子类对象只覆盖了父类的run函数,子类中并没有带有传递参数的构造函数,如果把匿名子类对象命名,会出现以下语句拆写困难
  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 }.start();
复制代码

,比如,如果写成
  1. class R implements Runnable
  2. {
  3.         public void run()
  4.         {
  5.                 System.out.println("Runnable...run");
  6.         }
  7. }

  8. public class ThreadTest2
  9. {

  10.         public static void main(String[] args)
  11.         {
  12.                 R r=new R();               
  13.                 /*new Thread(r)
  14.                 {
  15.                         public void run()
  16.                         {
  17.                                 System.out.println("subThread...run");
  18.                         }
  19.                 }.start();*/
  20.                
  21.                 //Sub s=new Sub(r);//第一种:会报错,没办法传递参数r
  22.                 //Thread t= new Sub(r);//第二种,会报错,还是没办法传递参数r
  23.                 //Thread t=new Thread(r);//第三种,不会报错,但是与Thread的子类完全没有关系
  24.                 /*Sub b=new Sub();
  25.                 Thread t=(Thread)b;第四种:还是没办法传递参数*/
  26.                
  27.         }        
  28. }

  29. class Sub extends Thread
  30. {
  31.         public void run()
  32.         {
  33.                 System.out.println("subThread...run");
  34.         }
  35. }
复制代码

这么看来,好像只要写成匿名内部类的时候,才能在创建Thread子类对象的同时也传递了任务对象。

我似乎偏离了最初的思考问题的轨道。那个语句之所以运行结果打印的子类里的方法,是因为run方法覆盖了Thread原来的run方法,所以没办法运行到任务对象里的run方法。

可是,如果以任务为主,这句话就是先建立了Thread对象,那么后面的大括号就没有了意义。当以子类为主理解时才有意义。我好像又回到了最初的起点。
求大神棒我理清思路!!!!!!!

作者: syb012    时间: 2015-11-10 19:09

作者: dongran    时间: 2015-11-10 19:15
问老师吧...
作者: syb012    时间: 2015-11-11 02:39
dongran 发表于 2015-11-10 19:15
问老师吧...

那你帮我圈个老师来吧
作者: 雨来    时间: 2015-11-11 11:23
过来看一下,好复习
作者: syb012    时间: 2015-11-11 16:28
雨来 发表于 2015-11-11 11:23
过来看一下,好复习

那这个地方你是咋理解的啊?为什么这句代码没错呢?为什么这句代码以子类为主呢?
作者: 海狮    时间: 2015-11-11 17:23
什么叫以子类为主啊。。。。
作者: 1379号监听员    时间: 2015-11-11 18:09
还没学到,帮不了你哟
作者: syb012    时间: 2015-11-11 20:01
1379号监听员 发表于 2015-11-11 18:09
还没学到,帮不了你哟


作者: 萧未然    时间: 2015-11-11 20:41
  1. /**
  2. * Thread--Runnable
  3. * @author Administrator
  4. *
  5. */
  6. public class ThreadTest {

  7.         public static void main(String[] args) {
  8.                 //我的看法是把程序拆解来看
  9.                 /*
  10.                 new Thread(new Runnable(){
  11.                         public void run(){
  12.                                
  13.                         }
  14.                 }){
  15.                         public void run(){
  16.                                
  17.                         }
  18.                 };*/
  19.                 //发现没,这样写是不会报错的
  20.                 /**
  21.                  * 那么说明什么呢?
  22.                  * 其实和下面:
  23.                  */
  24.                 /*
  25.                 new Runnable(){
  26.                         public void run(){}
  27.                 };*/
  28.                 //这是Runnable实现是一个道理的
  29.                 /*
  30.                  * 下面
  31.                  * */
  32.                 new Thread(){
  33.                         //public void run(){}//这里是继承Thread类
  34.                 };
  35.                 /**
  36.                  * 不知道还记得不,创建线程的两种方式:一种是继承Thread类
  37.                  * 一种是实现Runnable接口
  38.                  * 而下面:
  39.                  */
  40.                 new Thread(new Runnable(){
  41.                         public void run(){
  42.                                 System.out.println(1);
  43.                         }
  44.                 }){
  45.                         public void run(){
  46.                                 System.out.println(2);
  47.                         }
  48.                 }.start();
  49.                 /*
  50.                  * 其实容易混淆的是这个部分:Java虽然没有多继承,但是有多实现代替了
  51.                  * 而放到这个题目上是:他们一个继承了Thread类,一个实现了Runnable接口
  52.                  * 方式不同,但是同为匿名子类
  53.                  * 重点:始终,我们只调用了一次,start()方法
  54.                  * 现在的问题变成了:这个start()方法是谁的?
  55.                  * 仔细看不难发现,程序开始是哪个实例在执行?呼之既出了,Thread
  56.                  * */
  57.                
  58.         }
  59. }
复制代码

作者: 冰霜之卅    时间: 2015-11-11 21:37
萧未然 发表于 2015-11-11 20:41


分析的很对。  

但是这么写代码。   
还真是操蛋!
作者: 萧未然    时间: 2015-11-11 22:46
冰霜之卅 发表于 2015-11-11 21:37
分析的很对。  

但是这么写代码。   

我喜欢比较通俗点的啦,您觉得哪些地方需要改正的呢,因为自己也在写代码,就没分开写了,勿怪咯{:2_36:}
作者: syb012    时间: 2015-11-12 19:21
本帖最后由 syb012 于 2015-11-12 20:16 编辑
萧未然 发表于 2015-11-11 20:41

最后一句,程序是哪个实例调用了start方法。那么这个程序有多少个实例呢?

一个是实现Runnable接口的任务实例,但它不能之间调用start方法,它必须作为Thread的构造函数参数生成新
Thread的实例才能调用start方法。记为实例①

另一个实例是继承Thread类的匿名子类对象,它也可以调用start方法。记为实例②

你说的没有错,只能有一个实例调用了start方法,从运行结果可以得出调用start方法的是实例②。
既Thread类的匿名子类对象调用了start方法,而不是实现Runnable接口的任务对象间接调用。

可是为什么呢?我知道结果却不知道原因,有点不甘心。视频里毕老师说必须是以子类为主,我可以验证,可就是理解不了。为什么当“Thread类的匿名子类对象”和“以实现Runnable接口的任务对象作为参数的Thread实例”同时存在时,是前者而不是后者调用start方法?

又把那段视频看了一遍,毕老师说必须以子类为主是因为子类的run方法覆盖了父类的。我不太喜欢这个原因,因为任务对象作为参数传给Thread的构造函数生成的新的对象如果调用start,再执行run方法应该和Thread的匿名子类没有关系才是。因为那个子类里没有带参数的构造函数,所以不可能是把任务对象作为参数传给了Thread的匿名子类。既然毫无关系,不是多态,又怎么会覆盖呢?

作者: 萧未然    时间: 2015-11-12 21:49
syb012 发表于 2015-11-12 19:21
最后一句,程序是哪个实例调用了start方法。那么这个程序有多少个实例呢?

一个是实现Runnable接口的任务 ...

首先,毕老师从多态的角度讲解很专业,毕老师杠杠滴!
我们知道,Thread类实现了Runnable接口.
这里,通过查阅API可以发现(毕老师也查看过),从栈堆的角度去分析:
先看这个都知道的:
String name="张三";//一个对象
name="李四";//另一个对象
这个怎么理解大家都知道,就是栈内存中变量name在堆中的地址值指向发生了改变...
!--new Thread(new Runnable(){public void run(){}}){public void run(){}};
不偷懒,把它写全:
Thread thread=new Thread(new Runnable(){public void run(){}}){public void run(){}};
把他们分开:(当然)
因为有两个new,必然在堆内存中产生了两个对象--实例;
在理解的过程中我们可以这么想:
首先:thread指向了new Thread(new Runnable(){});
然后,thread改成了指向Thread的子类对象new Thread(){public void run(){}};
//他们都是可以独立运行的,不同的是,至始至终,栈内存中只有一个thread,所以
就是"李四"了
也就是说:最终只有一个结果:那就是Thread子类被thread指向
那么:
//伪代码
new Thread(new Runnable(){public void run(){}}){public void run(){}}.start();
等同于thread.start();
等同于new Thread(){public void run(){}}.start();
作者: syb012    时间: 2015-11-12 23:13
萧未然 发表于 2015-11-12 21:49
首先,毕老师从多态的角度讲解很专业,毕老师杠杠滴!
我们知道,Thread类实现了Runnable接口.
这里,通 ...

就是说一个虚拟的指针被赋予了“以实现Runnable接口的任务对象作为参数的Thread实例”的地址值后,又被“Thread的匿名子类对象”的地址值,所以最后是用后者的地址值调用了start方法

我感觉我现在能够理解为什么最后运行是匿名子类里run方法了。谢谢
作者: syb012    时间: 2015-11-12 23:17
萧未然 发表于 2015-11-12 21:49
首先,毕老师从多态的角度讲解很专业,毕老师杠杠滴!
我们知道,Thread类实现了Runnable接口.
这里,通 ...

感觉还是有点怪,两个new是没错,但当中的第二个new是用来创建实现Runnable接口的任务对象的;

第一个new创建的是“以实现Runnable接口的任务对象作为参数的Thread实例”呢?
还是创建“Thread的匿名子类对象”呢?
作者: 萧未然    时间: 2015-11-13 09:04
syb012 发表于 2015-11-12 23:17
感觉还是有点怪,两个new是没错,但当中的第二个new是用来创建实现Runnable接口的任务对象的;

第一个ne ...

第一个new当然是用来创建Thread对象的,有没有发现
new Thread().start();这样也是不会报错的,这主要是因为只有Thread才有
start()方法,而start()的功能是什么?
start()就是负责线程调用run()方法执行代码,仔细分析,就会发现,问题都出现在run()方法内部,它是怎么调用资源的?
!--首先,看看API中对Thread类中run方法的描述:
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。Thread 的子类应该重写该方法。
!--明确一点:Thread类实现了Runnable,那么它本身必然会有一个不返回任何操作Run()方法
,所以new Thread().start();没有任何数据显示
!--这里可以知道:原来后面无论是带Runnable构造参数也好,还是Thread子类也罢,都只不过是对一个线程中唯一的run()方法进行不断的复写而已,当线程还没有开启前,就是不断的更新run方法:下面
int i=0;
i=1;
i=2;
----------如果最后对i进行操作:int j=i;结果当然是2;
!--所以run方法不断更新,先是Ruunable匿名子类中的run()方法内容,然后又更行了,Tread匿名之类中的run()方法内容,我们可以这么理解,线程中run()方法一直都在,只是它的内容在不断的变化,而最终的结果,就是start()调用run()方法后的操作数据....
!--补充一下Thread带Runnable子类的构造函数:
       因为资源这个事物不确定,为了提高程序扩展性,于是就对外提供了一个Runnable接口,让线程能够动态的运行,而运行的关键就是run方法代码,也就是说,run()方法也只不过是,把需要操作的数据进行一个封装然后定义一个run标记而已,而线程运行函数strat()就是专门调用run标记里面的内容加载到线程当中
作者: 李永佳    时间: 2015-11-13 12:21
要我说呀,这就是一个标记型的接口,实现了这个runnable接口,就等于有了多线程的功能。子类的run方法确实覆盖了父类的,而且new出来的线程就是子类的线程,调用start方法时当然也是调用子类的方法。
作者: syb012    时间: 2015-11-14 12:56
李永佳 发表于 2015-11-13 12:21
要我说呀,这就是一个标记型的接口,实现了这个runnable接口,就等于有了多线程的功能。子类的run方法确实 ...

感觉你说的比较有道理,感觉楼上说的那个好混乱,有点前后不通的感觉
作者: syb012    时间: 2015-11-14 13:00
如果能搞清楚对象在堆内存是怎么变化的,最后堆内存的对象是什么样子的,问题应该就能明了了
作者: syb012    时间: 2015-11-14 13:07
本帖最后由 syb012 于 2015-11-14 13:32 编辑
  1. new Runnable()
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("Runnable...run");
  6.                         }
  7.                 }
复制代码

这是一个实现任务接口的匿名内部类,也就是Runnable的子类匿名对象,经常被称为任务对象,它是匿名的,可以给他命名为r,写成下面的样子

  1. class R implements Runnable
  2. {
  3.         public void run()
  4.         {
  5.                 System.out.println("Runnable...run");
  6.         }
  7. }

  8. public class ThreadTest2
  9. {

  10.         public static void main(String[] args)
  11.         {
  12.                 R r=new R();

  13.         }        
  14. }
复制代码

这样r就是任务对象,代替第二个new,让原语句看起来更清晰点,那么原语句就就变成了
  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 }.start();
复制代码


先不看start方法
  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 };
复制代码

这个new出来的对象到底是什么?


其实如果把它分开写

  1. new Thread(r);
复制代码
这就是一个Thread对象,建立对象时用的是Thread带参数的构造函数

  1. new Thread()
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 };
复制代码
这是一个Thread的匿名内部类,其实就是一个Thread的子类匿名对象。它是对象,不是图纸,它已经是一个实例。
分析到这里,我遇到困难了,为什么把它们合起来写成
  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 };
复制代码
这样一个奇葩的语句竟然编译通过,还能运行?这个四不像到底是个什么东西??????




作者: syb012    时间: 2015-11-14 13:39
萧未然 发表于 2015-11-13 09:04
第一个new当然是用来创建Thread对象的,有没有发现
new Thread().start();这样也是不会报错的,这主要是 ...

你的分析里有多处破绽不合理的地方

其中你说了这么一句“Thread类实现了Runnable”,可是Thread根本没有实现Runnable,实现Runnable的是Runnable的匿名内部类。我觉得你对java的一些基础知识掌握的很不牢固。

作者: syb012    时间: 2015-11-14 13:53
萧未然 发表于 2015-11-13 09:04
第一个new当然是用来创建Thread对象的,有没有发现
new Thread().start();这样也是不会报错的,这主要是 ...

还有这句话
:"原来后面无论是带Runnable构造参数也好,还是Thread子类也罢,都只不过是对一个线程中唯一的run()方法进行不断的复写而已"


后面,Thread子类的确对run方法进行了复写。但是当通过Thread的带任务对象作为参数的构造函数创建Thread对象时,并没有复写run方法,它是在Thread的run方法调用了任务对象的run方法。这再一次说明了你对java基础知识掌握不牢固。完全是凭主观臆测想象java的运行机制,看似合理,其实整个分析很不合理。

作者: syb012    时间: 2015-11-14 14:09
萧未然 发表于 2015-11-13 09:04
第一个new当然是用来创建Thread对象的,有没有发现
new Thread().start();这样也是不会报错的,这主要是 ...

第一句话:"第一个new当然是用来创建Thread对象的"凭什么“当然”?如果第一new建立的是Thread对象,那么你告诉我为什么运行结果是子类对象里的run方法?我猜你会说覆盖,毕老师也说过覆盖两个字,但是在理由不充分的情况下,那么即使是老师说的,我也会保留怀疑的态度。如果你说老师说的就一定是对的,那么我打心眼里瞧不起你。
可以做一个测试:

  1. class Fu
  2. {
  3.         void show()
  4.         {
  5.                 System.out.println("fu...show");
  6.         }
  7. }

  8. class Zi extends Fu
  9. {
  10.         void show()
  11.         {
  12.                 System.out.println("zi...show");
  13.         }
  14. }

  15. public class Text {

  16.         public static void main(String[] args) {
  17.                
  18.                 Fu f=new Fu();
  19.                 Zi z=new Zi();
  20.                 Fu f1=new Zi();//多态
  21.                 f.show();
  22.                 z.show();
  23.                 f1.show();
  24.         }
  25. }
复制代码

运行结果是:
fu...show
zi...show
zi...show


可以看到,只有当出现多态时,创建的父类对象调用方法时才会被子类方法覆盖。没有多态的情况下,父类对象调用方法时就是运行的自己的方法,根本不会被覆盖。

而我在这个帖子的刚开始就已经分析过了,原语句没有出现多态。

作者: 萧未然    时间: 2015-11-14 15:13
syb012 发表于 2015-11-14 13:39
你的分析里有多处破绽不合理的地方

其中你说了这么一句“Thread类实现了Runnable”,可是Thread根本没有 ...

Thread没有实现Runnable接口???我...  
自己看了半个多小时的API,然后十几分钟的测试,发的文字,写的东西没逻辑性,或许这就是最大的缺点了

后面我只是写出自己的理解方式,你如果非得从多态的角度理解,那得到毕老师的结论就行了,何必纠结?...
我分析run()方法的时候,是结合了最后只有一个start()方法开启一个线程这个基础上的,我以为你会跟前面分析的联系在一起来看,你没有...而且,我写过不偷懒的方式:
Thread thread=new Thread(new Runnable(){public void run()}){public void run()};
thread.start();
我只能说:程序是从上到下,从左到右运行的,内存中到底具体啥样,start()到底是怎么去内存调用run()方法的,这个暂时也不知道,只能待学长来说了{:3_57:}
作者: syb012    时间: 2015-11-14 15:55
萧未然 发表于 2015-11-14 15:13
Thread没有实现Runnable接口???我...  
自己看了半个多小时的API,然后十几分钟的测试,发的文字,写的东 ...

start方法的确是开启一个线程,但你从头到尾都没有说清楚开启的是哪个线程。


也没有说清楚
  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 };
复制代码
这句话到底new的是一个什么对象,让我不得不怀疑你从头到尾是凭空臆测

作者: 萧未然    时间: 2015-11-14 16:00
syb012 发表于 2015-11-14 15:55
start方法的确是开启一个线程,但你从头到尾都没有说清楚开启的是哪个线程。

基础不好,我看基础去了,啦啦{:2_36:}
作者: syb012    时间: 2015-11-14 16:12
萧未然 发表于 2015-11-14 16:00
基础不好,我看基础去了,啦啦

没有足够强大的对手可真没劲
作者: syb012    时间: 2015-11-14 16:25
萧未然 发表于 2015-11-14 15:13
Thread没有实现Runnable接口???我...  
自己看了半个多小时的API,然后十几分钟的测试,发的文字,写的东 ...


  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 };
复制代码
这个对象真的是一个Thread对象吗?

Thread类有很多构造函数,它创建一个对象的方式可以是
Thread thread=new Thread();
也可以是Thread thread= new Thread(参数);

但从来没有听说过Thread thread=new Thread(参数){  };
你确定new Thread(参数){  };真的是一个Thread的对象吗?如果是,那么为什么?
*
*
以上本来是想回复你的,但是没想到你放弃思考了,本来我不该再追问你了,可是又不想删掉,所以还是发出来了

作者: 萧未然    时间: 2015-11-14 17:10
syb012 发表于 2015-11-14 16:25
这个对象真的是一个Thread对象吗?

Thread类有很多构造函数,它创建一个对象的方式可以是

java.lang
类 Thread
java.lang.Object
  java.lang.Thread
所有已实现的接口:
Runnable

--------------------------------------------------------------------------------

public class Thread  extends Object  implements Runnable{}
--我一直站在Thread是实现了Runnable接口这个角度去说的,

!--创建新执行线程的一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run ()方法(是应该,可写可不写,在Tread中,run()方法不是抽象的,是实例成员方法
上面已经知道,Thread类中必定已经存在了public void run(){}方法,只不过里面没什么东西,而Runnable类中只有一个run()方法,没有start()这些东西
!--能调用start()方法的,是谁的对象就很明显了--Thread对象,或者它的子类对象...
这也是为什么,我使用引用数据类型指向后再调用start()方法的原因,就是直观的表示了
public <Thread> void start(){};
!--这样再结合实例中的new Thread(new Runnable(){public void run()}){public void run()};上面说的第二次
!--很明确的说,没错就是多态,只是因为加了一个Runnable子类所以对Thread实例中start()调用的run()方法有了个转折,有了不同的理解,这也是为什么我们都纠结的原因了吧,这也是要明确Treahd类实现了Runnable接口的原因
基础不好,我去看基础了
作者: syb012    时间: 2015-11-14 17:29
萧未然 发表于 2015-11-14 17:10
java.lang
类 Thread
java.lang.Object

多态的意思是父类引用指向子类对象,如果是多态,那么父类引用是谁?子类对象是谁?

如果你说 new Thread(r){ };是子类对象,那么你确定Thread类的子类对象可以这么写?

Thread类匿名子类对象的格式是 new Thread(){ };其中小括号里并没有传参数。
如果一个类建立对象时想传参数,那么这个类必须有含参数的构造函数。也就是说一个Thread类的子类想建立有参数的子类对象,那么子类中必须有含参数的构造函数。但原语句中的大括号里并没有带参数的构造函数,它只有无参数的默认构造函数。
所以Thread类的匿名子类不可能创建带参数的对象。所以按理说new Thread(r){ };不是子类对象。


然后,我很高兴你愿意继续和我为这个地方的知识进行据理力争。谢谢!希望你可以继续

作者: 萧未然    时间: 2015-11-14 17:58
syb012 发表于 2015-11-14 17:29
多态的意思是父类引用指向子类对象,如果是多态,那么父类引用是谁?子类对象是谁?

如果你说 new Threa ...

Thread类匿名子类对象的格式是 new Thread(){ }?太绝对了
Thread构造方法摘要
Thread()
          分配新的 Thread 对象。
Thread(Runnable target)
          分配新的 Thread 对象。
Thread(Runnable target, String name)
          分配新的 Thread 对象。
Thread(String name)
          分配新的 Thread 对象。
Thread(ThreadGroup group, Runnable target)
          分配新的 Thread 对象。
Thread(ThreadGroup group, Runnable target, String name)
          分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员。
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
          分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,作为 group 所引用的线程组的一员,并具有指定的堆栈大小。
Thread(ThreadGroup group, String name)
          分配新的 Thread 对象。
Thread构造函数有八种,有无参数,跟多态没关系,不冲突,构造函数仅仅是对类中成员初始化提供了不同的显示方式
作者: 萧未然    时间: 2015-11-14 18:02
syb012 发表于 2015-11-14 17:29
多态的意思是父类引用指向子类对象,如果是多态,那么父类引用是谁?子类对象是谁?

如果你说 new Threa ...

你慢慢看,我基础不好,看基础去了
作者: syb012    时间: 2015-11-14 18:07
本帖最后由 syb012 于 2015-11-14 18:09 编辑
萧未然 发表于 2015-11-14 17:58
Thread类匿名子类对象的格式是 new Thread(){ }?太绝对了
Thread构造方法摘要
Thread()

那是Thread类的构造函数,不是Thread类的子类的构造函数。创建子类的对象想要带参数,必须子类有带参数的构造函数。但是原语句中的大括号里只有一个方法,它的构造参数是默认的无参数的构造函数。希望你把基础看好后还能再来。

作者: syb012    时间: 2015-11-14 18:16
萧未然 发表于 2015-11-14 17:58
Thread类匿名子类对象的格式是 new Thread(){ }?太绝对了
Thread构造方法摘要
Thread()

匿名内部类的格式: new 父类或者接口(){定义子类的内容}

你的基础真的很不熟,很不扎实
作者: 萧未然    时间: 2015-11-14 18:26
定义匿名内部类的格式如下:
  1. [java] view plaincopy
  2. new 父类构造器(参数列表)|实现接口()  
  3. {  
复制代码

结语:学习的问题跟态度无关{:2_36:}

作者: syb012    时间: 2015-11-14 18:36
萧未然 发表于 2015-11-14 18:26
定义匿名内部类的格式如下:

结语:学习的问题跟态度无关

这里,我只想把这块知识搞清楚,而你给我的感觉是半桶水。所以我再找其它人帮我吧
作者: syb012    时间: 2015-11-14 18:49
萧未然 发表于 2015-11-14 18:26
定义匿名内部类的格式如下:

结语:学习的问题跟态度无关

你的那个格式给了我很大的启发,然后我查到了别人写的一个博文,等我弄清了思路发给你看。先谢谢你
作者: syb012    时间: 2015-11-14 19:34
本帖最后由 syb012 于 2015-11-14 19:37 编辑
萧未然 发表于 2015-11-14 18:26
定义匿名内部类的格式如下:

结语:学习的问题跟态度无关

先把博文的地址发出来:http://blog.csdn.net/liuzhidong123/article/details/6561521

定义匿名内部类的格式如下:
  1. new 父类构造器(参数列表)|实现接口()  
  2. {  
  3. //匿名内部类的类体部分  
  4. }  
复制代码
所以你说的格式是正确的。我写出的格式来自毕老师里的视频,而他为了方便我们理解省略了很多内容。





匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。
关于匿名内部类还有如下两条规则:
1)匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建内部类的对象。因此不允许将匿名内部类
定义成抽象类。
2)匿名内部类不能定义构造器,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化块,
通过实例初始化块来完成构造器需要完成的事情。

第二句话是重点,我看的毕老师的视频里并没有提到这个知识。“匿名内部类不能定义构造器”。


在看原博文的这段话:
当通过实现接口来创建匿名内部类时,匿名内部类也不能显示创建构造器,因此匿名内部类只有一个隐式的无参数构造
器,故new接口名后的括号里不能传入参数值。
    但如果通过继承父类来创建匿名内部类是,匿名内部类将拥有和父类相似的构造器,此处的相似指的是拥有相同的形参
列表。


重点仍然第二句话,原来的我认为,匿名子类的带有参数的构造函数必须写到那个大括号里才行。但是第二句话的知识告诉我,匿名子类的构造函数
是和它的父类相似的,匿名子类不需要再定义构造函数就拥有了带参数的构造函数了。


那么那个语句
  1. new Thread(r)
  2.                 {
  3.                         public void run()
  4.                         {
  5.                                 System.out.println("subThread...run");
  6.                         }
  7.                 };
复制代码
就是一个Thread类的子类。



把它的代码改写一下
  1. public class Text {
  2.         
  3.         public static void main(String[] args)
  4.         {
  5.                 Runnable r=new Runnable()
  6.                         {
  7.                                 public void run()
  8.                                 {
  9.                                         System.out.println("Runnable...run");
  10.                                 }
  11.                         };
  12.                         
  13.                 Zi z=new Zi(r);//这个语句其实就是原语句的改写
  14.                
  15.                 z.start();
  16.         }

  17. }
  18. class Zi extends Thread
  19. {
  20.         Zi()
  21.         {
  22.                 super();               
  23.         }
  24.         Zi(Runnable r){
  25.                 super(r);
  26.         }
  27.         //......和Thread类拥有类似的构造函数
  28.         
  29.         public void run()
  30.         {
  31.                 System.out.println("subThread...run");
  32.         }
  33. }
复制代码



我现在已经能完全明白原语句了,我之前只所以不理解是因为我缺少了上面的知识,我不知道匿名内部的构造器原来是那个样子的。


我现在非常感谢你肯和我一直争论,因为这样我才会不停的思考,不然可能就把这个问题永远扔在那不了了之了。我之前发的一个问问题的帖子就是那样到现在还没解决。我也没在管那个问题了。


现在我也是知道你是理解那个语句的,只是因为你不知道我对这块知识的盲点在哪里所以才总是说不通我,这不是你的错,你不可能知道我的知识储备,当然也不可能知道我不理解那个语句的盲点在哪里。






作者: 李永佳    时间: 2015-11-18 07:35
syb012 发表于 2015-11-14 12:56
感觉你说的比较有道理,感觉楼上说的那个好混乱,有点前后不通的感觉

我把javaweb视频的也都看了看,学习了下。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2