背景
继续查缺补漏
1.使用.this与.new
当需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this。例如:
package c10;
public class DotThis {
void f(){ System.out.println("DotThis.f()");}
public class Inner{
public DotThis outer(){
return DotThis.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。例如:
package c10;
public class DotNew {
public class Inner{}
public static void main(String[] args){
DotNew dn=new DotNew();
DotNew.Inner dni=dn.new Inner();
}
}
在拥有外部类对象之前是不可能创建内部类对象的,因为内部类对象会暗暗地连接到创建它的外部类对象上。
但是如果你创建的是嵌套类(静态内部类),那就不需要对外部类对象的引用。
2.匿名内部类
匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,当时不能两者兼备,
而且如果是实现接口,也只能实现一个接口。
在匿名类中不可能有命名构造器,但通过实例初始化,就能够为匿名内部类实现构造器的效果,例如:
package c10;
abstract class Base{
public Base(int i){
System.out.println("Base constructor.i="+i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i){
return new Base(i){
{System.out.println("Inside instance initializer");}
public void f(){
System.out.println("In anonymous f()");
}
};
}
public static void main(String[] args){
Base base=getBase(47);
base.f();
}
}
3.使用匿名内部类实现工厂方法
例如:
package c10;
import static tools.Print.*;
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
private Implementation1(){}
public void method1(){ print("Implementation1 method1");}
public void method2(){ print("Implementation1 method2");}
public static ServiceFactory factory=new ServiceFactory(){
public Service getService(){
return new Implementation1();
}
};
}
class Implementation2 implements Service{
private Implementation2(){}
public void method1(){ print("Implementation2 method1");}
public void method2(){ print("Implementation2 method2");}
public static ServiceFactory factory=new ServiceFactory(){
public Service getService(){
return new Implementation2();
}
};
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s=fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}
}
4.嵌套类
如果不需要内部类对象与其外部类对象之间有联系,可以将内部类声明为static。
要创建嵌套类对象,并不需要其外部类的对象。
不能从嵌套类的对象中访问非静态的外部类对象。
5.接口内部的类
放到接口中的任何类都自动地是public和static。例如:
package c10;
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();
}
}
}
6.从多层嵌套类中访问外部类成员
例如:
package c10;
class MNA{
private void f(){}
class A{
private void g(){}
public class B{
void h(){
g();
f();
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args){
MNA mna=new MNA();
MNA.A mnaa=mna.new A();
MNA.A.B mnaab=mnaa.new B();
mnaab.h();
}
}
7.为什么需要内部类
内部类有效地实现了“多重继承”,也就是说,内部类允许继承多个非接口类型(类过抽象类)。例如:
package c10;
class D{}
abstract class E{}
class Z extends D{
E makeE(){
return new E(){};
}
}
public class MultiImolementation {
static void takeD(D d){}
static void takeE(E e){}
public static void main(String[] args){
Z z=new Z();
takeD(z);
takeE(z.makeE());
}
}
内部类的特性:
(1)内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立
(2)在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。
8.闭包与回调
闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。内部类是面向
对象的闭包。回调的价值在于它的灵活性,可以在运行时动态地决定调用什么方法。通过回调,
对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。例如:
package c10;
import static tools.Print.*;
interface Incrementable{
void increment();
}
//Very simple to just implement the interface:
class Callee1 implements Incrementable{
private int i=0;
public void increment(){
i++;
print(i);
}
}
class MyIncrement{
MyIncrement(){}
public void increment(){ print("Other oepration");}
static void f(MyIncrement mi){ mi.increment(); }
}
//If your class must implement increment() in
//some other way.you must use an inner class:
class Callee2 extends MyIncrement{
private int i=0;
public void increment(){
super.increment();
i++;
print(i);
}
private class Closure implements Incrementable{
public void increment(){
//Specify outer-class method.otherwise
//you'd get an infinite recursion:
Callee2.this.increment();
}
}
Incrementable getCallbackReference(){
return new Closure();
}
}
class Caller{
private Incrementable callbackReference;
Caller(Incrementable cbh){ callbackReference=cbh;}
void go(){ callbackReference.increment();}
}
public class Callbacks {
public static void main(String[] args){
Callee1 c1=new Callee1();
Callee2 c2=new Callee2();
MyIncrement.f(c2);
Caller caller1=new Caller(c1);
Caller caller2=new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
9.内部类继承
package c10;
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner {
//InheritInner(){} //Won't compile
InheritInner(WithInner wi){
wi.super();
}
public static void main(String[] args){
WithInner wi=new WithInner();
InheritInner ii=new InheritInner(wi);
}
}
指向外部类对象的“秘密的”引用必须被初始化。
InheritInner只继承了内部类,构建器必须传递一个指向外部类对象的引用,在构建器内部需要使用 wi.super()
10.内部类可以被覆盖
package c10;
import static tools.Print.*;
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 inserYolk(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(){inserYolk(new Yolk());}
public static void main(String[] args){
Egg2 e2=new BigEgg2();
e2.g();
}
}
需要明确地继承某个内部类,像上面那样。Egg2.Yolk
11.局部内部类
使用局部内部类而不是匿名内部类的理由是我们需要一个已命名的构造器,或者需要重载构造器,
而匿名内部类只能用于实例初始化。另一个理由是需要不止一个内部类的对象。