(轉(zhuǎn))https://blog.csdn.net/qq_25827845/article/details/52598319
匿名內(nèi)部類也就是沒(méi)有名字的內(nèi)部類岛杀,正因?yàn)闆](méi)有名字阔拳,所以匿名內(nèi)部類只能使用一次,它通常用來(lái)簡(jiǎn)化代碼編寫(xiě)类嗤。
但使用匿名內(nèi)部類還有個(gè)前提條件:必須繼承一個(gè)父類或?qū)崿F(xiàn)一個(gè)接口
1糊肠、繼承一個(gè)父類的匿名內(nèi)部類實(shí)現(xiàn):
abstractclassPeople{
publicabstractvoideat();
}
publicclassDemo{
publicstaticvoidmain(String[] args){
People p =newPeople() {
publicvoideat(){
System.out.println("I can eat ");
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? p.eat();
? ? }
}
2、在接口上使用匿名內(nèi)部類:
interfacePeople{
publicvoideat();
}
publicclassDemo{
publicstaticvoidmain(String[] args){
People p =newPeople() {
publicvoideat(){
System.out.println("I can eat ");
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? p.eat();
? ? }
}
?此處 new People( )看似實(shí)例化了一個(gè)接口遗锣,事實(shí)并非如此货裹,接口式的匿名內(nèi)部類是實(shí)現(xiàn)了一個(gè)接口的匿名類。而且只能實(shí)現(xiàn)一個(gè)接口精偿。
ps再來(lái)說(shuō)一下線程創(chuàng)建的兩種方式:
(1)繼承Thread類的方式因?yàn)轳詈闲蕴珡?qiáng)弧圆,所以一般不用。
(2)常用實(shí)現(xiàn)Runnable接口的創(chuàng)建線程方式笔咽。
但是我們更喜歡用匿名內(nèi)部類的方式來(lái)創(chuàng)建一個(gè)線程搔预。代碼如下:
newThread(newRunnable() {
@Override
publicvoidrun(){
inti=0;
while(true){
i++;
System.out.println("this is 線程"+i);
}
}
}).start();
就這一句話就可以創(chuàng)建并且啟動(dòng)一個(gè)線程,相對(duì)來(lái)說(shuō)比較方便叶组。而且特別直觀易懂拯田。
此處的new Runnable( )并沒(méi)有實(shí)例化了一個(gè)接口,切記切記Kκ4印!侣监!
匿名內(nèi)部類(Anonymous?Inner?Class)鸭轮,在創(chuàng)建實(shí)例的同時(shí)給出類的定義,所有這些在一個(gè)表達(dá)式中完成橄霉。
Runnable?rn?=?newRunnable()?{
????public void run()?{
????}
};
相當(dāng)于:
classAnomymous?implementsRunnable?{
????public void run()?{
????}
}
Runnable?rn?=?newAnomymous();
可以看到前者更簡(jiǎn)潔张弛。(注意前者最后的分號(hào)不能省略,編譯器把整個(gè)看作一條語(yǔ)句)
不過(guò)酪劫,匿名內(nèi)部類僅限于只實(shí)例化一次的內(nèi)部類,如果內(nèi)部類需要多次實(shí)例化寺董,通常用后者覆糟。
另外,匿名內(nèi)部類要么繼承一個(gè)父類遮咖,要么實(shí)現(xiàn)一個(gè)接口滩字,不能兩者兼有,實(shí)現(xiàn)接口時(shí)也不能實(shí)現(xiàn)多個(gè)接口。
參考示例(轉(zhuǎn))
匿名內(nèi)部類也就是沒(méi)有名字的內(nèi)部類
正因?yàn)闆](méi)有名字麦箍,所以匿名內(nèi)部類只能使用一次漓藕,它通常用來(lái)簡(jiǎn)化代碼編寫(xiě)
但使用匿名內(nèi)部類還有個(gè)前提條件:必須繼承一個(gè)父類或?qū)崿F(xiàn)一個(gè)接口
實(shí)例1:不使用匿名內(nèi)部類來(lái)實(shí)現(xiàn)抽象方法
abstract class Person {
????public abstract void eat();
}
class Child extends Person {
????public void eat() {
????????System.out.println("eat something");
????}
}
public class Demo {
????public static void main(String[] args) {
????????Person p =?new Child();
????????p.eat();
????}
}
運(yùn)行結(jié)果:eat something
可以看到,我們用Child繼承了Person類挟裂,然后實(shí)現(xiàn)了Child的一個(gè)實(shí)例享钞,將其向上轉(zhuǎn)型為Person類的引用
但是,如果此處的Child類只使用一次诀蓉,那么將其編寫(xiě)為獨(dú)立的一個(gè)類豈不是很麻煩栗竖?
這個(gè)時(shí)候就引入了匿名內(nèi)部類
實(shí)例2:匿名內(nèi)部類的基本實(shí)現(xiàn)
abstract class Person {
????public abstract void eat();
}
public class Demo {
????public static void main(String[] args) {
????????Person p =?new Person() {
????????????public void eat() {
????????????????System.out.println("eat something");
????????????}
????????};
????????p.eat();
????}
}
運(yùn)行結(jié)果:eat something
可以看到,我們直接將抽象類Person中的方法在大括號(hào)中實(shí)現(xiàn)了
這樣便可以省略一個(gè)類的書(shū)寫(xiě)
并且渠啤,匿名內(nèi)部類還能用于接口上
實(shí)例3:在接口上使用匿名內(nèi)部類
interfacePerson {
????publicvoideat();
}
publicclassDemo {
????publicstaticvoidmain(String[] args) {
????????Person p =?newPerson() {
????????????publicvoideat() {
????????????????System.out.println("eat something");
????????????}
????????};
????????p.eat();
????}
}
運(yùn)行結(jié)果:eat something
由上面的例子可以看出狐肢,只要一個(gè)類是抽象的或是一個(gè)接口,那么其子類中的方法都可以使用匿名內(nèi)部類來(lái)實(shí)現(xiàn)
最常用的情況就是在多線程的實(shí)現(xiàn)上沥曹,因?yàn)橐獙?shí)現(xiàn)多線程必須繼承Thread類或是繼承Runnable接口
實(shí)例4:Thread類的匿名內(nèi)部類實(shí)現(xiàn)
publicclassDemo{
publicstaticvoidthreadMethod(String name){
Thread t =newThread(name) {
publicvoidrun(){
for(inti =1; i <=5; i++) {
System.out.print(Thread.currentThread().getName()+":"+i +"? ;? ");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? t.start();
}
publicstaticvoidmain(String[] args){
threadMethod("線程1");
threadMethod("線程2");
? ? }
}
運(yùn)行結(jié)果(不確定):線程1:1 ? ; ? 線程1:2 ? ; ? 線程1:3 ? ; ? 線程2:1 ? ; ? 線程1:4 ? ; ? 線程2:2 ? ; ? 線程1:5 ? ; ? 線程2:3 ? ; ? 線程2:4 ? ; ? 線程2:5 ? ; ??
實(shí)例5:Runnable接口的匿名內(nèi)部類實(shí)現(xiàn)
publicclassDemo{
publicstaticvoidthreadMethod(){
Runnable r =newRunnable() {
publicvoidrun(){
for(inti =1; i <=5; i++) {
System.out.print(Thread.currentThread().getName()+":"+i +" ? ; ? ");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? };
Thread t1 =newThread(r,"線程1");
Thread t2 =newThread(r,"線程2");
? ? ? ? t1.start();
? ? ? ? t2.start();
? ? }
publicstaticvoidmain(String[] args){
? ? threadMethod();
? ? }
}
運(yùn)行結(jié)果(不確定):線程1:1 ? ; ? 線程2:1 ? ; ? 線程1:2 ? ; ? 線程2:2 ? ; ? 線程1:3 ? ; ? 線程2:3 ? ; ? 線程1:4 ? ; ? 線程2:4 ? ; ? 線程2:5 ? ; ? 線程1:5 ? ; ??
---------------------------------------------------------------
ps:上面的繼承Thread和實(shí)現(xiàn)Runnable是常用的
之前沒(méi)寫(xiě)過(guò)多線程份名,也記一下下面的吧
packagecom;
publicclassTestRunnableimplementsRunnable{
privateinti =10;
@Override
publicvoidrun(){
System.out.println("TestRunnable class "+Thread.currentThread().getName()+":"+(--i));
}
publicstaticvoidmain(String[] args){
TestRunnable t1 =newTestRunnable();
TestRunnable t2 =newTestRunnable();
//執(zhí)行出的結(jié)果的順序不確定? 變量i copy
newThread(t1).start();
newThread(t2).start();
//執(zhí)行出的結(jié)果的順序不確定? 變量i 共享
/*new Thread(t1,"thread1").start();
new Thread(t1,"thread2").start();*/
}
}