一,前言

​ 在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。

作用:

​ 1,间接性实现Java多继承,每个内部类都能独立的继承一个接口的实现,因此对于外部类来说就算继承了某个父类,在内部类中是不会有任何影响的。

​ 2,可以将复杂的逻辑代码组合在一起,且对外是隐藏的。

​ 3,内部多线程的使用。

二,成员内部类

​ 成员内部类是最普通的内部类,它的定义为位于另一个类的内部。

​ 访问规则:

​ 1,内部类可以不受权限符的限制,直接访问外部类的成员变量。

​ 2,实例化内部类之前,必须先创建外部类对象,才能访问内部类属性。

直接创建内部类公式为:

​ 外部类名称.内部类名称 对象名 = new 外部类名称.new 内部类名称();

​ 3,外部类不能直接访问内部类的变量和方法,需要通过内部类对象进行访问。

public class Outer {
    private Inner inner = null;
    int num = 10;
    public Inner getInner() {
        if (inner == null)
            inner = new Inner();
        return inner;
    }
    public class Inner {
        int num = 20;
        public void heart() {
            int num = 30;
            System.out.println("就近原则:" + num);  // 结果:30
            System.out.println("本类中;" + this.num);  // 结果:20
            System.out.println("外部类中:" + Outer.this.num);   // 结果:10
        }
    }
}

​ 成员内部类是最为普通的一种,但上述代码有个细节就是在外部类中,内部类及内部类方法中存在变量名称相同的问题。在这种情况下访问规则是:

​ 1,就近原则,先访问本方法中的变量值。

​ 2,如果访问本类中可使用this关键字。

​ 3,如果访问外部类变量值(方法),使用方式为:外部类名称.this.变量名称(外部类.this.成员方法)。

​ 创建方法有两种:

        //第一种方式:直接创建
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();  //必须通过Outer对象来创建
        inner.heart();

        //第二种方式:间接创建
        Outer.Inner inner1 = outer.getInner();
        inner1.heart();

三,局部内部类

​ 如果一个类是定义在方法内部的,那就是一个局部内部类。
“局部”:出了这个方法,其他地方都不能调用局部内部类。

public class LocalCLass {
    public void localInner(){
        // 局部内部类
        class Inner{
            int num = 10;
            public void methodInner(){
                System.out.println("局部内部类:"+num);   // 结果:10
            }
        }
        // 在方法内部,调用局部内部类
        Inner inner = new Inner();
        inner.methodInner();
    }
}

注意:

​ 1,关于类的权限修饰符:

public>protected>(default)>private

外部类:public/(default)
内部类:public/protected/(default)/private
局部内部类:什么都不能写

2,局部类访问局部成员方法:

  • 如果要访问这个局部类所在方法的局部变量,那么必须是有效的final修饰的。
  • 从jdk8+开始,只要局部变量实际上不会改变,则可以省略final关键字。

​ 为什么要被final关键字修饰,这个和对象的生命周期有关系。

​ 1,new出来的对象是在内存的堆中的。
​ 2,局部变量是跟着方法走的,在栈内存中。
​ 3,当方法结束后,便会即可出栈,局部变量消失。
​ 4,而new出来的对象还在堆内存中,直到GC回收消失。
​ 因此,当局部内部类还在堆内存中时,如果再次使用局部变量时,而方法中的局部变量已经出栈消失了。因此必须使用final修饰为常量,使局部内部类可以去常量池中复制一份。另一个原因就是,如果不是final修饰为常量,后期该局部变量值被修改了,那么便会造成局部内部类读取的数据不一致的情况。

四,匿名内部类

​ 匿名内部类简单理解就是没有类名称的类。

​ 一般在实际开发中匿名类是使用最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。

那么一般在什么情况下会使用到匿名内部类。

​ 如果接口的实现类(父类的子类)只需要唯一的一次。那么这种情况下就可以省略对该类的实现,直接使用匿名内部类。

​ 请看如下代码,先来定义一个接口。

public interface IAnonymous {
    void anonymousMethod();
}
        // 匿名内部类的创建方式
        // 第一种方法
        IAnonymous anonymous = new IAnonymous() {
            @Override
            public void anonymousMethod() {
                System.out.println("使用匿名内部类实现接口!");
            }
        };
        anonymous.anonymousMethod();
        
        // 第二种方式,匿名对象
        new IAnonymous(){
            @Override
            public void anonymousMethod() {
                System.out.println("使用匿名对象实现接口!");
            }
        }.anonymousMethod();

匿名内部类注意事项:
​ 1,匿名内部类在创建对象的时候,只能使用唯一的一次,如果要多次创建同一个对象时,
并且内容是相同的,那必须单独定义实现类或者子类。
​ 2,匿名对象,在调用方法的时候,只能调用唯一的一次。如果同一个方法要调用多个方法,
则需要给对象定义对象名称。
​ 3,匿名内部类是省略了实现类或者子类,而匿名对象是省略了对象名称。
两者并不是一回事。

五,静态内部类

​ 静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

public class StaticInnerClass {
    // 外部类静态成员属性
    private static int num  = 10;

    public static class staticInner{
        public void staticMethod(){
            System.out.println("静态内部类!");
            System.out.println("外部静态成员变量:"+num);
        }
    }
}
class StaticMain{
    public static void main(String[] args) {
        StaticInnerClass.staticInner innerClass = new StaticInnerClass.staticInner();
        innerClass.staticMethod();
    }
}

六,总结

​ 每种内部类均有各自的使用场景,因此对于内部类的使用也要根据自己的业务需求进行选择。尤其也要注意内部类使用的细节问题,以及使用规则。

​ 最后以上均是自主学习总结,如有不适之处还请留言指教。

感谢阅读!

版权声明:本文为fenjyang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/fenjyang/p/11467018.html