Java内部类

Posted by Csming on 2017-03-15

什么是内部类

将一个类的定义放在另一个类的内部,就称之为内部类

创建内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Parcel1 {
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 = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(String args[]){
Parcel1 p = new Parcel1();
p.ship("Tasmania");
}
}

可以使外部类有一个方法,该方法返回一个指向内部类的引用,就像在to()和contents()方法

连接到外部类

内部类拥有其外围类的所有元素的访问权;
内部类的对象可以访问其外为对象的所有成员

.this与.new

  • 1. .this可以生成对外部类的对象的引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DotThis{
void f(){System.out.println("DoThis.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();//利用outer函数调用外部类对象
}
}
  • 2. .new告知某些其他对象,去创建其某个内部类的对象;
1
2
3
4
5
6
7
public class DotNew{
public class Inner{}
public static void main(String args[]){
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();//使用.new创建内部类对象
}
}

内部类的向上转型

将内部类向上转型为其基类,尤其是转型为一个接口时;内部类就有了用武之地;从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上是一样的;

  • 创建以下接口
1
2
3
4
5
6
7
public interface Destination{
String readLabel();
}

public interface Contents{
int value();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Parcel{
private class PContents implements Contents{
private int i = 11;
public int value(){return i;}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String whereTo){
label = whereTo;
}
public String readLabel(){return label;}
}
public Destination destination(String s){
return new PDestination(s);
}
public Contents contents(){
return new PContents();
}
}

public class TestParcel{
public static void main(String args[]){
Parcel p = new Parcel();
Contents c = p.contents();
Destination d = p.destination("Tasmania");
}
}

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

可以在一个方法或者一个作用域内部定义内部类;
有两个理由这么做:
1.实现了某个类型的接口,于是可以创建并返回对其引用
2.要解决一个问题,于是创建一个类来辅助解决方案,但又不希望这个类是公用的

  • 可以这么做:
    1.一个定义在方法中的类
    2.一个定义在作用域内的类,此作用域在方法的内部
    3.一个实现了接口的匿名类
    4.一个匿名类,扩展了有非默认构造器的类
    5.一个匿名类,执行了字段的初始化
    6.一个匿名类,通过实例初始化实现构造(匿名类不可能有构造器)

  • 1.方法中的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Parcel{
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PEestination(String whereTo){
label = whereTo;
}
public String readLabel(){return label;}
}
return new PDestination(s);
}

public static void main(String args[]){
Parcel p = new Parcel();
Destination d = p.destination("Tasmania");
}
}
  • 2.嵌入作用域中的内部类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Parcel{
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();
}
}

public void track(){internalTracking(true);}

public static void main(String args[]){
Parcel p = new Parcel();
p.track();
}
}

匿名内部类

没有名字的类;作为实现了某个接口或基类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Parcel{
public Contents contents(){
return new Contents(){//匿名类
private int i = 11;
public int value(){return i;}
};
}

public static void main(String args[]){
Parcel p = new Parcel();
Contents c = p.contents();
}
}
  • 注意点:
    1.若基类需要一个带有参数的构造器;则给匿名类一个参数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Parcel{
public Wrapping wrapping(int x){
return new Wrapping(x){
//这个参数是提供给基类构造器的,匿名类中不能使用
public int value(){
return super.value()*47;
}
};
}
public static void main(String args[]){
Parcel p = new Parcel();
Wrapping w = p.wrapping(10);
}
}

Wrapping基类如下:

1
2
3
4
5
public class Wrapping{
private int i;
public Wrapping(int x){i = x;}
public int value(){return i;}
}

2.若希望匿名类可以使用一个定义在外部的对象,则需要将该参数声明为final;//代码太多懒得写了……

工厂方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
interface Service{
void method1();
void metiod2();
}

interface ServiceFactory{
Service getService();
}

class Implementation1 implements Servie{
private Implementation1(){}
public void method1(){
...
}
public void method2(){
...
}
public static ServiceFactory factory = new ServiceFactory(){
publc Service getService(){
return new Implementation1();
}
};

}

class Implementation2 implements Servie{
private Implementation1(){}
public void method1(){
...
}
public void method2(){
...
}
public static ServiceFactory factory = new ServiceFactory(){
publc 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(Implemention1.factory);
serviceConsumer(Implemention2.factory);
}
}

嵌套类

将内部类声明为static;由此,内部类对象与外部类对象之间没有了联系

It means:
1.要创建嵌套类的对象,不需要其外部类的对象
2.不能从嵌套类的对象中访问非静态的外部类对象

普通的内部类的字段和方法只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段;也不能包含嵌套类

但是嵌套类就可以包含这些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Parcel{
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 ParceDestination(String whereTo){
label = whereTo;
}
public String readLabel(){return label;}
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 ParcelContents();
}
public static Contents contents(){
return new ParcelContents();
}

public static void main(String args[]){
Contents c = contents();
Destination d = destination("Tasmania");
}
}
}

接口内部的类

用于进行测试

从多层嵌套类中访问外部类的成员

一个内部类无论被嵌套多少层,其依旧可以透明的访问所有它嵌入的外围类的所有成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

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

闭包和回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package closure;

interface Incrementable{
void increment();
}
class MyIncrement{
public void increment(){System.out.println("Other operation");}
static void f(MyIncrement mi){mi.increment();}
}

class Callee1 implements Incrementable{
private int i = 0;
public void increment(){
i++;
System.out.println(i);
}
}
class Callee2 extends MyIncrement{
private int i = 0;
public void increment(){
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable{
public void increment(){
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();
}
}

输出:
Other operation
1
1
2
Other operation
2
Other operation
3

内部类与控制框架

内部类的继承

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
class WithInner{
class Inner{}
}

public class InheritInner extends WithInner.Inner{
InheritInner(WithInner wi){
wi.super();//必须使用此句
}
public static void main(String args[]){
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}

内部类可以被覆盖吗

不能被覆盖的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){
...
}
}
public Egg(){
...
y = new Yolk();
}
}

public class BigEgg extends Egg{
public class Yolk{
pubic Yolk(){...}
}
public static void main(String args[]){
new BigEgg();
}
}

能被覆盖的情况

必须使用extends

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){
...
}
}
public Egg(){
...
y = new Yolk();
}
}

public class BigEgg extends Egg{
public class Yolk extends Egg.Yolk{
pubic Yolk(){...}
}
public static void main(String args[]){
new BigEgg();
}
}

局部内部类与匿名类的区别

一个有名字一个没有名字

内部类标识符

Xxx&Xxx.java


资料:《Thking in java》