1.内部类的实例与外部类的实例共享一种特殊的关系,这种特殊的关系为内部类中的代码提供对封装(外部)类成员的访问。其实,内部类就是外部类的一部分。不仅仅是“一部分”,而且是外部类的一个完整的,正式的成员。内部类实例可以访问外部类的所有成员,甚至是那些标识为private的成员。
1.1编写常规内部类
此处的常规表示:内部类不是静态的,局部方法的,匿名的。应是如下形式的:
class MyOuter {
class MyInner{ }
}
编译时会生成两个类文件:
javac MyOuter.java
生成:
MyOuter.class和MyInner.class
常规的内部类不能有任何类型的静态生命。能够访问内部类的唯一方法是通过外部类的一个活的实例。
看如下代码:
class MyOuter {
private int x=7;
class MyInner {
public void seeOuter(){
System.out.println("Outer x is "+x);//可以直接访问外部类的成员,即使是private的
}
}
}
实例化外部类
在外部类中实例化内部类
class MyOuter {
private int x=7;
public void makeInner(){
MyInnner in=new MyInner();
in.seeOuter();
}
class MyInner {
public void seeOuter() {
System.out.println("Outer x is "+x);
}
}
}
可见,MyOuter将MyInner当做其他任何可访问的类一样,它使用类名称【new MyInner()】来实例化。然后再引用变量上调用方法[in.seeOute()]。这种方法能起作用的唯一原因是:外部类实例方法代码正在进行实例化。换句话说,已经存在一个外部类的实例---运行makeInner()的实例。
从外部类实例代码之外创建外部类的对象
没有外部类的实例,就不能从外部类的静态方法实例化内部类(因为静态代码内不存在this引用)。内部类的实例总是拥有一个外部类的隐含引用。编译器负责处理这种隐含关系。
在外部类之外,创建内部类实例,可以这样做:
public static void main(String[] args){
MyOuter mo=new MyOuter();
MyOuter.MyInner inner=mo.new MyInner();
inner.seeOuter();
}
或者:
public static void main(String[] args){
MyOuter.MyInner inner=new MyOuter().new MyInner();
inner.seeOuter();
}
小结:
在外部类实例代码内部,以正常的方法使用内部类名称。
MyInner mi=new MyInner();
在外部类实例代码外部(包括外部类内的静态方法代码),内部类名称必须包含外部类名称:
MyOute.MyInner
为了实例化他,必须使用一个对外部类的引用。
new MyOuter().new MyInner(); 或者是 outerObjRef.new MyInner();
1.2 在内部类内部引用内部或外部实例
在内部类代码内,this引用会引用该内部类的实例,如果内部类代码希望显示的引用一个与该内部类实例相关的外部类实例,应使用NameOfOuter.this(如MyOut.this)
class MyOuter {
private int x=7;
public void makeInner(){
MyInnner in=new MyInner();
in.seeOuter();
}
class MyInner {
public void seeOuter() {
System.out.println("Outer x is "+x);
System.out.println("Inner class ref is "+this);
System.out.println("Outer class ref is "+MyOuter.this);
}
}
public static void main(String[] args){
MyOuter.MyInner inner=new MyOuter.new MyInner();
inner.seeOuter();
}
}
2.局部方法内部类
即在某个方法内定义的内部类。
2..1 局部方法内部类对象能做什么,不能做什么
局部方法内部类只能在定义该内部类的方法内实例化。同样,局部方法内部类对象可以访问外部类对象的所有变量,但是,内部类对象不能使用他所在的方法的局部变量(除非该变量定义为final的)。因为方法的局部变量只能存在于该方法的生命周期内,即该方法的栈存活的时间,但是局部方法内部类实例可能在栈消失后,仍然存活于某个堆上(只要有个活引用就行)。这样的话,如果不对内部类对象使用他所在的方法的局部变量做限制,很可能会出错。
注:在一个静态方法内声明的局部类,只能访问该封装类的静态成员,因为没有与该封装类相关的任何实例。如果位于一个没有this的静态方法内,则该方法内的内部类的限制于静态方法相同。换句话说,根本不能访问实例变量。
3.匿名内部类
1.匿名内部类形式一
class Popcorn {
public void pop(){
System.out.println("popcorn");
}
}
class Food {
Popcorn p=new Popcorn(){
pubic void pop(){
System.out.println(" anonymous popcorn");
}
public void otherMethod(){
//add the code here
}
};
}
注意此处,p实际上引用的是Popcorn类的一个子类的对象。但是由于使用超类型的引用变量来引用子类对象,p并不能调用otherMethod方法。
3.2 普通的就是匿名内部类形式二
interface Cookable{
public void cook();
}
class Food {
Cookable c=new Cookable(){
public void cook(){
System.out.println("anonymous cookable inplementer");
}
};
}
此处c引用的是一个实现了Cookable接口的一个类的对象。
关于内部接口实现器要注意:只能实现一个接口。
3.3 变元内声明的匿名内部类
class MyClass{
void go(){
Bar b=new Bar();
b.doStuff(new Foo(){
public void foof(){
System.out.println("foofy");
}
});
}
}
interface Foo {
void foof();
}
class Bar {
void doStuff(Foo f){}
}
不再赘述,想想Java Swing编程中添加的actionListener,也是这么种情况。
4.静态嵌套类
实际上静态嵌套类不能称作静态内部类。因为按照内部类的标准定义,他们必须与外部类共享一种特殊的关系。但是静态嵌套类则没有。警惕啊嵌套类就是在另一个类作用域内的非内部类(也称为“顶级”类)。因此,对于静态类,更重要的是名字空间的解析,而不是两个类之间的隐含关系。
下面看如何实例化和使用静态嵌套类。
class BigOuter {
static class Nest {
void go(){
System.out.println("hi");
}
}
}
class Broom(){
static class B2{
void goB2(){
System.out.println("hi 2");
}
}
public static void main(String[] args){
BigOuter.Nest n=new BigOuter.Nest();//跟用另外一个包中的类差不多吧
n.go();
B2 b2=new B2();
b2.goB2();
}
}