美文网首页
6内部类

6内部类

作者: Teemo_fca4 | 来源:发表于2020-05-06 16:54 被阅读0次
内部类

外部类的方法使用内部类时 与其他普通类类似 可以直接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的子类,但是我们现在描述的主体是容器而不是容器持有对象的类型。

相关文章

  • 内部类

    成员内部类 局部内部类(定义在方法内和定义在作用域内的类) 匿名内部类

  • Java 内部类

    内部类包括成员内部类、方法内部类、*静态内部类、匿名内部类*。 内部类的作用 由于内部类的实现和外部类没有关系,内...

  • Java学习——内部类

    内部类 一,成员内部类(包括静态内部类和非静态内部类) 非静态内部类可以直接访问外部类的成员,反之则不行 非静态内...

  • Java 内部类、静态内部类、方法内部类(未完待续)

    内部类 什么是内部类?内部类其实就是在一个类中创建的类。内部类有四种: 成员内部类 静态内部类 局部内部类 匿名内...

  • java 内部类

    一般有四种内部类的使用方式: 嵌套的内部类 方法内的内部类 静态内部类 匿名内部类 什么时候用内部类: 有时候明显...

  • 内部类

    内部类 1.可以访问访问其外部类所有属性和方法,无需创建外部类对象 2.必须创建内部类对象,否则无法从外部类访问内...

  • Java 中的方法内部类

    Java 中的方法内部类 方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内...

  • java——内部类

    内部类 定义: 内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内...

  • java之面向对象5

    方法内部类: 简而言之就是定义在外部类的方法内的类。 方法内部类只在该方法的内部可见,即只在该方法内可以使用。 方...

  • Java 内部类

    1. 内部类 概念:在一个类的内部再定义一个完整的类内部类分为 4 类:成员内部类、静态内部类、局部内部类、匿名内...

网友评论

      本文标题:6内部类

      本文链接:https://www.haomeiwen.com/subject/zkiwghtx.html