.println(Outer.this.s);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? ? new Inner(k);
? ? ? }
?
? ? ? publicstaticvoid main(String[] args) {
? ? ? ? ? ? ? // 访问局部内部类必须先有外部类对象
? ? ? ? ? ? ? Outer out = new Outer();
? ? ? ? ? ? ? out.f(3);
? ? ? }
}
?
C:静态内部类(嵌套类):(注意:前两种内部类与变量类似,所以可以对照参考变量)
如果你不需要内部类对象与其外围类对象之间有联系,那你可以将内部类声明为static。这通常称为嵌套类(nested class)。想要理解static应用于内部类时的含义,你就必须记住,普通的内部类对象隐含地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时,就不是这样了。嵌套类意味着:
1. 要创建嵌套类的对象,并不需要其外围类的对象。
2. 不能从嵌套类的对象中访问非静态的外围类对象。
?
publicclass Outer {
? ? ? privatestaticinti = 1;
? ? ? privateintj = 10;
? ? ? publicstaticvoidouter_f1() {
? ? ? }
?
? ? ? publicvoidouter_f2() {
? ? ? }
?
? ? ? // 静态内部类可以用public,protected,private修饰
? ? ? // 静态内部类中可以定义静态或者非静态的成员
? ? ? staticclass Inner {
? ? ? ? ? ? ? staticintinner_i = 100;
? ? ? ? ? ? ? intinner_j = 200;
? ? ? ? ? ? ? staticvoidinner_f1() {
? ? ? ? ? ? ? ? ? ? ? //静态内部类只能访问外部类的静态成员(包括静态变量和静态方法)
? ? ? ? ? ? ? ? ? ? System.out.println("Outer.i" + i);
? ? ? ? ? ? ? ? ? ? outer_f1();
? ? ? ? ? ? ? }
?
? ? ? ? ? ? ? voidinner_f2() {
? ? ? ? ? ? ? ? ? ? // 静态内部类不能访问外部类的非静态成员(包括非静态变量和非静态方法)
? ? ? ? ? ? ? ? ? ? // System.out.println("Outer.i"+j);
? ? ? ? ? ? ? ? ? ? // outer_f2();
? ? ? ? ? ? ? }
? ? ? }
?
? ? ? publicvoidouter_f3() {
? ? ? ? ? ? ? // 外部类访问内部类的静态成员:内部类.静态成员
? ? ? ? ? ? ? System.out.println(Inner.inner_i);
? ? ? ? ? ? ? Inner.inner_f1();
? ? ? ? ? ? ? // 外部类访问内部类的非静态成员:实例化内部类即可
? ? ? ? ? ? ? Inner inner = new Inner();
? ? ? ? ? ? ? inner.inner_f2();
? ? ? }
?
? ? ? publicstaticvoid main(String[] args) {
? ? ? ? ? ? ? newOuter().outer_f3();
? ? ? }
}
生成一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。静态内部类的对象可以直接生成:Outer.Inner in = new Outer.Inner();而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类(正常情况下,你不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分,因为它是static 的。只是将嵌套类置于接口的命名空间内,这并不违反接口的规则)
?
D:匿名内部类(from thinking in java 3th)
简单地说:匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
·只用到类的一个实例。
·类在定义后马上用到。
·类非常小(SUN推荐是在4行代码以下)
·给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
·匿名内部类不能有构造方法。
·匿名内部类不能定义任何静态成员、方法和类。
·匿名内部类不能是public,protected,private,static。
·只能创建匿名内部类的一个实例。
·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
?
下面的例子看起来有点奇怪:
//在方法中返回一个匿名内部类
public class Parcel6 {
? ? ? ? public Contents cont() {
? ? ? ? ? ? ? ? return new Contents() {
? ? ? ? ? ? ? ? ? ? private int i = 11;
?
? ? ? ? ? ? ? ? ? ? public int value() {
? ? ? ? ? ? ? ? ? ? ? ? ? ? return i;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }; // 在这里需要一个分号
? ? ? ? }
?
? ? ? ? public static void main(String[] args) {
? ? ? ? ? ? ? ? Parcel6 p = new Parcel6();
? ? ? ? ? ? ? ? Contents c = p.cont();
? ? ? ? }
}
cont()方法将下面两个动作合并在一起:返回值的生成,与表示这个返回值的类的定义!进一步说,这个类是匿名的,它没有名字。更糟的是,看起来是你正要创建一个Contents对象:
return new Contents()
但是,在到达语句结束的分号之前,你却说:“等一等,我想在这里插入一个类的定义”:
return new Contents() {
private int i = 11;
public int value() { return i; }
};
这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象。”通过new 表达式返回的引用被自动向上转型为对Contents的引用。匿名内部类的语法是下面例子的简略形式:
class MyContents implements Contents {
private int i = 11;
public int value() { return i; }
? ? }
return new MyContents();
在这个匿名内部类中,使用了缺省的构造器来生成Contents。下面的代码展示的是,如果你的基类需要一个有参数的构造器,应该怎么办:
public class Parcel7 {
public Wrapping wrap(int x) {
// Base constructor call:
return new Wrapping(x) { // Pass constructor argument.
public int value() {
return super.value() * 47;
? ? ? ? ? ? }
}; // Semicolon required
? ? }
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Wrapping w = p.wrap(10);
? ? }
}
只需简单地传递合适的参数给基类的构造器即可,这里是将x 传进new Wrapping(x)。在匿名内部类末尾的分号,并不是用来标记此内部类结束(C++中是那样)。实际上,它标记的是表达式的结束,只不过这个表达式正巧包含了内部类罢了。因此,这与别的地方使用的分号是一致的。
?
如果在匿名类中定义成员变量,你同样能够对其执行初始化操作:
public class P