黑马程序员技术交流社区
标题: 内部类 小结一 [打印本页]
作者: 321哈哈哈 时间: 2017-10-12 01:39
标题: 内部类 小结一
内部类允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性。
内部类看起来像一种代码隐藏机制;同时它了解外围类,并能与之通信。
Private(成员)内部类:
可以完全阻止任何依赖于类型的编码??
(将内部类向上转型为基类或者接口,通过方法返回的只是指向基类或接口的引用,就像new了一个接口对象)(这时扩展接口没有价值)
(甚至无法实现向下转型,因为无法访问该类名)
完全隐藏了实现的细节(private修饰)
嵌套类:
static修饰的(成员)内部类
内部类对象与其外围类对象没有联系(没有保存外部类对象的引用,要创建嵌套类对象并不需要其外部类对象)
不能从嵌套类的对象中访问非静态的外围类成员
普通内部类中不能有static成员(也不能有嵌套类);嵌套类可以包含所有这些东西
局部内部类
定义在方法中(甚至只存在于方法的一个作用域内)
匿名(局部)内部类:(类的定义和创建对象一举完成)
可以继承有非默认构造方法的类(一样传参)
不可能有构造器,可以在类内添加字段初始化(或者构造代码块)来替代
字段初始化所需要的值作为所在方法的参数传入,该形参要声明为final??
局限是不能重载这种“构造器”
可以扩展类或实现接口,但不能两者兼备
为什么需要内部类
内部类使得多重继承的解决方案变得完整(接口解决了部分问题)
每个内部类都能独立的继承类(实现接口)
通过内部类可以继承多个非接口类型
内部类还有的其他特性:
内部类可以有多个实例,每个实例都有自己独立的状态信息
在单个外部类中,可以让多个内部类以不同方式实现同一个接口(继承同一个类)
内部类并没有令人迷惑的“is - a”关系(当外部类不满足某个is - a测试,但需要继承那个类,可以让内部类继承)
这些特性本身是相当直观的,但这些特性的使用是设计阶段考虑的问题。
当见到这些语言特性的实际应用时,就最终理解它们了。
Tip:
典型的情况是,外部类有一个方法,返回一个指向内部类对象的引用。
如果想从外部类的非静态方法之外的任意位置创建某个内部类对象,必须指明完整类型:外部类.内部类
能访问其外围对象的所有成员,就像他们自己拥有似的
因为,当某个外围类对象创建了一个内部类对象时,内部类对象必定会秘密地捕捉一个指向那个外围类对象的引用,所以在拥有外部类对象之前是不可能创建内部类对象的
内部类(非static时)对象只能在于其外部类对象相关联的情况下才能被创建
所以创建内部类对象时,必须在new表达式中提供对其外部类对象的引用(使用.new语法),同时给外部类对象一个消息,创建其内部类对象的消息,像命令它调用自己的成员方法一样。
如果要在内部类里获得对外部类对象的引用:使用外部类名.this
这个this是外部类的一个隐式成员
只写this获得的是指向内部类对象的引用
*接口内部的类
自动的是public static的
通过这样,可以创建某些公共代码,使得它们可以被某个接口的所有不同实现所公用??
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();
}
}
} /* Output:
Howdy!
*///:~
使用嵌套类来放置测试代码(main方法,方便得测试每个类)
会生成一个独立的类TestBed$Tester.class(执行java TestBed$Tester 可以测试)
发布产品时,将这个class文件删除(相当于源码中 类里面没写测试的内部类)
public class TestBed {
public void f() { System.out.println("f()"); }
public static class Tester {
public static void main(String[] args) {
TestBed t = new TestBed();
t.f();
}
}
} /* Output:
f()
*///:~
*多层嵌套类
可以透明得访问它所嵌入的外部类的所有成员
创建多层嵌套的内部类对象的标准写法:.new能产生正确的作用域,所以不必在调用构造器时写完整类名
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();
}
} ///:~
闭包与回调
闭包(closure)是一个对象。它记录了一些信息,这些信息来自于创建它的作用域。
内部类对象自动包含外部类对象的引用,可以自由使用外部类的信息,是一个闭包。
通过内部类提供闭包(内部类对象),来实现回调(callback),比指针更灵活、安全。
本例中也能看出interface是如何允许接口与接口的实现完全独立的(private内部类实现接口;public方法提供闭包,即接口引用)
interface Incrementable {
void increment();
}
//接口和类中有相同的方法,所以下面的Callee2使用的内部类来实现多重继承
class MyIncrement {
public void increment() {
System.out.println("Other operation");
}
}
// 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++;
System.out.println(i);
}
//该内部类对象就是一个闭包(包含了外部类对象的信息)
private class Closure implements Incrementable {
public void increment() {
//这个this是指向Callee2对象(被回调)的引用
//由此提供了闭包的“钩子”(hook)功能
//该闭包只能调用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) {
Callee2 c2 = new Callee2();
Caller caller2 = new Caller(c2.getCallbackReference());
caller2.go();//使用闭包回调
caller2.go();
}
}
*内部类的继承
子类和被继承的内部类一样,其构造方法必须连接到指向其外围类对象的引用??
所以在继承内部类时:外围类引用必须被初始化;导出类中不再存在可连接的默认对象(所以下例中的wi.super()不能省略)??
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);
}
} ///:~
*内部类可以被重写吗
如下例所示,导出类和基类中同名的两个内部类是完全独立的两个实体,各自在自己的命名空间内??,互不影响,没有“重写”
(继承后父类空间存在于子类空间中。父类的内部类的作用域是父类空间,父类可以使用,但如果是开放权限的内部类,子类也能使用)??
// An inner class cannot be overriden like a method.
// 内部类不能像父类方法一样被重写
import static net.mindview.util.Print.*;
class Egg {
private Yolk y;
protected class Yolk {
public Yolk() { print("Egg.Yolk()"); }
}
public Egg() {
print("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {
public Yolk() { print("BigEgg.Yolk()"); }
}
public static void main(String[] args) {
new BigEgg();
}
} /* Output:
New Egg()
Egg.Yolk()
*///:~
明确继承内部类是可以的:
// Proper inheritance of an inner class.
import static net.mindview.util.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 insertYolk(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() { insertYolk(new Yolk()); }
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
} /* Output:(创建一个子类对象前先创建其父类对象,同样适用于内部类继承的情况)
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
*///:~
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |