《Java编程思想》笔记10-内部类

  1. 在方法和作用域内的内部类
  2. 匿名内部类
  3. 嵌套类
  4. 为什么需要内部类
  5. 闭包和回调
  6. 继承内部类
  7. 内部类可以被覆盖吗
  8. 局部内部类

可以将一个类的定义放在另一个类的定义内部,这就是内部类。

public class Outer {
    class Inner {
        Inner() {System.out.println("Hello I am Inner Class!");}
        public Outter outer(){
            return Outter.this; // 返回外部类对象
        }
    }
    Inner getInner(){return new Inner();}

    Outer(){System.out.println("Hello I am Outer Class!");}

    public static void main(String[] args) {
        Outer outer=new Outer();
        Inner myInner=outer.getInner(); // 实例化内部类,方法一
        Inner newInner=outer.new Inner(); // 实例化内部类,方法二
    }
}
  • 在初始化外部类 Outer 的时候,并不会自动初始化内部类 Inner。
  • 如果 Inner 类不是静态的,要实例化内部 Inner 类,必须通过外部 Outer 类的实例。
  • 非静态内部类自动拥有对其外部类所有成员的访问权。
  • 内部类持有对外部类对象引用的语法:外部类名称.this
  • private 内部类,可以完全隐藏实现的细节。

在方法和作用域内的内部类

方法内部,称为局部内部类。
作用域方面,如果内部类声明在if条件语句下作用域中,那超出这个域也是不可用的。

匿名内部类

匿名类没有命名的构造器(类本身就没有名字),可以通过实例初始化来完成构造器的功能。

匿名内部类从 JDK8 开始能访问非 final 的参数了
JDK8 之前为保护外部类的变量不被破坏,Java 硬性规定匿名内部类只能访问 final 类型的外部对象。但从 JDK8 开始,访问非 final 对象编译器也不会报错了。但匿名内部类内部仍然不能改变这些对象,因为匿名内部类内部会对这些对象做一份拷贝。所有操作都在这个镜像上进行。

嵌套类

静态内部类

普通的内部类不能有 static 数据和 static 字段,也不能包含嵌套类。但是嵌套类可以包含这些。

接口的内部类,嵌套类可以作为接口的一部分。

为什么需要内部类

每个内部类都能独立地继承自一个(接口的)实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。可以有效的实现了多重继承。

如果拥有的是抽象的类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承。

class D {}
abstract class E {}

class Z extends D {
  E makeE() { return new E() {}; }
}

public class MultiImplementation {
  static void takesD(D d) {}
  static void takesE(E e) {}
  public static void main(String[] args) {
    Z z = new Z();
    takesD(z);
    takesE(z.makeE());
  }
}
  • 内部类可以有多个实例,每个实例可以拥有独立于外部类对象的不同信息;
  • 一个外部类可以有多个内部类,每个内部类可以以不同的方式实现同一个接口或者继承同一个类;
  • 内部类实例创建时刻并不受到外部类对象创建的限制;
  • 用内部类不会制造“is-a”关系的混乱,每个内部类都是个实体。

闭包和回调

闭包是一种可调用的对象,它记录了来自创建它的作用域的一些信息。内部类是一种面向对象的闭包,不仅包含了外部类的信息,而且通过包含一个指向外部类对象的引用,可以操作所有成员,包括private。

回调,通过其它对象携带的信息,可以在稍后的某个时刻调用初始对象。回调的价值在于灵活性,可以在运行时决定需要调用的方法。 GUI编程将体现得更明显。

继承内部类

class Outer {
    class Inner {}
}
public class InheritInner extends Outer.Inner {
    //! InheritInner() {} // Won’t compile
    InheritInner(Outer o) {
        o.super();
    }
}

内部类可以被覆盖吗

继承外部类,如果直接再定义一遍内部类,并不会覆盖原有内部类。若想覆盖原有内部类,必须连同外部类一起,同时显式地继承内部类,然后再重写内部类子类的方法。

class Outer {
    class Inner {
        public innerMethod(){System.out.println("Outer.Inner.innerMethod()")}
    }
}
public class InheritOuter extends Outer {
    public class InheritInner extends Outer.Inner {
        public innerMethod(){System.out.println("InheritOuter.InheritInner.innerMethod()")}
    }
}

局部内部类

局部内部类不能有访问限定符;有访问局部final变量和外部类所有成员的权限;可以有命名的构造器;在方法外不能访问。

绝大部分情况下,可以用匿名类来替代局部内部类,除非:

  • 需要命名的构造器,或者需要重载构造器
  • 需要多个内部类的对象


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:《Java编程思想》笔记10-内部类

文章字数:1.2k

本文作者:Bin

发布时间:2018-03-28, 21:12:22

最后更新:2019-08-06, 00:46:42

原始链接:http://coolview.github.io/2018/03/28/Java%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3/%E3%80%8AJava%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3%E3%80%8B%E7%AC%94%E8%AE%B010-%E5%86%85%E9%83%A8%E7%B1%BB/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录