一个类的定义放在另一个定义内部,这就是内部类。
10.1 创建内部类
public class Parcel1{
class Contents{
private int i = 11;
public int value (){ return i; }
}
class Destination {
private String able;
Destinaltion(String whereTo){
label = whereTo;
}
String readLabel (){ return label;}
}
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("Tasmainaaaaa");
}
}
10.2 链接到外部类
内部类是一种名字隐藏和组织代码的模式,当生成内部类对象时,此对象可以用访问外围对象的所有成员
10.3 使用 .this与。new
对外部类的引用:外部类的名字紧跟this.
创建内部类对象:使用 .new语法
10.4 内部类与向上转型
内部类向上转型为基类或一个接口,所得到的是指向基类或接口的引用,隐藏实现细节
public interface Destination{
String readLabel();
}
public interface Contents{
int value();
}
//(接口的所有成员自动被设置成public)
class Parcel4{
private class Pcontents implements Contenets {
private int i =1;
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 PDestinations(s);
}
public Contents contents(){
return new PContents();
}
}
public class TestPracel{
public static void main(String[] args){
Pracel4 p = new Parcel4();
Contents c = p.contents();
Destriation d = p.destination("tasmainaaa");
}
内部类PContents是privae,只有Parcel4 可以访问, PDesination是protected只有Parcel4及子类可以访问
private内部类可以阻止任何依赖型的代码,隐藏实现细节。
10.5 在方法和作用域内的内部类
可以在方法或在作用域定义内部类。
理由
- 1 实现某种类型的接口,可以创建并返回对其引用。
- 2 创建一个类来辅助解决方案,但不希望这个类时公用的。
内部类的实现。
- 1> 定义在方法中的内部类
- 2>定义在作用域内的类,作用域的方法在内部
- 3>一个实现接口的匿名类
- 4>一个匿名类,它扩展了默认构造器的类
- 5>一个匿名类,它执行字段初始化
- 6>一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)
10.6 匿名内部类
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();
}
}
匿名内部类末尾的分号,并不是用来标记内部类的结束,标记的是表达式的结束,这个表达式包含了匿名内部类。
匿名内部类使用外部对象(不包含基类使用)参数引用需要final修饰。
匿名内部类实例初始化的效果就是构造器,但受到了限制(不能重载实例初始化方法,匿名内部类可以扩展类,也可以实现接口,但不能两者兼备,如果是实现接口也只能实现一个接口)
- 10.6.1 再访工厂方法
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implement Service{
private Implementation1(){}
public method1(){ print("Implementation1 method1")}
public method2(){ print("Implementation1 method2")}
}
public static ServiceFactory factory =
new ServiceFactory(){
public Service getService(){
return new Implementation1 ();
};
}
class Implementation2 implement Service{
private Implementation2(){}
public method1(){ print("Implementation2 method1")}
public method2(){ print("Implementation2 method2")}
}
public static ServiceFactory factory =
new ServiceFactory(){
public Service getService(){
return new Implementation2 ();
};
}
public class Factories{
public static void ServiceConsumer(ServiceFactory factory){
Service s = factory.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
ServiceConsumer(Implementation1.factory);
ServiceConsumer(Implementation2.factory);
}
}
由上构造器都可以是private,并没有创建工厂的类具名
优先使用类而不是接口。如果你的设计需要接口,你必须了解它。否则,不到迫不得已,不需要将它放到你的设计中
10.7 嵌套类
如果不需要内部类对象与外围类有联系,可以将内部类对象声明为static,这就是嵌套类。
普通内部类对象隐式保存了一个引用,指向创建它的外围类对象,而内部类是static时,嵌套类就意味着
- 1 要创建嵌套类的对象,并不需要外围类对象。
- 2 不能从嵌套类对象中访问费静态的外围类对象
(注意普通类内部不能有static数据和static字段,也不能包含嵌套类,但嵌套类可以包含这些东西)
10.8 为什么需要内部类
Sun公司为什么会增加这个语言特性,一般来说,内部类继承某个类或实现某个接口,内部类的代码操作创建它的外围类的对象,内部类提供了某种进入外围类的窗口。
- 1) 如果只是需要一个接口的引用,为什么不通过外围类实现那个接口
答案是:“如果这能满足需求,那么就应该这样做” - 2) 内部类实现一个接口与外围类实现这个接口有什么区别
答案是:后者不是总能享用到接口带来的方便,有时需要用到接口的实现,所以使用最吸引人的原因是:
每个内部类都能独立继承一个接口的实现,所以无论外围类是否已经继承了某个接口的实现,对于内部类都没有影响
也就是说内部类允许继承多个非接口类型
内部类可以获得其他一些特性
1)内部类可以有多个实例,每个实例都有自己的状态信息,并且与外围类的对象信息相互独立。
2)在单个外围类中,可以让内部类以不同的方式实现同一个接口,或继承同一个类。
3)创建内部类对象不依赖外围类对象的创建。
4)内部类没有“is-a”关系,他就是一个独立的类
10.8.1 闭包与回调
通过内部类提供的闭包功能是优良的解决方案,它比指针更灵活,更安全。
10.9 内部类的继承
内部类的构造器不需连接到指向外围类对象的引用,所以在继承内部类的时候,事情会变得有点复杂,问题在于,那个指向外围类的对象的“秘密的”引用必须被初始化,而在导出类中不再存在可连接的默认对象。要解决这个问题,必须使用特殊的语法说明它们之间的关联。
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner wi){}
wi.super();
}
public static void main(String[] args){
WithInner wi = new WitnInner();
InherItInner ii = new InheritInner(wi);
}
}
10.10 内部类可以被覆盖吗
覆盖内部类就好像是它的一个方法,其实并不起什么作用
10.11 局部内部类
可以访问当前代码块内的常量,以及此外围类所有成员。
匿名内部类和局部内部类创建的比较
interface Counter{
int next();
}
public class LocalInnerClass{
private int count = 0;
Counter getCounter(final String name){
class LocalCounter implements Counter{
public LocalCounter(){}
public int next(){
return count++;
}
}
}
Counter getCounter2(final String name){
return new Counter(){
public int next(){
return count++;
}
};
}
}
当需要一个已命名的构造器,或者需要重载构造器,使用局部内部类,匿名内部类只能用于实例初始化。
当需要不止一个内部类对象时,使用局部内部类。
10.12 内部类标识符
每个类都会产生一个.class文件,其中包含了如何创建该类型的全部信息(此信息产生一个“meta-class”,叫Class对象)内部类必须生成一个.class文件以包含它们的Class对象信息。这些文件的命名有严格的规定:外围类的名字,加上“$”再加上内部类的名字