随笔-0  评论-0  文章-24  trackbacks-0

1 嵌套类定义
在一个类的内部定义另一个类,这种类称为嵌套类。

2 嵌套类的分类
嵌套类根据加不加static修饰符可分为两类:静态嵌套类和非静态嵌套类,后者又叫内部类,可再细分成三类。
顶级类 top-level classes
a.嵌套顶级类 nested top-level classes
b.成员内部类 instance inner classes
c.本地内部类 local inner classes
d.匿名内部类 anonymous inner classes

3 嵌套类的好处
a.令源代码更清晰。
b.减少命名冲突。
c.控制框架:一个“应用程序框架”是指一个或一系列类,它们专门设计用来解决特定类型的问题。为应用该框架,我们可从一个或多个类继承,并覆盖其中的部分方法。我们在覆盖方法中编写的代码用于定制由那些框架提供的常规方案,以解决实际问题。“控制框架”属于应用程序框架的一种特殊类型,受到对事件响应的需要的支配;主要用来响应事件的一个系统叫作“事件驱动的系统”。内部类可以在单独一个类里表达一个控制框架应用的全部实施细节,从而完整地封装与那个实施有关的所有东西。内部类用于表达多种不同类型的action(),以便解决实际的问题。除此以外,若使用了private内部类,实施细节会完全隐藏起来,可以安全地修改。因为能方便地访问外部类的任何成员,内部类使我们具体的实施变得更加巧妙。

4 嵌套类的共性
a.嵌套类是独立的类,编译后会生成相应.class文件,但之前有顶级类的类名和$。
b.嵌套类是顶级类的一部分,可以自由的访问顶级类的成员,不论是否为private的,同理,顶级类也可以访问嵌套类的private成员。
c.嵌套类的成员及方法可以与顶级类重名,在类内会被覆盖。
d.嵌套类也可继承和被继承,但要注意作用域规则。

5 嵌套顶级类
从技术上讲,嵌套顶级类不属于内部类。因为内部类和外部类共享一种实例关系,而嵌套顶级类只是位于一个类的内部,并没有以上共享关系。
静态的含义是,为创建一个嵌套顶级的对象,我们不需要一个顶级类对象。不能从嵌套顶级类的一个对象中访问一个顶级类对象。
与静态方法相似,嵌套顶级类只能访问顶级类的static(静态)成员及方法。

class TLC1 {
    
private static String s1 = "tlc1:static string";
    String s2 
= "tlc1:non-static string";

    
// 嵌套顶级类
    static class NTLC {
        
private String ns1 = "ntlc:string";
        
private static String ns2 = "ntlc:static string";

        
public void f() {
            System.out.println(s1); 
// 可访问private
            
// ! System.out.println(s2); 不能访问顶级类的非static成员
        }
    }

    
public void f() {
        System.out.println(
new NTLC().ns1); // 可访问private
        System.out.println(NTLC.ns2);
    }
}

main里的验证代码:

        TLC1.NTLC ntlc1 = new TLC1.NTLC();
        TLC1.NTLC ntlc2 
= new TLC1.NTLC();
        System.out.println(ntlc1 
== ntlc2); // 返回false
        ntlc1.f();
        
new TLC1().f();

运行结果:

false
tlc1:static string
ntlc:string
ntlc:static string

 
6 成员内部类
成员内部类内不允许有任何静态声明,能够访问成员内部类的唯一方式就是通过顶级类(外部类)对象。
a.从外部类的非静态方法访问
实质上是通过外部类的this引用实现的。
b.从外部类的静态方法访问
由于静态方法没有this引用,必须先创建一个外部类对象,然后调用.new创建成员内部类对象进行访问。
c.从其他类访问
先创建外部类对象,再调用.new创建成员内部类对象。
d.从内部类中访问外部类对象
可以使用Outer.this来访问。

class TLC2 {
    
private String s = "tlc2:string";

    
// 成员内部类
    class IIC {
        
private static final String is1 = "iic:static final string";
        
// ! static String is2 = "iic:static string"; static必须同时是final的
        private String is3 = "iic:string";

        
public void f1() {
            System.out.println(s);
            System.out.println(TLC2.
this); // 访问外部类对象
        }
        
// ! static void f2(){} 不能声明静态函数
    }
    
    
public void f1(){
        
new IIC().f1();
    }
    
public static void f2(){
        TLC2 tlc2 
= new TLC2();
        tlc2.
new IIC().f1();
    }
}

main代码:

        TLC2 tlc2 = new TLC2();
        tlc2.f1();
        tlc2.f2();
        TLC2.IIC iic 
= tlc2.new IIC();
        iic.f1();

结果:

tlc2:string
day090521.TLC2@1bab50a
tlc2:string
day090521.TLC2@c3c749
tlc2:string
day090521.TLC2@1bab50a

对于普通的类,可用的修饰符有final、abstract、strictfp、public和默认的包访问。
但是成员内部类更像一个成员变量和方法,可用的修饰符有:final、abstract、public、protected、private、默认、strictfp和static。
一旦用static修饰,它就变成静态嵌套类了囧。

7 本地内部类
本地内部类定义在方法中,类似于本地变量(局部变量)。所以可以用于修饰本地内部类的只有final和abstract。
本地内部类只能在定义该内部类的方法或块内实例化,不可以在外部对其实例化。
本地内部类对象不能使用该内部类所在方法的非final局部变量。因为方法的局部变量位于栈上,只存在于该方法的生命期内。当一个方法结束,其栈结构被删除,局部变量成为历史。但是该方法结束之后,在方法内创建的内部类对象可能仍然存在于堆中!如果对它的引用被传递到其他某些代码,并存储在一个成员变量内。正因为不能保证局部变量的存活期和方法内部类对象的一样长,所以内部类对象不能使用它们。
静态方法是没有this引用的,因此在静态方法内的内部类遭受同样的待遇,即只能访问外部类的静态成员。

class TLC3 {
    
private String s = "tlc3:string";

    
public void f(boolean b) {
        String s1 
= "tlc3:f:string";
        
final String s2 = "tlc3:f:final string";
        
if (b) {
            
// 本地内部类
            class LIC1 { // 块内可见
                private String ls;

                LIC1(String str) {
                    
this.ls = str;
                }

                
public void f() {
                    System.out.println(s);
                    
// ! System.out.println(s1); 只能使用final类型的外部对象
                    System.out.println(s2);
                    System.out.println(ls);
                }
            }
            
// ! new LIC(); 只能有一个构造函数
            System.out.println(new LIC1("lic1:string").ls);

            
final class LIC2 extends LIC1 {
                LIC2() {
                    
super("lic2:string");
                    
super.f();
                }
            }
            
new LIC2();
            
// ! class LIC3 extends LIC2{} final类不可继承
        } else {
            
class LIC1 {
            }
        }
        
// ! new LIC2(); 超出作用域
    }
}

main代码:

        new TLC3().f(true);

结果:

lic1:string
tlc3:string
tlc3:f:final string
lic2:string
上面的代码会生成TLC3$1LIC1.class和TLC3$2LIC1.class,可看出命名规则:外部类名+$+数字编号+内部类名,以防内部类重名。


8 匿名内部类
a.用于实现一个接口
b.用于扩展拥有非默认构造函数的一个类
c.用于执行字段初始化
d.通过实例初始化进行构建(匿名内部类不可拥有构造函数)

class TLC4 {
    
// 匿名内部类
    public Contents f1() {
        
return new Contents() {
            @Override
            
public String get() {
                
return "tlc4:f1:anonymous:string";
            }
        };
    }

    
public void f2(AC ac) {
        ac.f1();
        ac.f2();
    }

    
public AC f3(final int i) {
        
return new AC(i) {
            
// 初始化
            {
                
if (i == 1)
                    System.out.println(
"i==1 is true");
            }

            @Override
            
public void f1() {
                System.out.println(
"tlc4:f3:anonymous:f1");
            }
        };
    }
}

abstract class AC {
    
private int i;

    
public AC(int i) {
        
this.setI(i);
    }

    
abstract public void f1();

    
public void f2() {
        System.out.println(
"AC:f2");
    }

    
public void setI(int i) {
        
this.i = i;
    }

    
public int getI() {
        
return i;
    }
}

interface Contents {
    String get();
}

main代码:

        TLC4 tlc4 = new TLC4();
        System.out.println(tlc4.f1().get());
        tlc4.f2(
new AC(3) {
            @Override
            
public void f1() {
                System.out.println(
"anonymous:f1 i:" + this.getI());
            }
        });
        tlc4.f3(
1);

执行结果:

tlc4:f1:anonymous:string
anonymous:f1 i:
3
AC:f2
i
==1 is true


9 链接到外部类
创建自己的内部类时,那个类的对象同时拥有指向封装对象(这些对象封装或生成了内部类)的一个链接。内部类的一个对象只能与封装类的一个对象联合创建。

10 小结
java嵌套类内容很多,很纷杂。要记清其种类以及每种相应的规则,做到胸有成竹。本文完整源代码下载

posted on 2009-05-21 17:45 chenkkkabc 阅读(205) 评论(0)  编辑  收藏 所属分类: java特性