Java内部类

内部类 - 将一个类的定义放在另一个内部类里面

1 为什么我们需要内部类

在学习内部类之前我们应该思考一下,Java中为什么会引入内部类这个概念。
因为Java中一个子类只能继承一个父类,没有C++的多重继承,但内部类这个概念可以帮助Java实现多重继承

2 内部类的创建与引用

public class Parcel2 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  public Destination to(String s) {
    return new Destination(s);
  }
  public Contents contents() {
    return new Contents();
  }
  public void ship(String dest) {
    Contents c = contents();
    Destination d = to(dest);
    System.out.println(d.readLabel());
  }
  public static void main(String[] args) {
    Parcel2 p = new Parcel2();
    p.ship("Tasmania");
    Parcel2 q = new Parcel2();
    // Defining references to inner classes:
    Parcel2.Contents c = q.contents();
    Parcel2.Destination d = q.to("Borneo");
  }
} /* Output:
Tasmania
*///:~

1.如果从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么形如main()中OuterClassName.InnerClassName
2.内部类拥有外部类的所有元素访问权
3.当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密得捕获一个指向那个外围类对象的引用,然后在访问外部类成员时,就是用那个引用来选择外围类的成员

3 使用.this和.new

3.1内部类中对外部类对象引用

使用外部类的名字后面紧跟圆点和this生成对外部类对象的引用

// Qualifying access to the outer-class object.

public class DotThis {
  void f() { System.out.println("DotThis.f()"); }
  public class Inner {
    public DotThis outer() {
      return DotThis.this;
      // A plain "this" would be Inner's "this"
    }
  }
  public Inner inner() { return new Inner(); }
  public static void main(String[] args) {
    DotThis dt = new DotThis();
    DotThis.Inner dti = dt.inner();
    dti.outer().f();
  }
} /* Output:
DotThis.f()
*///:~

3.2 内部类对象的创建

在拥有外部类对象之前,是不可能创建内部类对象的,所以不能通过直接引用外部类的名字来创建

public class DotNew {
  public class Inner {}
  public static void main(String[] args) {
    DotNew dn = new DotNew();
    DotNew.Inner dni = dn.new Inner();
  }
} 

4 内部类与向上类型

5 内部类的种类

5.1 局部内部类

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

/*方法中嵌入内部类*/
public class Parcel5 {
  public Destination destination(String s) {
    class PDestination implements Destination {
      private String label;
      private PDestination(String whereTo) {
        label = whereTo;
      }
      public String readLabel() { return label; }
    }
    return new PDestination(s);
  }
  public static void main(String[] args) {
    Parcel5 p = new Parcel5();
    Destination d = p.destination("Tasmania");
  }
} ///:~

/*作用域中的内部类*/
public class Parcel6 {
  private void internalTracking(boolean b) {
    if(b) {
      class TrackingSlip {
        private String id;
        TrackingSlip(String s) {
          id = s;
        }
        String getSlip() { return id; }
      }
      TrackingSlip ts = new TrackingSlip("slip");
      String s = ts.getSlip();
    }
    // 在TrackingSlip 外面的{}外,它是不可用的
    //! TrackingSlip ts = new TrackingSlip("x");
  }	
  public void track() { internalTracking(true); }
  public static void main(String[] args) {
    Parcel6 p = new Parcel6();
    p.track();
  }
} ///:~

5.2 匿名内部类

将返回值的生成与表示这个返回值的类的定义结合在一起,且没有“姓名”

public class Parcel7 {
  public Contents contents() {
    return new Contents() { // 插入一个类定义
      private int i = 11;
      public int value() { return i; }
    }; // 分号required in this case
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Contents c = p.contents();
  }
} ///:~

/*创建一个来自Contents的匿名类对象,通过new表达式返回的引用被自动向上转型为对Contents的引用
上述代码可以简化为如下*/
public class Parcel7b {
  class MyContents implements Contents {
    private int i = 11;
    public int value() { return i; }
  }
  public Contents contents() { return new MyContents(); }
  public static void main(String[] args) {
    Parcel7b p = new Parcel7b();
    Contents c = p.contents();
  }
} ///:~

如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器要求其参数引用是final

public class Parcel9 {
  // Argument must be final to use inside
  // anonymous inner class:
  public Destination destination(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.destination("Tasmania");
  }
} ///:~

5.3 嵌套(静态内部)类

普通的内部类保存了外围对象的引用,但嵌套类不需要,类似于外部类的一个static方法
1.要创建嵌套类的对象,并不需要外围类的对象
2.不能从嵌套类的对象访问非静态的外围类对象
普通类不能包含static数据和字段以及嵌套类,但嵌套类都可以包含

public class Parcel11 {
  private static class ParcelContents implements Contents {
    private int i = 11;
    public int value() { return i; }
  }
  protected static class ParcelDestination implements Destination {
    private String label;
    private ParcelDestination(String whereTo) {
      label = whereTo;
    }
    public String readLabel() { return label; }	
    // Nested classes can contain other static elements:
    public static void f() {}
    static int x = 10;
    static class AnotherLevel {
      public static void f() {}
      static int x = 10;
    }
  }
  public static Destination destination(String s) {
    return new ParcelDestination(s);
  }
  public static Contents contents() {
    return new ParcelContents();
  }
  public static void main(String[] args) {
    Contents c = contents();
    Destination d = destination("Tasmania");
  }
} ///:~
5.3.1 嵌套类可以作为接口内部的类

正常情况下,不能在接口中放置任何代码,但嵌套类可以作为接口的一部分

public interface ClassInInterface {
  void howdy();
  class Test implements ClassInInterface {
    public void howdy() {
      System.out.println("Howdy!");
    }
    public static void main(String[] args) {
      new Test().howdy();
    }
  }
} /* Output:
Howdy!
*///:~

6 内部类不可以被覆盖但可以被继承

6.1 内部类不可以被覆盖

以下示例告诉我们不同作用域的同名内部类是完全独立的两个实体,各自在自己的命名空间里

class Egg {
  private Yolk y;
  protected class Yolk {
    public Yolk() { print("Egg.Yolk()"); }
  }
  public Egg() {
    print("New Egg()");
    y = new Yolk();
  }
}	

public class BigEgg extends Egg {
  public class Yolk {
    public Yolk() { print("BigEgg.Yolk()"); }
  }
  public static void main(String[] args) {
    new BigEgg();
  }
} /* Output:
New Egg()
Egg.Yolk()
*///:~

6.2 内部类可以被继承

class Egg2 {
  protected class Yolk {
    public Yolk() { print("Egg2.Yolk()"); }
    public void f() { print("Egg2.Yolk.f()");}
  }
  private Yolk y = new Yolk();
  public Egg2() { print("New Egg2()"); }
  public void insertYolk(Yolk yy) { y = yy; }
  public void g() { y.f(); }
}	

public class BigEgg2 extends Egg2 {
  public class Yolk extends Egg2.Yolk {
    public Yolk() { print("BigEgg2.Yolk()"); }
    public void f() { print("BigEgg2.Yolk.f()"); }
  }
  public BigEgg2() { insertYolk(new Yolk()); }
  public static void main(String[] args) {
    Egg2 e2 = new BigEgg2();
    e2.g();
  }
} /* Output:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
*///:~

7 内部类标识符

由于每个类都会产生一个.class文件,内部类也必须生成一个.class文件以包含它们的Class对象信息
内部类的命名规则是:外围类的名字+$+内部类的名字+.class
如上
BigEgg2.class,内部类为BigEgg2$Yolk.class
Egg2.class 内部类为Egg2$Yolk.class
如果内部类是匿名的,编译器会产生一个数字作为标识符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值