内部类:通俗的说就是定义在另一个类中的类,通过内部类,可以做到代码隐藏,内部类也可以和与外围类通信,有时,它可以让代码更优雅而清晰,本质作用:多重继承,信息隐藏,闭包回调,更加灵活适合应用控制框架;
心得:
1. 如果一个类实现了多个接口,不同的功能,那么通过内部类闭包的方式,可以返回给client不同接口的闭包,这样不同的client可以只获取对应功能的部分,这是一种安全的调用方式;
使用接口的方式:
a. 单一类;
b. 内部类;
内部的分类:
静态内部类;
非静态内部类;
匿名内部类;
局部内部类;
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. 局部内部类
局部内部类和匿名内部类之间的区别:你可以在局部(如方法内)创建多个局部内部类实例,但是后者只能用于实例初始化。