6内部类

内部类

外部类的方法使用内部类时 与其他普通类类似 可以直接new 就像contents() 和 to()方法一样,
如果需要在其他类里面获取内部类对象 那么需要通过 外部类.内部类 来接收

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
*///:~
 
class OtherClass{
    public void test1() {
        Parcel2 q = new Parcel2();
        Parcel2.Contents a = q.contents();
    }
    
    public static void main(String[] args) {
        Parcel2 q = new Parcel2();
        Parcel2.Contents a = q.contents();
    }
}

内部类可以访问外部类的所有属性和方法,这是因为当外部类对象创建内部类对象时,内部类会密码获取指向外部类的引用,
然后访问外部类属性和方法时,就是使用这个引用来获取外部类的属性和方法,但是当内部类是static时 是访问不到外部类的普通成员的 可以访问静态成员。
创建内部类对象时 必须先创建外部类对象,除非这个内部类是static的

interface Selector {
  boolean end();
  Object current();
  void next();
}   

public  class Sequence {
  private Object[] items;
  private int next = 0;
  public Sequence(int size) { items = new Object[size]; }
  public void add(Object x) {
    if(next < items.length)
      items[next++] = x;
  }
    class SequenceSelector implements Selector {
    private int i = 0;
    public boolean end() { return i == items.length; }
    public Object current() { return items[i]; }
    public void next() { if(i < items.length) i++; }
  }
  public Selector selector() {
    return new SequenceSelector();
  } 
  public static void main(String[] args) {
    Sequence sequence = new Sequence(10);
    for(int i = 0; i < 10; i++)
      sequence.add(Integer.toString(i));
    Selector selector = sequence.selector();
    while(!selector.end()) {
      System.out.print(selector.current() + " ");
      selector.next();
    }
  }
}

通过.this来获取外部引用

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

除了在外部类提供一个方法来获取内部类对象,也可以通过.new 来获取内部类对象

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

一个需要用到的接口

public interface Contents {
  int value();
}

匿名内部类
匿名内部类 这个类是没用名字的,创建了一个继承Contents的匿名对象 通过new 返回的引用被自动转型为Contents

public class Parcel7 {
  public Contents contents() {
    return new Contents() { 
      private int i = 11;
      public int value() { return i; }
    };
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Contents c = p.contents();
  }
} 

匿名内部类使用调用方法的局部变量aa 以及调用方法的形参dest 都需要定义为final,jdk8中加入语法糖 无需显式使用final修饰,但是底层还是会加上final的,所以在匿名内部类内修改对象时会报错

public class Parcel9 {
  public Destination destination(final String dest) {
      final String aa = "11";
    return new Destination() {
      private String label = dest;
      public String readLabel() { 
//        dest = "111";
//        aa = "22";
          return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.destination("Tasmania");
  }
}

静态内部类 意味着1 该内部类不需要外部类对象,2不能从该内部类对象中获取非静态的外部类成员

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

我们为什么需要内部类
借助内部类来实现多继承

abstract class FlyingAnimal {
    abstract void fly();
}
abstract class SwimmingAnimal {
    abstract void swim();
}

public class Swan extends FlyingAnimal{
 
    @Override
    void fly() {
        // TODO Auto-generated method stub
        System.out.println("Swan.fly()");
    }
    
    void swim() {
        this.getSwimming().swim();
    }
    
    SwimmingAnimal getSwimming() {
        return new SwimmingAnimal(){
            @Override
            void swim() {       
                System.out.println("Swan.swim()");
            }
        };
    }
    
    
    public static void main(String[] args) {
        Swan swan = new Swan();
        swan.fly();
        swan.swim();
    }
}

Swan(天鹅)类既继承抽象类FlyingAnimal(飞行动物),又要继承SwimmingAnimal(游动物)。但Swan只能继承一个类FlyingAnimal,另一个类的继承与方法复写,只能在内部类中继承实现。所以在内部类中,通过getSwimming()方法,返回一个匿名内部类实例,并在Swan外部类中构造了swim()方法,来调用匿名内部类对象的swim()方法。

反射 ,泛型

java程序在运行之前并非完全加载,其各个部分是在必需的时候才加载的,当程序对要使用一个类的静态成员(方法或者属性)时,jvm就会加载这个类,这也证明构造器是静态的,即使构造方法前没有使用static关键字。因此使用new操作符创建类的新对象的时候也会被当做调用类的静态成员。
Class.forName与XX.class与XX.getClass
json 转实bean体

泛型擦除的补偿
擦除让泛型代码丢失了某些操作的能力,比如以下操作

public class Erased<T> {
  private final int SIZE = 100;
  public static void f(Object arg) {
    if(arg instanceof T) {}          // Error
    T var = new T();                 // Error
    T[] array = new T[SIZE];         // Error
    T[] array = (T)new Object[SIZE]; // Unchecked warning
  }
} 

我们可以显式的使用Class对象来对擦除进行补偿

class Building {}
class House extends Building {}

public class ClassTypeCapture<T> {
  Class<T> kind;
  public ClassTypeCapture(Class<T> kind) {
    this.kind = kind;
  }
  public boolean f(Object arg) {
    return kind.isInstance(arg);
  } 
  public static void main(String[] args) {
    ClassTypeCapture<Building> ctt1 =new ClassTypeCapture<Building>(Building.class);
    System.out.println(ctt1.f(new Building()));
    System.out.println(ctt1.f(new House()));
    ClassTypeCapture<House> ctt2 =new ClassTypeCapture<House>(House.class);
    System.out.println(ctt2.f(new Building()));
    System.out.println(ctt2.f(new House()));
  }
}
//  true
//  true
//  false
//  true

我们可以使用工厂来实现创建泛型对象的功能

package generics;

interface FactoryI<T> {
  T create();
}

class Foo2<T> {
  public T x;
  public <F extends FactoryI<T>> Foo2(F factory) {
    x = factory.create();
  }
  // ...
}

class IntegerFactory implements FactoryI<Integer> {
  public Integer create() {
    return new Integer(0);
  }
}   

class Widget {
  public static class Factory implements FactoryI<Widget> {
    public Widget create() {
      return new Widget();
    }
  }
}

public class FactoryConstraint {
  public static void main(String[] args) {
      Foo2<Integer> f1 = new Foo2<Integer>(new IntegerFactory());
      System.out.println(f1.x);
      Foo2<Widget> f2 = new Foo2<Widget>(new Widget.Factory());
      System.out.println(f2.x);
  }
} 
//  0
//  generics.Widget@15db9742

也可以使用模板方法模式来实现创建泛型对象

abstract class GenericWithCreate<T> {
  final T element;
  GenericWithCreate() { element = create(); }
  abstract T create();
}

class X {}

class Creator extends GenericWithCreate<X> {
  X create() { return new X(); }
  void f() {
    System.out.println(element.getClass().getSimpleName());
  }
}   

public class CreatorGeneric {
  public static void main(String[] args) {
    Creator c = new Creator();
    c.f();
  }
} /* Output:
X
*///:~

数组的例子

class Fruit {}
class Apple extends Fruit {}
class Orange extends Fruit {}
class Jonathan extends Apple {}


public class CovariantArrays {
  public static void main(String[] args) {
    Fruit[] fruit = new Apple[10];  
    fruit[0] = new Apple(); // OK
    fruit[1] = new Jonathan(); // OK
    // Runtime type is Apple[], not Fruit[] or Orange[]:
    try {
      // Compiler allows you to add Fruit:
      fruit[0] = new Fruit(); // ArrayStoreException
    } catch(Exception e) { 
        System.out.println(e); 
    }
    try {
      // Compiler allows you to add Oranges:
      fruit[0] = new Orange(); // ArrayStoreException
    } catch(Exception e) { System.out.println(e); }
  }
} /* Output:
java.lang.ArrayStoreException: Fruit
java.lang.ArrayStoreException: Orange
*///:~

上面将Apple数组赋值给Fruit数组,编译时该数组被认定为Apple类型,而运行期 数组机制是知道它处理的是Apple类型数组,因此添加Fruit类型时会抛出异常。
这种情况对于集合来说是编译都通不过的

public class NonCovariantGenerics {
  // Compile Error: incompatible types:
  List<Fruit> flist = new ArrayList<Apple>();
} ///:~

对于容器来说,泛型没有内建协变类型,虽然Apple是Fruit的子类,但是我们现在描述的主体是容器而不是容器持有对象的类型。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351