深入理解Java—内部类

发表于:2014-12-10 10:30

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:牛奶、不加糖    来源:51Testing软件测试网采编

  如果在匿名类中定义成员变量或者使用带参数的构造函数,你同样能够对其执行初始化操作:
public class Parcel8 {
// Argument must be final to use inside
// anonymous inner class:
public Destination dest(final String name, String city) {
return new Destination(name, city) {
private String label = name;
public String getName() {
return label;
}
};
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Destination d = p.dest("Tanzania", "gz");
}
abstract class Destination {
Destination(String name, String city) {
System.out.println(city);
}
abstract String getName();
}
}
  注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final。
  内部类的重载问题
  如果你创建了一个内部类,然后继承其外围类并重新定义此内部类时,会发生什么呢?也就是说,内部类可以被重载吗?这看起来似乎是个很有用的点子,但是“重载”内部类就好像它是外围类的一个方法,其实并不起什么作用:
class Egg {
private Yolk y;
protected class Yolk {
public Yolk() {
System.out.println("Egg.Yolk()");
}
}
public Egg() {
System.out.println("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {
public Yolk() {
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
  输出结果为:
  New Egg()
  Egg.Yolk()
  缺省的构造器是编译器自动生成的,这里是调用基类的缺省构造器。你可能认为既然创建了BigEgg 的对象,那么所使用的应该是被“重载”过的Yolk,但你可以从输出中看到实际情况并不是这样的。
  这个例子说明,当你继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。当然,明确地继承某个内部类也是可以的:
class Egg2 {
protected class Yolk {
public Yolk() {
System.out.println("Egg2.Yolk()");
}
public void f() {
System.out.println("Egg2.Yolk.f()");
}
}
private Yolk y = new Yolk();
public Egg2() {
System.out.println("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() {
System.out.println("BigEgg2.Yolk()");
}
public void f() {
System.out.println("BigEgg2.Yolk.f()");
}
}
public BigEgg2() {
insertYolk(new Yolk());
}
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
}
  输出结果为:
  Egg2.Yolk()
  New Egg2()
  Egg2.Yolk()
  BigEgg2.Yolk()
  BigEgg2.Yolk.f()
  现在BigEgg2.Yolk 通过extends Egg2.Yolk 明确地继承了此内部类,并且重载了其中的方法。Egg2 的insertYolk()方法使得BigEgg2 将它自己的Yolk 对象向上转型,然后传递给引用y。所以当g()调用y.f()时,重载后的新版的f()被执行。第二次调用Egg2.Yolk()是BigEgg2.Yolk 的构造器调用了其基类的构造器。可以看到在调用g()的时候,新版的f()被调用了。
  内部类的继承问题
  因为内部类的构造器要用到其外围类对象的引用,所以在你继承一个内部类的时候,事情变得有点复杂。问题在于,那个“秘密的”外围类对象的引用必须被初始化,而在被继承的类中并不存在要联接的缺省对象。要解决这个问题,需使用专门的语法来明确说清它们之间的关联:
class WithInner {
class Inner {
Inner(){
System.out.println("this is a constructor in WithInner.Inner");
};
}
}
public class InheritInner extends WithInner.Inner {
// ! InheritInner() {} // Won't compile
InheritInner(WithInner wi) {
wi.super();
System.out.println("this is a constructor in InheritInner");
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}
  输出结果为:
  this is a constructor in WithInner.Inner
  this is a constructor in InheritInner
  可以看到,InheritInner 只继承自内部类,而不是外围类。但是当要生成一个构造器时,缺省的构造器并不算好,而且你不能只是传递一个指向外围类对象的引用。此外,你必须在构造器内使用如下语法:
  enclosingClassReference.super();
  这样才提供了必要的引用,然后程序才能编译通过。
  为什么非静态内部类中不能有static修饰的属性,但却可以有常量?
  如:
  public class InnerClassDemo{
  int x;
  class A{
  static  int a = 0;//这样写是不合法的.
  static final int b=0;//这样写是合法的
  }
  }
  定义一个静态的域或者方法,要求在静态环境或者顶层环境,即如果加上 static class A变成静态内部类就ok非静态内部类 依赖于一个外部类对象,而静态域/方法是不依赖与对象——仅与类相关(细说了,就是加载静态域时,根本没有外部类对象)因此,非静态内部类中不能定义静态域/方法,编译过不了。
  而常量之所以可以(不论有无static),因为java在编译期就确定所有常量,放到所谓的常量池当中。常量的机制和普通变量不一样
44/4<1234
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号