A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

syb012 中级黑马 2015-11-14 13:07:49
21#
本帖最后由 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:31
22#
萧未然 发表于 2015-11-13 09:04
第一个new当然是用来创建Thread对象的,有没有发现
new Thread().start();这样也是不会报错的,这主要是 ...

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

其中你说了这么一句“Thread类实现了Runnable”,可是Thread根本没有实现Runnable,实现Runnable的是Runnable的匿名内部类。我觉得你对java的一些基础知识掌握的很不牢固。
回复 使用道具 举报
syb012 中级黑马 2015-11-14 13:53:19
23#
萧未然 发表于 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:41
24#
萧未然 发表于 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


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

而我在这个帖子的刚开始就已经分析过了,原语句没有出现多态。
回复 使用道具 举报
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:10
26#
萧未然 发表于 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的是一个什么对象,让我不得不怀疑你从头到尾是凭空臆测
回复 使用道具 举报
syb012 发表于 2015-11-14 15:55
start方法的确是开启一个线程,但你从头到尾都没有说清楚开启的是哪个线程。

基础不好,我看基础去了,啦啦{:2_36:}
回复 使用道具 举报
syb012 中级黑马 2015-11-14 16:12:39
28#
萧未然 发表于 2015-11-14 16:00
基础不好,我看基础去了,啦啦

没有足够强大的对手可真没劲
回复 使用道具 举报
syb012 中级黑马 2015-11-14 16:25:28
29#
萧未然 发表于 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的对象吗?如果是,那么为什么?
*
*
以上本来是想回复你的,但是没想到你放弃思考了,本来我不该再追问你了,可是又不想删掉,所以还是发出来了
回复 使用道具 举报
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:18
31#
萧未然 发表于 2015-11-14 17:10
java.lang
类 Thread
java.lang.Object

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

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

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


然后,我很高兴你愿意继续和我为这个地方的知识进行据理力争。谢谢!希望你可以继续
回复 使用道具 举报
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构造函数有八种,有无参数,跟多态没关系,不冲突,构造函数仅仅是对类中成员初始化提供了不同的显示方式
回复 使用道具 举报
syb012 发表于 2015-11-14 17:29
多态的意思是父类引用指向子类对象,如果是多态,那么父类引用是谁?子类对象是谁?

如果你说 new Threa ...

你慢慢看,我基础不好,看基础去了
回复 使用道具 举报
syb012 中级黑马 2015-11-14 18:07:01
34#
本帖最后由 syb012 于 2015-11-14 18:09 编辑
萧未然 发表于 2015-11-14 17:58
Thread类匿名子类对象的格式是 new Thread(){ }?太绝对了
Thread构造方法摘要
Thread()

那是Thread类的构造函数,不是Thread类的子类的构造函数。创建子类的对象想要带参数,必须子类有带参数的构造函数。但是原语句中的大括号里只有一个方法,它的构造参数是默认的无参数的构造函数。希望你把基础看好后还能再来。
回复 使用道具 举报
syb012 中级黑马 2015-11-14 18:16:10
35#
萧未然 发表于 2015-11-14 17:58
Thread类匿名子类对象的格式是 new Thread(){ }?太绝对了
Thread构造方法摘要
Thread()

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

你的基础真的很不熟,很不扎实
回复 使用道具 举报
定义匿名内部类的格式如下:
  1. [java] view plaincopy
  2. new 父类构造器(参数列表)|实现接口()  
  3. {  
复制代码

结语:学习的问题跟态度无关{:2_36:}
回复 使用道具 举报
syb012 中级黑马 2015-11-14 18:36:32
37#
萧未然 发表于 2015-11-14 18:26
定义匿名内部类的格式如下:

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

这里,我只想把这块知识搞清楚,而你给我的感觉是半桶水。所以我再找其它人帮我吧
回复 使用道具 举报
syb012 中级黑马 2015-11-14 18:49:13
38#
萧未然 发表于 2015-11-14 18:26
定义匿名内部类的格式如下:

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

你的那个格式给了我很大的启发,然后我查到了别人写的一个博文,等我弄清了思路发给你看。先谢谢你
回复 使用道具 举报
syb012 中级黑马 2015-11-14 19:34:53
39#
本帖最后由 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. }
复制代码



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


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


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





回复 使用道具 举报
syb012 发表于 2015-11-14 12:56
感觉你说的比较有道理,感觉楼上说的那个好混乱,有点前后不通的感觉

我把javaweb视频的也都看了看,学习了下。
回复 使用道具 举报
12
您需要登录后才可以回帖 登录 | 加入黑马