局部内部类;
1. 内部类与外围类的关系
从这个例子谈起
1.1 内部来的代码隐藏作用
public
class
Parcel1 {
class
Contents {
private
int
i
= 11;
public
int
value() {
return
1;
}
}
class
Destination {
private
String
label
;
Destination(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(
"home"
);
//由于内部类隐藏代码的机制,你只能通过外部类的对象来创建内部类对象,除非加上static关键字
Parcel1.Contents c = p.new Contents();
}
}
这说明,(非static的)内部类的生命周期存在于外部类之内,要想在外部非静态方法外使用当然要延长其生命周期,把内部类变成static的;
变成嵌套类;
非静态内部类
结论:
a. 生命周期:依赖与外部类;
b. 访问权限:内部类对象拥有外部类所有元素的访问权;
2. 访问外围类
内部类可以直接访问外围类的所有成员,在其中实际上有一个Outter.this到外围类的引用;
使用.this和.new操作:
通过Outter.this可以在内部类获得外围类对象实例;
创建内部类:Outter outter = outter.new Inner();
3. 内部类与向上转型
可以通过在将外围类设置成private或protected,并通过create()方法,在其他地方创建或获得内部类实例,但是需要一个接口或者基类来取得引用;
讨论下列情况:
public
class
UseInner {
protected
class
II
implements
InnerInterface {
private
int
i
= 11;
public
class
A {
public
class
B {
public
class
C {
}
}
}
public
class
D {
}
public
II() {
//这是必须的
//
TODO
Auto-generated constructor stub
}
@Override
public
String test() {
//
TODO
Auto-generated method stub
return
String.valueOf(
i
);
}
}
public
static
void
main(String[] args) {
//
TODO
Auto-generated method stub
}
}
第三方使用者:
public
class
InnerITest
extends
UseInner {
public
InnerInterface getII() {
return
new
InnerITest.II();
}
public
static
void
main(String[] args) {
//
TODO
Auto-generated method stub
}
}
结论:即使内部类被声明为protected,在外围类的子类中如果要通过构造器创建其protected内部类,也需要该内部类有public构造器;如果该内部类被声明private的话,即使是外围类的子类也无法直接使用到内部类的Class;
Constructor[] cs = II.
class
.getConstructors();
for
(Constructor c : cs) {
System.
out
.println(c.getName() +
"_"
+ (c.getModifiers() == Modifier.
PUBLIC
));
}
getConstructors():只能获取到public构造器;
4. 内部类可以存在在哪里(这里作用域是其存在意义的标准)
4.1 方法和作用域内的内部类
4.2 匿名内部类(和向上转型紧密相关)
a. 需要注意:匿名内部类是继承了某个类,那么就不能直接使用父类的private域和方法;
b. 匿名内部类传参数:——需要基类有相应构造器;
c. 使用外围类的成员,可以直接使用,作用域局部变量需要final声明——作用域的限制;
你可能会想到容器为什么可以不用限制放入final对象实例呢?因为放入容器,实际上容器会创建一个指向实际对象的引用,这个引用是容器自己维护的,这个变量引用的作用域是在容器自身内的;但是内部类传入局部变量的话,这个变量引用什么对象并不是只受内部类控制,所以是不行的;
d. 匿名类的限制:一次只能实现或者继续一个接口或基类;
5. 工厂方法和内部类
interface
Service {
void
method1();
void
method2();
}
interface
ServiceFactory {
Service create();
}
class
ServiceEx
implements
Service {
@Override
public
void
method1() {
//
TODO
Auto-generated method stub
}
@Override
public
void
method2() {
//
TODO
Auto-generated method stub
}
ServiceFactory getFactory() {
return
new
ServiceFactory() {
@Override
public
Service create() {
//
TODO
Auto-generated method stub
return
new
ServiceEx();
}
};
}
}
public
class
FactoryInner {
public
static
void
main(String[] args) {
//
TODO
Auto-generated method stub
}
}
总结:优先使用类而不是接口,如果你的设计中需要某个接口,必须彻底了解它!!!
6. 嵌套类
static 内部类:结构嵌套,互相独立;
在接口中可以定义嵌套类;
7. 为什么需要内部类
a. 内部类是某种进入外围类的的窗口;
b. 更加灵活的多重继承,尤其是在要继承的接口和类有重叠的情况下(如方法签名相同);
7.1 闭包和回调(closure)
闭包使用的方式:
a. 指针;
b. 接口;
闭包:一个可调用的对象(内部类),它记录一些信息,这些信息来自于创建它的作用域(外围类);
内部类:面向对象(外围类对象)的闭包,它拥有一个指向外围类对象的引用:Outter.this;
回调:实现调用者和被调用者的分离,调用者不需要具体的被调用者(指针/接口),在运行时决定要调用什么方法,更加灵活;
7.2 内部类与控制框架
应用程序框架(application framework):我的理解就是用来解决一个主题问题的一组程序集合。设计应用程序框架,需要组件化来构成框架的各个部分,那么可能需要一个类继承和实现多个已有组件以及一个或多个可覆盖的方法,”将变化的和不变的事物分开“,典型运用模块方法,像Anroid中的activity等GUI中回调机制,大量运用了这个思想;
控制框架:用来解决
响应事件的需求;
书上给出了一个控制框架的例子,使用一个Controlls对象,维护一组Event时间,检查状态并执行,每个event都有自己ready()和action()来决定自己的行为;最后我们可以通过向controlls中放入不同的event来决定我们想要的东西是什么;
8. 内部类的继承
必须要让继承的类,和外部类连接起来
class
WithInner {
class
Inner {
}
}
public
class
InheritInner
extends
WithInner.Inner {
InheritInner(WithInner wi) {
wi.
super
(); //这一步必须的
}
public
static
void
main(String[] args) {
}
}
9. 内部类可以被覆盖吗:不可以,在继承的类中重写内部类(类名一样)和基类的内部类没有关系,两者的命名空间根本不一样
如果要继承可以向这样:
public
class
BigEgg
extends
Egg {
class
Yolk
extends
Egg.Yolk {
public
Yolk() {
System.
out
.println(
"create BigEgg.Yolk"
);
}
@
Override
public
void
f() {
System.
out
.println(
"BigEgg.f"
);
}
}
public
BigEgg() {
System.
out
.println(
"BigEgg"
);
this
.
y
=
new
Yolk();
}
public
static
void
main(String[] args) {
Egg e =
new
BigEgg();
}
}
//Output:
Egg
create Egg.Yolk
BigEgg
create Egg.Yolk
create BigEgg.Yolk
分别继承基类及其外部类:从输出结果我们可以看到都是先执行基类的构造器在执行导出类的,内部类也一样;
10. 局部内部类
局部内部类和匿名内部类之间的区别:你可以在局部(如方法内)创建多个局部内部类实例,但是后者只能用于实例初始化。