最全面Java内部类总结(面试&查漏补缺必备)

前言

这几天趁着时间多多,回顾并总结出来超全面的Java内部类知识;Java内部类老实说我们在开发的时候用的不多,然而正是因为用的不多,久而久之我们就忘了Java内部类,所以才想写这一篇博客,相信看了这篇博客之后,你绝对敢说学会了Java内部类,如果遇到面试的时候,吹给面试官听,很可能面试官就会对你刮目相看(面试官内心独白:这个小伙子不错哟,Java内部类用的不多都这么熟悉,那么经常使用的技术是不是非常熟练?)。

下面先贴出一张超全的Java内部类知识图谱


在这里插入图片描述

上面思维导图已经大部分说明了Java内部类,但是还是想把这篇博客的大纲列出来,这样会更清晰一些。

Java内部类知识大纲

  1. 什么是内部类
  2. 内部类间接体现Java多继承?
  3. 四大内部类
  4. 成员内部类
  5. 静态内部类
  6. 局部(方法)内部类
  7. 匿名内部类

什么是内部类

将一个类定义在另一个类的内部,这就是内部类。内部类和普通类一样,都是类,都可以定义属性、方法 (包括构造方法,静态方法等等)。通常将内部类分为4种:成员内部类、静态内部类、局部(方法)内部类、匿名内部类。在这四种内部类之中,有的内部类可以定义静态成员,有些内部类就不能定义静态成员,再下面将会一一说明。

内部类间接体现Java多继承?

我们都知道在Java中,一个类继承另一个类,就会继承那个类(父类、基类)公有成员(属性、方法),如果外部类继承一个类,内部类也继承一个类(内部类也是类,可以继承类,或者实现接口),又因为内部类可以直接访问外部类的成员(属性、方法),所以内部类也可以访问外部类继承父类的成员,所以说内部类的出现间接体现Java多继承(虽然最多是继承两个类,外部类一个,内部类一个)。这个是我个人的见解,如果有不同的想法看法,可以评论交流一下下。


在这里插入图片描述

四种内部类

虽然内部类和普通的类一样,都可以继承类,实现接口,而且都可以定义成员(属性,方法),但是它们之间还是有区别的;
比如成员内部类就不能定义静态成员(静态变量,静态方法),而静态内部类就可以定义静态成员,下面将会一一介绍这四大内部类,而且都会附带完整的代码说明,只讲理论不给代码都是不贴心的。

成员内部类

我们在学面向对象的时候,应该都知道static这个关键字,被static修饰(属性、方法)就是类级别的了,也就是类成员(不依赖于对象,被该类所有对象共享),那么反过来不被static修饰就是对象成员了,所以成员内部类就是不能被static修饰的,但是可以被四大权限修饰符修饰(public、private、...)。

外部类与成员内部类

下面给出成员内部类代码,下面还会给出成员内部类总结,而这个总结就是从这个代码里浓缩出来的(因为语法错误编译器会报红)。
代码可能看起来有点长,可以复制到IDEA中慢慢细读,相信会有收获的。

/**
 *  外部类内部使用成员内部类
 *      1.成员内部类可以继承类,实现接口
 *      2.成员内部类不能创建静态成员(静态变量,静态方法)
 *      3.不能在外部类静态方法内部创建成员内部类对象
 *      4.如果外部类属性与内部类属性同名时,
 *          直接调用是访问内部类属性,通过外部类名.this.属性名访问的是外部类属性
 *  其他类内部使用成员内部类
 *      第一种方式:
 *          //创建外部类对象
 *          MemberInnerClass outer = new MemberInnerClass();
 *          //创建内部类对象
 *          MemberInnerClass.InnerClass inner = outer.new InnerClass();
 *      第二种方式:
 *          //链式创建内部类对象
 *          MemberInnerClass.InnerClass innerClass = new MemberInnerClass().new InnerClass();
 */
@Data
public class MemberInnerClass {

    private Integer age = 22;
    private String name = "xq";
    private static String country = "中国";

    public void outerMethod() {
        System.out.println("我是外部类的成员方法!");
    }

    public static void outerStaticMethod() {
        System.out.println("我是外部类的静态方法!");
    }

    public class InnerClass {

        /**
         * 成员变量
         */
        private Integer age = 18;
        /**
         * 成员内部类不允许定义静态变量
         */
//        public static String name;    //报错

        /**
         * 构造器
         */
        public InnerClass() {
        }

        /**
         * 内部类成员方法,访问外部类信息(属性、方法)
         */
        public void innerCallOuter() {
            //当内部类属性和外部类属性不同名时,直接调用即可
            System.out.println(name);
            //当内部类属性和外部类属性同名时,访问的是内部类属性
            System.out.println("内部类age属性:" + age);
            //当内部类属性和外部类属性同名时,可通过外部类名.this.属性名
            System.out.println("外部类age属性:" + MemberInnerClass.this.age);
            System.out.println("外部类静态变量:" + country);
            //访问外部类的方法
            outerMethod();
            outerStaticMethod();
        }

        /**
         * 成员内部类不允许定义静态方法,报错
         */
        /*public static void innerStaticMethod(){}*/
    }

    /**
     * 外部类静态方法不能创建内部类对象,
     * 也就是在外部类静态方法内访问不了内部类信息
     * @param args
     */
    /*public static void main(String[] args) {
        InnerClass innerClass = new InnerClass();
    }*/

    /**
     * 外部类非静态方法创建内部类对象,访问内部类信息
     */
    public void outerCallInner() {
        InnerClass innerClass = new InnerClass();
        innerClass.innerCallOuter();
    }

    /**
     * 外部类静态方法,创建外部类对象,调用外部类成员方法(内部访问内部类信息)
     *
     * @param args
     */
    public static void main(String[] args) {
        MemberInnerClass memberInnerClass = new MemberInnerClass();
        memberInnerClass.outerCallInner();
    }

}

其他类使用成员内部类

public class MemberInnerClassTest {

    public static void main(String[] args) {
        //创建外部类对象
        MemberInnerClass outer = new MemberInnerClass();
        outer.outerCallInner();
        System.out.println("=========================");
        //创建内部类对象
        MemberInnerClass.InnerClass inner = outer.new InnerClass();
        inner.innerCallOuter();

        System.out.println("========================");
        //链式创建内部类对象
        MemberInnerClass.InnerClass innerClass = new MemberInnerClass().new InnerClass();
        innerClass.innerCallOuter();

    }
}

成员内部类总结

  1. 成员内部类可以被任何的访问修饰符修饰。
  2. 成员内部类的内部不能定义静态成员。
  3. 成员内部类也是类,可以继承类,可以实现接口,方法也可以重写,重载,this和super随便使用。
  4. 成员内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突,调用外部类.this.属性或者方法
  5. 其它类如何访问成员内部类,被public修饰的成员内部类,可以被不同包的其他类访问;其他情况和普通类一样...

静态内部类

静态内部类就是static修饰的内部类,也可以被四大权限修饰符修饰。

外部类定义以及使用静态内部类

下面代码以及注释非常清晰说明了静态内部类的特性。

/**
 * 外部类&静态内部类
 */
public class StaticInnerClass {

    //和内部类属性同名
    private int age = 22;

    private String outer = "outerClass";
    private static String country = "china";

    static {
        System.out.println("外部类静态代码块...");
    }

    public void outerMethod() {
        System.out.println("我是外部类的成员方法!");
    }

    public static void outerStaticMethod() {
        System.out.println("我是外部类的静态方法!");
    }

    /**
     * 静态内部类,需要使用static修饰
     */
    public static class InnerClass {

        private int age = 18;
        private String inner = "innerClass";

        //静态内部类可以定义静态变量
        private static String country = "中国";

        static {
            System.out.println("内部类静态代码块...");
        }

        public void innerMethod() {
            //静态内部类不能访问外部类非静态成员属性
//            System.out.println("outer:"+outer); 报错

            System.out.println("inner:" + inner);

            System.out.println("静态内部类age属性:" + age);
            //静态类内部不能通过这种方式访问外部类的同名属性
//            System.out.println("外部类age属性:"+StaticOuterClass.this.age);

            System.out.println("静态内部类static属性:" + country);
            System.out.println("外部类static属性:" + cn.zwq.innerclass.StaticInnerClass.country);

            //静态内部类不能调用外部类成员方法
//            outerMethod(); 报错
            //静态内部类可以调用外部类静态方法
            outerStaticMethod();
        }

        /**
         * 静态内部类可以定义静态方法
         */
        public static void innerStaticMethod() {
//            outerMethod(); 报错
            outerStaticMethod();
        }

        public static void main(String[] args) {
            //访问静态内部类静态属性
            System.out.println(cn.zwq.innerclass.StaticInnerClass.InnerClass.country);
            //访问静态内部类静态方法
            cn.zwq.innerclass.StaticInnerClass.InnerClass.innerStaticMethod();
        }

    }
}

其他类使用静态内部类

创建静态内部类对象和创建成员内部类对象稍微不同,可以和上面稍微对比一下就清晰了。

public class StaticInnerClassTest {

    public static void main(String[] args) {
        //创建静态内部类对象,和创建成员内部类稍微不同
        StaticInnerClass.InnerClass innerClass = new StaticInnerClass.InnerClass();
        //访问静态内部类方法(静态、非静态)
        innerClass.innerMethod();
        innerClass.innerStaticMethod();

        //直接调用静态内部类静态属性:外部类.静态内部类.静态属性(非私有的)
        StaticInnerClass.InnerClass.innerStaticMethod();
    }
}

在这里插入图片描述

静态内部类总结

  1. 静态内部类使用static修饰,可以定义非静态成员,也可以定义静态成员。
  2. 静态内部类中的方法(成员方法、静态方法)只能访问外部类的静态成员,不能访问外部类的非静态成员。
  3. 静态内部类可以被4大权限修饰符修饰,被public修饰而任意位置的其他类都可以访问,被private修饰只能被外部类内部访问。
  4. 静态内部类内部的静态成员,可以直接使用外部类.静态内部类.静态成员访问。

局部内部类

局部内部类是定义在方法内部的,我们可以想一下,以前定义方法的时候,有哪些限制?

  1. 首先呢,是变量不能使用权限修饰符修饰,而局部内部类就是方法内部定义的变量,所以局部内部类也不能使用权限修饰符修饰。
  2. 这里先列举一条限制,下面还会给出更加详细的总结。
/**
 * 局部内部类
 */
public class LocalInnerClass {

    //和局部内部类属性同名
    private int age = 22;

    private String outer = "outerClass";
    private static String country = "china";

    public void outerMethod() {
        System.out.println("我是外部类的成员方法!");
    }

    public static void outerStaticMethod() {
        System.out.println("我是外部类的静态方法!");
    }

    /**
     * 外部类成员方法,内部定义局部内部类
     */
    public void localInnerClass() {

        String name = "java";
        name = "javaEE";

        //报错,局部内部类不能被权限修饰符修饰
        /*public class InnerClass{

        }*/

        class InnerClass {

            private String inner = "inner";
            private int age = 18;

            //报错,局部内部类不能定义静态成员(属性、方法)
//            private static String country = "中国";
            /*public static void innerStaticMethod(){

            }*/

            public void innerMethod() {
                //报错,因为局部内部类访问方法定义的变量,该变量必须是final修饰的
//                System.out.println(name);报错
                System.out.println("局部内部类inner属性:" + inner);

                //访问外部类信息
                System.out.println("外部类outer属性:"+outer);
                System.out.println("局部内部类age属性:"+age);
                System.out.println("外部类age属性:"+LocalInnerClass.this.age);
                System.out.println("外部类静态属性country:"+country);
                outerMethod();
                outerStaticMethod();
            }
        }

        /*
            局部内部类只能在声明的方法内部使用
         */
        InnerClass innerClass = new InnerClass();
        innerClass.innerMethod();
        System.out.println(innerClass.age);
        System.out.println(innerClass.inner);
    }

}

局部内部类总结

  1. 局部内部类不能被权限修饰符修饰。
  2. 局部内部类只能在方法内部使用。
  3. 局部内部类不能定义静态成员。
  4. 局部内部类可以直接访问方法内部的局部变量和方法参数。
  5. 局部内部类可以访问外部类的静态成员、非静态成员。

局部内部类注意点(重点)

如果局部内部类访问方法内部的局部变量、方法形参,那么就要求这些局部变量、方法形参被final修饰,否则会报错。
下图很好的说明了这个问题:


在这里插入图片描述

匿名内部类

  1. 首先匿名内部类也是内部类的一种,只不过它没名字。
  2. 匿名内部类最常用的使用场景就是快速创建抽象类或接口的实例。
  3. 如果某个类判定只使用一次,那么就不要通过new关键字创建那个类的对象,而是使用匿名内部类的方式。
  4. 匿名内部类的格式:
    new 实现接口() | 父类构造器(实参列表){
     //匿名内部类类体部分     
    };
    

5.接下来使用匿名内部类创建Runnable接口的实例,创建Thread类的实例。

public static void main(String[] args) {
    //使用匿名内部类创建接口实例
    Runnable runnable = new Runnable() {
        @Override
        public void run() {

        }
    };
    //使用匿名内部类创建Thread类实例
    Thread thread = new Thread(runnable,"小小线程"){
          
    };
}

好了,到这里Java内部类已经说完了,相信你看了这篇之后,之后面试被问到,或者笔试题考到Java内部类题目,都可以轻松解决了。
如果感觉OK的话,可以关注或者点赞博主我一下下,感谢!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335