C# Java 内部类之间的比较
一、引言
严格来说,C#并没有“内部类”这个概念,它应该叫做“嵌套类” (Nested Class)。下面先看一段Cclass Outer
{
void Print()
{
Console.WriteLine("Hello World!");
}
class Inner
{
void Show()
{
Print();
}
}
}
将这一段代码复制到Java中:
class Outer
{
void Print()
{
System.out.println("Hello World!");
}
class Inner
{
void Show()
{
Print();
}
}
}
二、C#中的嵌套类
从上面的例子我们至少可以看出一点:在C#中,类里面定义一个新类,和外部的类是没有任何关系的。虽然Inner类定义在Outer中,但是不能访问Outer中的成员,此时,Outer更加像一个命名空间。我们可以用诸如Outer.Inner i = new Outer.Inner();之类的语句来实例化一个Inner对象。
甚至可以在C#中加入一个嵌套静态类:
class Outer
{
static class Inner
{
public static int i = 0;
public static void Increase()
{
i++;
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
Outer.Inner.Increase();
}
}
因为C#中的嵌套类逻辑如此简单,所以一切都是“理所当然”的,书中不会提及太多。顺便说一下,随着var关键字的引入,C#是支持匿名类的,例如语句var A = new { a = 3 } ;创建了一个匿名类的对象,此对象里有一个Int32成员a,被赋予初值3。
以上的特性,在Java程序中就完全不一样了。
三、Java中的内部类(Enclosing Type)
在第一点的Java代码段中,我们了解到,内部类Inner可以调用外部类的方法,这种行为我们叫做“闭包”(Enclosure),也就是。创建内部类的对象的我是这样理解的:在创建了内部类后,编译器同时还创建了一个“隐藏的引用”(姑且叫它为Outer.this)。在最开始的例子中,我们调用Inner的Print方法时,其实调用的是Outer.this.Print。因为这样的特性,Java中的内部类理解起来会比C#要麻烦。
我们在C#中新建一个嵌套类的对象,可以用以下语句:
Outer.Inner i = new Outer.Inner();
但是,我们不能用这种方式在Java中实例化一个内部类。其原因是,既然内部类中包含了一个外部类的引用,那么我们在创建内部类实例的时候,就必须要指明外部类的实例的。我们用以下特殊的语法:
Outer o = new Outer();
Outer.Inner i = o.new Inner();
首先,我们定义了一个外部类的实例o,然后我们必须要用.new方式来创建内部类的实例:o.new Inner(),并且需要注意的是,不能写成o.new Outer.Inner(),否则编译器会报错。
如果我们需要在内部类中返回外部类的实例,要用[外部类名].this。如上面的两行代码,如果我需要在Inner类中返回外部类实例o,需要写成:
return Outer.this;
你可以在类中嵌套若干层内部类,可以在任意一层调用外部类的成员。若内部类的层次之上存在同名成员,它会返回里内部类最近的那一层的成员。Java对内部类的限制很少,甚至可以在方法体中定义一个内部类。
四、Java中的匿名类
Java中的匿名类和C#中的匿名类不同。Java中的匿名类要以某个类为基类进行扩展。例如以下Java代码段:
class Main
{
class A {}
public A test(){
return new A(){
{ num = 5; }
void run(){}
int num;
int num2 = 3;
};
}
public static void main(String[] args) {}
}
class Main
{
class A {}
public A test(final int i){
return new A(){
int num = i;
};
}
public static void main(String[] args) {}
}
如果把final去掉,将会得到一个编译错误。
上段代码等效为:
class Main
{
class A {}
public A test(final int i){
class TempClass extends A {
int num = i;
}
return new TempClass();
}
public static void main(String[] args) {}
}
五、Java中的嵌套类
有了以上基础,理解Java中的嵌套类(nested class)就很容易了。Java的嵌套类就是C#的嵌套类。Java中定义嵌套类的方法是将内部类声明为static的。无论是C#还是Java,一旦一个类是一个嵌套类,它将无法访问外部类的非静态成员。作为一个Java的内部类,不得包含static成员和方法,但是嵌套类是可以的。