最全面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的话,可以关注或者点赞博主我一下下,感谢!

你可能感兴趣的:(最全面Java内部类总结(面试&查漏补缺必备))