美文网首页Java互联网科技
【本人秃顶程序员】Java的内部类真的那么难以理解?

【本人秃顶程序员】Java的内部类真的那么难以理解?

作者: 本人秃顶程序员 | 来源:发表于2019-04-17 15:37 被阅读5次

    ←←←←←←←←←←←← 快!点关注

    前言

    很早之前,有想要转行学习Java的朋友咨询我,有哪方面的书可以推荐,我郑重其事地介绍了《Java编程思想》,并且一再叮嘱他这是一本Java入门级的经典书,必须耐着性子读完它。现在想想,自己当时的推荐真是轻率!

    我这样说,并不是为了否认《Java编程思想》这本书的价值,因为站在书本的角度,它可能会感慨说:这程序员的学习能力有问题啊,读我竟然这么困难!

    不是有那样一句话嘛:“如果你手里有一把锤子,所有东西看上去都像钉子。”我认为“内部类”这一章很难懂,其根本的原因在于我对“内部类”没有很好的理解。想要继续扎实Java的基础知识,唯一要做的就是——想尽一切办法搞懂“内部类”,并梳理成文。

    内部类的定义

    顾名思义,内部类就是放在另外一个类的内部定义的类。非常重要的一点是,内部类能够访问外部类的所有成员,包括private修饰的。

    来看程序清单1-1:

    public class Wanger {
        private int age;
        public Wanger(int age) {
            this.age = age;
        }
        class Thought {
            public void know() {
                System.out.println("秃顶程序员的年龄" + age);
            }
        }
        public Thought getThought() {
            return new Thought();
        }
        public static void main(String[] args) {
            Wanger wanger = new Wanger(30);
            Wanger.Thought thought = wanger.getThought();
            thought.know();
            // 输出:秃顶程序员的年龄30
            // 使用.new的形式创建内部类对象
            Wanger.Thought thought1 = wanger.new Thought();
            thought1.know();
        }
    }
    

    程序清单1-1要表达什么意思呢?

    答案是:我,秃顶程序员,已经29岁了,89年出生。我读书不多,但特别爱思考,于是我就给自己创建了一个会思考的内部类Thought。

    从程序清单1-1可以看得出,尽管Thought是内部类,但可以访问外部类Wanger的私有成员变量age。

    如果想创建内部类的对象,需要先指明对象引用的类型,格式为OuterClassName.InnerClassName,就像main()方法中的Wanger.Thought那样。

    紧接着,就要来创建内部类对象了,有两种形式。第一种形式是先在外部类中定义一个方法Thought getThought(),返回使用new关键字创建的内部类对象,然后使用外部类对象调用该方法wanger.getThought();第二种形式是直接通过外部类对象.new创建wanger.new Thought()。

    匿名内部类

    以我的编程经验来看,匿名内部类使用最频繁的场合就是在创建线程的时候。

    来看程序清单2-1:

    public class Demo {
        public void test(String title) {
            Thread thread = new Thread(new Runnable() {
                @Override
                            public void run() {
                    // title = "我不要吃鸡";
                    // 改变时会提示错误
                    // 在封闭范围中定义的局部变量必须是final的。
                    System.out.println(title);
                }
            }
            );
            thread.start();
        }
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                Demo demo = new Demo();
                demo.test("我要吃鸡" + i);
            }
        }
    }
    

    在程序清单2-1中,test()方法内部有一个线程对象thread,是通过new Thread()创建的。new Thread()可以接收一个实现了Runnable接口类型的对象,这个对象要怎么创建呢?可以通过匿名内部类的形式来创建——new Runnable() {public void run(){......}}——这段简短的代码等同于:

    // 实现Runnable接口
    class MyRunnable implements Runnable {
        @Override
            public void run() {
        }
    }
    // 向上转型
    Runnable myRunnable = new MyRunnable();
    

    匿名内部类的好处就在于不仅节省了定义实现类的过程,还能够自动向上转型

    在程序清单2-1中,test()方法还有一个参数title,JDK1.8之前,编译器要求它必须是final类型的。但JDK1.8之后,如果我们在匿名内部类中需要访问局部变量,那么这个局部变量不再需要用final关键字修饰了。

    但如果想要在匿名内部类中改变局部变量的值,编译器就会提醒你不能这样做,它会提示:“在封闭范围中定义的局部变量必须是final的。”

    为什么需要内部类

    Java的内部类让我很容易的想起来JavaScript的闭包,闭包就是定义在一个函数内部的函数——这听起来和Java的内部类定义一样一样的。本质上,闭包是将函数内部与函数外部连接起来的桥梁。内部类一样,它是将内部类与外部类连接起来的桥梁。

    来看看什么是闭包吧:

    function wanger() {
        var age = 30;
        function know() {
            console.log(age);
        }
    }
    wanger();
    // 控制台输出30
    

    除此之外,内部类最引人注意的原因是:

    内部类可以独立地继承一个抽象类或者实现一个接口,无论外部类是否也这样做了,对内部类都没有影响

    总而言之,内部类让类的内容丰富多彩,就好像一个人的心中还可以住着另外一个人。

    读者福利:

    分享免费学习资料

    针对于Java程序员,我这边准备免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)

    为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!

    资料领取方式:加入Java技术交流群963944895点击加入群聊,私信管理员即可免费领取

    相关文章

      网友评论

        本文标题:【本人秃顶程序员】Java的内部类真的那么难以理解?

        本文链接:https://www.haomeiwen.com/subject/wfsnwqtx.html