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