java高级之内部类(InnerClass)

8.1 概述

8.1.1 什么是内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类(InnerClass),类B则称为外部类(OuterClass)

8.1.2 为什么要声明内部类呢

具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。

总的来说,遵循高内聚、低耦合的面向对象开发原则。

8.1.3 内部类的分类 

根据内部类声明的位置(如同变量的分类),我们可以分为:成员内部类以及局部内部类。

8.2 成员内部类

8.2.1 概述

如果成员内部类中不使用外部类的非静态成员,那么通常将内部类声明为静态内部类,否则声明为非静态内部类。

语法格式:

[修饰符] class 外部类{
    [其他修饰符] [static] class 内部类{
    }
}

成员内部类的使用特征,概括来讲有如下两种角色:

  • 成员内部类作为类的成员的角色

    • 和外部类不同,Inner class还可以声明为private或protected;

    • 可以调用外部类的结构。(注意:在静态内部类中不能使用外部类的非静态成员)

    • Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;

  • 成员内部类作为类的角色

    • 可以在内部定义属性、方法、构造器等结构

    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关

    • 可以声明为abstract类 ,因此可以被其它的内部类继承

    • 可以声明为final的,表示不能被继承

    • 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)

注意点:

  1. 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式

  2. 成员内部类可以直接使用外部类的所有成员,包括私有的数据

  3. 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的

8.2.2 创建成员内部类对象
  • 实例化静态内部类

外部类名.静态内部类名 变量 = 外部类名.静态内部类名();
变量.非静态方法();
  • 实例化非静态内部类

外部类名 变量1 = new 外部类();
外部类名.非静态内部类名 变量2 = 变量1.new 非静态内部类名();
变量2.非静态方法();
8.2.3 举例
public class TestMemberInnerClass {
    public static void main(String[] args) {
        //创建静态内部类实例,并调用方法
        Outer.StaticInner inner = new Outer.StaticInner();
        inner.inFun();
        //调用静态内部类静态方法
        Outer.StaticInner.inMethod();
​
        System.out.println("*****************************");
        
        //创建非静态内部类实例(方式1),并调用方法
        Outer outer = new Outer();
        Outer.NoStaticInner inner1 = outer.new NoStaticInner();
        inner1.inFun();
​
        //创建非静态内部类实例(方式2)
        Outer.NoStaticInner inner2 = outer.getNoStaticInner();
        inner1.inFun();
    }
}
class Outer{
    private static String a = "外部类的静态a";
    private static String b  = "外部类的静态b";
    private String c = "外部类对象的非静态c";
    private String d = "外部类对象的非静态d";
​
    static class StaticInner{
        private static String a ="静态内部类的静态a";
        private String c = "静态内部类对象的非静态c";
        public static void inMethod(){
            System.out.println("Inner.a = " + a);
            System.out.println("Outer.a = " + Outer.a);
            System.out.println("b = " + b);
        }
        public void inFun(){
            System.out.println("Inner.inFun");
            System.out.println("Outer.a = " + Outer.a);
            System.out.println("Inner.a = " + a);
            System.out.println("b = " + b);
            System.out.println("c = " + c);
//            System.out.println("d = " + d);//不能访问外部类的非静态成员
        }
    }
​
    class NoStaticInner{
        private String a = "非静态内部类对象的非静态a";
        private String c = "非静态内部类对象的非静态c";
​
        public void inFun(){
            System.out.println("NoStaticInner.inFun");
            System.out.println("Outer.a = " + Outer.a);
            System.out.println("a = " + a);
            System.out.println("b = " + b);
            System.out.println("Outer.c = " + Outer.this.c);
            System.out.println("c = " + c);
            System.out.println("d = " + d);
        }
    }
​
​
    public NoStaticInner getNoStaticInner(){
        return new NoStaticInner();
    }
}

8.3 局部内部类

8.3.1 非匿名局部内部类

语法格式:

[修饰符] class 外部类{
    [修饰符] 返回值类型  方法名(形参列表){
            [final/abstract] class 内部类{
        }
    }    
}
  • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。

    • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类

  • 和成员内部类不同的是,它前面不能有权限修饰符等

  • 局部内部类如同局部变量一样,有作用域

  • 局部内部类中是否能访问外部类的非静态的成员,取决于所在的方法

举例:

/**
 * ClassName: TestLocalInner
 * @Author 尚硅谷-宋红康
 * @Create 17:19
 * @Version 1.0
 */
public class TestLocalInner {
    public static void main(String[] args) {
        Outer.outMethod();
        System.out.println("-------------------");
​
        Outer out = new Outer();
        out.outTest();
        System.out.println("-------------------");
​
        Runner runner = Outer.getRunner();
        runner.run();
​
    }
}
class Outer{
​
    public static void outMethod(){
        System.out.println("Outer.outMethod");
        final String c = "局部变量c";
        class Inner{
            public void inMethod(){
                System.out.println("Inner.inMethod");
                System.out.println(c);
            }
        }
​
        Inner in = new Inner();
        in.inMethod();
    }
​
    public void outTest(){
        class Inner{
            public void inMethod1(){
                System.out.println("Inner.inMethod1");
            }
        }
​
        Inner in = new Inner();
        in.inMethod1();
    }
​
    public static Runner getRunner(){
        class LocalRunner implements Runner{
            @Override
            public void run() {
                System.out.println("LocalRunner.run");
            }
        }
        return new LocalRunner();
    }
​
}
interface Runner{
    void run();
}
8.3.2 匿名内部类

因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。

new 父类([实参列表]){
    重写方法...
}
new 父接口(){
    重写方法...
}

举例1:使用匿名内部类的对象直接调用方法:

interface A{
    void a();
}
public class Test{
    public static void main(String[] args){
        new A(){
            @Override
            public void a() {
                System.out.println("aaaa");
            }
        }.a();
    }
}

举例2:通过父类或父接口的变量多态引用匿名内部类的对象

interface A{
    void a();
}
public class Test{
    public static void main(String[] args){
        A obj = new A(){
            @Override
            public void a() {
                System.out.println("aaaa");
            }
        };
        obj.a();
    }
}

举例3:匿名内部类的对象作为实参

interface A{
    void method();
}
public class Test{
    public static void test(A a){
        a.method();
    }
    
    public static void main(String[] args){
        test(new A(){
​
            @Override
            public void method() {
                System.out.println("aaaa");
            }
        });
    }   
}

个人思考

  1. 封装和隐藏实现细节:内部类可以用于隐藏一个类的实现细节,使其对外部世界不可见。这有助于提高代码的模块化和封装性。

  2. 实现多重继承:在某些编程语言中,内部类可以用于实现多重继承,因为一个类可以包含多个内部类,从而获得多个类的功能。

  3. 回调函数:内部类常常用于实现回调函数或事件处理程序。一个外部类可以定义一个内部类来实现某种接口或抽象类,然后在适当的时候创建内部类的实例并将其用作回调函数。

  4. 访问外部类成员:内部类可以访问外部类的成员,包括私有成员,这对于实现某些特定功能非常有用。

  5. 代码组织和可读性:内部类可以帮助组织代码,使其更具可读性。相关的类可以放在一起,减少类的数量,从而简化代码结构。

  6. 局部性和作用域:内部类的作用域通常被限制在包含它的外部类中,这可以防止内部类的名称与其他部分的代码发生冲突。

  7. 单例模式:内部类可以用于实现懒汉式单例模式,确保只有在需要时才会创建类的实例。

  8. 事件处理:在图形用户界面(GUI)开发中,内部类通常用于处理事件,例如按钮点击事件或鼠标事件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值