程序员你真的理解匿名内部类吗?

前言 嘿,java学习者,问你两个问题:若是提到线程你会不会立马想到接口和继承?若是提到接口和继承你会不会立马想到匿名内部类? @[toc]javascript

开篇甜点

为了加深各位对匿名内部类的印象、好奇心以及求知的渴望,咋们先来看一个程序java

package AnonymousInner;

public class NiMingInnerClassThread {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i<5;i++){
                    System.out.println("熊孩子:"+i);
                }
            }
        };
        new Thread(r).start();
        for (int i = 0; i < 5 ; i++){
            System.out.println("傻狍子:"+i);
        }
    }
}

看不懂不要紧啦,看标题就知道了,这只是餐前甜点,这样你才会更有胃口去感觉匿名内部类的魅力小程序

唉唉唉...是否是感受这个写法好像有点不正常啊?但事实上,java确实能够这样玩,这个写法正是匿名内部类方式实现线程的建立~不懂线程不要紧,以后博主应该能抽个空出来写一篇线程文章~,这个程序就涉及到了这篇文章的主要核心,那就是匿名内部类。多线程

何谓匿名内部类?

正所谓匿名内部类,正如它的字面意思同样,也就是没有名字的内部类。也是由于没有名字因此<font color=red>匿名内部类只能执行一次</font>,想应该也能想到这一点吧。匿名内部类一般用简化代码编写,咱们平时写代码都不多用简化代码,因此看着奇怪也不足为奇。框架

为何要使用匿名内部类?

至于为何要使用匿名内部类这个问题,我以为先看下面程序以后,会更好的体会:eclipse

普通实现抽象方法(不使用匿名内部类)ide

package AnonymousInner;

abstract class Father{
    public abstract void speak();
}

class Son extends Father{

    @Override
    public void speak() {
        System.out.println("熊孩子:粑粑,我想哦粑粑");
    }
}

public class NIMingDemo {
    public static void main(String[] args) {
        Father f=new Son();
        f.speak();

    }
}
        
运行结果:
        熊孩子:粑粑,我想哦粑粑

能够看到,咱们用Son继承了Father类,而后实现了Son的一个实例,将其向上转型为Father类的引用。 可是,若是此处的Son类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?这个时候就应该想到匿名内部类了,匿名内部类就此诞生了!因此咱们就可使用匿名内部类来实现抽象方法,具体操做在下面一节详细讲解。工具

注意:若是对多态的向上转型概念不够清晰的童鞋能够看看下面这篇文章,下面这篇文章里面详细的介绍了多态的向上向下转型以及多态的优势。【蓝色字体,点击进入】学习

【java基础之多态】理解多态的向上向下转型从“妈妈我想吃烤山药”讲起开发工具

匿名内部类的使用

开篇已经隐式地提醒过你们了,使用匿名内部类有个前提条件:必须继承一个父类或实现一个接口,但最多只能继承一个父类,或实现一个接口。

关于匿名内部类必需要知道的两点知识:

一、匿名内部类不能有构造器(构造方法),你想嘛,匿名内部类没有类名,咋定义构造器,构造方法的方法名是要与类名一致,但匿名内部类能够定义实例初始化块。

一、匿名内部类不能够是抽象类,刚说过了匿名内部类不能有构造器,而抽象类能够有构造方法,这是其一。java在建立匿名内部类的时候,会当即建立内部类的对象,而抽象类不能建立实例,这是其二。

到这里,你可能会问,都看不见名字,怎样判断一个匿名类的存不存在啊?其实很简单,咱们讲匿名内部类的使用格式以前来看一个小程序,以下

package AnonymousInner;

abstract class Father{
    public abstract void speak();
}

public class NIMingDemo {
    public static void main(String[] args) {
        Father f=new Father();
    }
}

以上这个程序,小白童鞋会不觉得然,而基础好一点的童鞋就会发现,这是错误的写法。你见过抽象类能够实例化嘛?显然不行,会编译失败以下: 在这里插入图片描述 这个时候,咱们的匿名内部类就登场了~

package AnonymousInner;

abstract class Father{
    public abstract void speak();
}

public class NIMingDemo {
    public static void main(String[] args) {
        Father f=new Father() {
            @Override
            public void speak() {
                System.out.println("刘东强东墙东强");
            }
        };
    }
}

你可能有点蒙蒙的感受,咋作到滴,先不说怎么作到代码实现的,咱们先来看看java开发工具是怎么实现的,这里要为idea点个赞了!idea写上面的代码是这样的 在这里插入图片描述eclipse或者Myeclipse工具则是这样的 在这里插入图片描述 经过这里这个小插件楼主只想告诉各位同窗,idea的丧心病狂的提示绝壁会让你尖叫的,不只仅是代码提示仍是编译运行速度都强于eclipse,因此人生苦短,请直接上手idea,忘了eclipse吧,若是在学ssm框架的同窗能够参考这篇IDEA优雅整合ssm框架(详细思路+附带源码)

OK,回到正题,咱们把上面的那个程序的灵魂给抽出来,灵魂代码以下:

abstract class Father(){
....
}
public class NIMingDemo{
   Father f = new Father(){ .... };  //{}里就是个匿名内部类
}

通常来讲,new 一个对象时()后应该是分号;,也就是new出对象该语句就结束了。可是匿名内部类就不同,()后跟的是{}{}中是该new 出对象的具体的实现方法,最后还须要在{}后面加个;表明结束。由于楼主在前面也说过,一个抽象类是不能直接new 的,必须先有实现类了咱们才能new出它的实现类。上面的灵魂代码就是表示new 的是Father的实现类,只不过这个实现类是个匿名内部类的形式而已。

到这里咱们已经讲了继承这一方面的例子了,这个时候确定会有小白同窗说刚才不是一种再讲抽象和匿名内部类咩?好像没有讲到继承,呃呃呃,小白同窗啊抽象类也是一个类,我已是用Son子类继承了Father父类了,只是这个Father父类就是一个抽象类鸭!!!

至于接口方面也是同样的,啥?也要讲。。。行吧,那下面再来一个匿名内部类用于接口上的例子!

package AnonymousInner;

interface Father{
    public abstract void speak();
}

public class NIMingDemo {
    public static void main(String[] args) {

        Father f=new Father() {
            @Override
            public void speak() {
                System.out.println("粑粑:孩子,不你不想拉粑粑");
            }

            public void eatBaBa(){
                System.out.println("熊孩子:粑粑,我想拉粑粑");
            }
        };

        f.speak();
        f.eatBaBa(); //编译失败,不能调用eatBaBa()方法
    }
}

写这个程序的过程当中, f.eatBaBa(); 会编译失败,提示不能调用eatBaBa()方法,Why?注意 Father f=new Father()建立的是Father的对象,而非匿名内部类的对象。其实匿名内部类连名字都没有,你咋实例对象去调用它的方法呢?可是f.speak()方法却能够执行,Why?由于匿名内部类实现了接口Fatherspeak()方法,所以能够借助Father的对象去调用。

确定会有特别倔强的童鞋就是想调用匿名内部类的自定义的eatBaBa()方法,有没有办法呢?固然也是有办法滴,并且有两个方法:

方法1、 事实上匿名内部类中隐含一个匿名对象,经过该方法能够直接调用eatBaBa()speak()方法;具体代码以下:

package AnonymousInner;

interface Father{
    public abstract void speak();
}

public class NIMingDemo {
    public static void main(String[] args) {

        new Father() {
            @Override
            public void speak() {
                System.out.println("粑粑:孩子,不你不想拉粑粑");
            }

            public void eatBaBa(){
                System.out.println("熊孩子:粑粑,我想拉粑粑");
            }
        }.eatBaBa() ;

    }
}
                 
运行结果:
        熊孩子:粑粑,我想拉粑粑

只不过这个匿名对象只能调用一个方法也就是说只能使用一次,我试着调用两个方法好像行不通,固然大家也能够尝试尝试,博主仍是个菜鸟并不能保证这句话的正确性,若有错误请必定要告诉我!感激涕零!!!

方法2、 把eatBaBa()方法更改成speak()方法同样的使用,也就是说在Father接口中声明eatBaBa()方法,而后在匿名内部类中覆写此方法便可。这个就不贴代码了吧!

匿名方法在多线程上的实现

不得不说匿名方法最经常使用的状况就是在多线程的实现上,由于要实现多线程必须继承Thread类或是继承Runnable接口,开篇的时候写的就是继承Runnable接口的代码,因此这里博主就讲讲Thread类的匿名内部类实现,代码以下:

package AnonymousInner;

public class ThreadDemo {

    public static void main(String[] args) {

        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 3; i++) {
                    System.out.print(i);
                }
            }
        };
        t.start();
    }
}
运行结果:  123

若是本文对你有所帮助,请给博主点一个爱心,支持一下hhhh!!!

结语:博主并不能保证每句话都正确,若有错误或者博主理解不够深入的地方请必定要告诉我!!!

最后,欢迎各位关注个人公众号,一块儿探讨技术,向往技术,追求技术,说好了来了就是盆友喔... 在这里插入图片描述

相关文章
相关标签/搜索