Java内部类的概念和使用

    |     2015年4月1日   |   Java面向对象高级特性   |     0 条评论   |    1803

Java 允许在一个类(或方法、语句块)内部再定义另一个类,称为内部类(Inner Class),有时也叫嵌套类(Nested Class)。

内部类和外层类存在逻辑上的所属关系,一般只用在定义它的类或语句块里,实现没有通用意义的功能。外部引用时必须给出完整名称。

使用内部类的主要原因:可以访问外部类数据(包括私有的);可以对同一个包中的其他类隐藏;写回调时不想单独开一个类,匿名内部类比较方便;也能减少类名冲突。

种类 定义位置 创建方式
成员内部类(非 static) 类体里,方法外 必须先有外部对象,再 outer.new Inner()
静态嵌套类 类体里,带 static new Outer.Inner(),不依赖外部实例
局部内部类 方法或代码块里 只在该块内可见
匿名内部类 表达式里当场实现 必须继承父类或实现接口

内部类是编译器现象:会生成独立的 Outer$Inner.class,虚拟机只看到普通类。内部类可以用 public、protected、private,外部顶层类只能 public 或默认。

一、成员内部类

在外部类内部直接定义(不在方法或代码块里)的就是成员内部类,可以直接用外部类的全部成员,包括 private。外部类要访问内部类成员,得通过内部类对象。

public class Outer {
    private int size;
    public class Inner {
        private int counter = 10;
        public void doStuff() {
            size++;
        }
    }
    public static void main(String args[]) {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        inner.doStuff();
        System.out.println(outer.size);
        System.out.println(inner.counter);
        // System.out.println(counter); 编译错误,外部类不能直接访问内部类变量
    }
}

非静态内部类必须先有外部对象才能生成,因为它要访问外部实例成员。非静态内部类里不能声明 static 成员(编译期常量除外)。同一个外部类里的多个内部类可以互相调用。

有 static 就是类级,可通过外部类名访问;没有就是对象级。非静态内部类会自动持有外部实例引用,约定写法是 Outer.this。

1)外部创建非静态内部类

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.dostuff();

2)静态内部类可直接 new

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer.Inner();
        inner.dostuff();
    }
}
class Outer {
    private static int size;
    static class Inner {
        public void dostuff() {
            size++;
            System.out.println("size=" + size);
        }
    }
}

运行结果:size=1。静态内部类相当于外部类的 static 成员,和外部实例没有依赖,因此只能直接访问外部类的静态成员。

3)同名成员怎么区分

public void dostuff(int size) {
    size++;           // 局部变量
    this.size++;      // 内部类的 size
    Outer.this.size++; // 外部类的 size
}

二、局部内部类

局部内部类定义在代码块中,只在该块内可见。不能是 static,也不能用 public / private / protected,可以用 abstract。Java 8 之前只能访问块里的 final 局部变量;Java 8 起改为“实际上的 final”(赋值一次即可,不必写出 final)。

public class Outer {
    public static final int TOTAL_NUMBER = 5;
    public int id = 123;
    public void func() {
        final int age = 15;
        String str = "http://www.warmtel.com";
        class Inner {
            public void innerTest() {
                System.out.println(TOTAL_NUMBER);
                System.out.println(id);
                // str 若后面还会被赋值,这里就不能用
                System.out.println(age);
            }
        }
        new Inner().innerTest();
    }
}

运行结果:5、123、15。

三、匿名内部类

匿名内部类是局部内部类的特殊形式:没有名字指向这个类,实现写在表达式里。必须继承一个父类或实现一个接口。子类只用一次时,不必单独写 Child。

abstract class Person {
    public abstract void eat();
}
public class Demo {
    public static void main(String[] args) {
        new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        }.eat();
    }
}

运行结果:eat something。内部类语法较繁,实际开发里匿名类(以及后来的 lambda)用得更多;不必把它当成入门重点死磕。

一句话总结:内部类能摸到外部私有成员;非静态的要先有外部对象,静态的可以直接 new,局部和匿名只在当场用一次。

转载请注明来源:Java内部类的概念和使用
本文链接地址:https://ai.zhousir.top/?p=120
回复 取消