内部类(InnerClass)

1. 概述

1.1 什么是内部类

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

1.2 为什么要声明内部类呢

具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。
总的来说,遵循高内聚、低耦合的面向对象开发原则。

1.3 内部类的分类

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

image-20221124223912529

2. 成员内部类

2.1 概述

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

语法格式:

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

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

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

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

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

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

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

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

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

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

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

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

注意点:

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

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

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

2.2 创建成员内部类对象

  • 实例化静态内部类

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

  • 实例化非静态内部类

外部类名 变量1 = new 外部类();
外部类名.非静态内部类名 变量2 = 变量1.new 非静态内部类名();
变量2.非静态方法();

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();  
    }  
}

3. 局部内部类

3.1 非匿名局部内部类

语法格式:

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

    • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
  • 和成员内部类不同的是,它前面不能有权限修饰符等

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

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

举例:

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();  
}

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");  
            }  
        });  
    }     
}
Java基础

包装类

2025-8-9 14:54:38

Java基础

异常的概念

2025-8-9 15:06:15

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索