嵌套类的实例化作者王福麟Java程序中的最外层只能是class,enum和interface。
它们不能带有static修饰符,所以对class只有嵌套的类才可以由静态和非静态之说。
在一个类的内部定义的类称为嵌套类(Nested Class),嵌套类可以是静态的或者是非静态的。
按照java的定义,静态嵌套类(Static Nested Class)不是内部类(Inner Class),内部类都是非静态的,内部类包括内部成员类(Inner Class),内部局部类(Local Class)和内部匿名类(Anonymous Class)。
class OuterClass{...static class StaticNestedClass //静态嵌套类{...}class InnerClass //成员内部类,简称内部类{...}void myMethod(){class LocalClass //局部内部类{...}new OuterClass(){ //匿名内部类...};}}匿名类就在它使用的那点实例化了,局部类和内部类的实例化没有太大的差别,只是所在范围不同,都是在外部类的对象里面实例化的。
所以下面我们仅讨论静态嵌套类和内部类。
静态和非静态是说明存储方式的,只要知道java是怎么在内存中放置它们的,就可以对引用及实例化时,它们的差异有所认识了。
java中的内存有一块地址叫静态代码区,所有静态类都是放在这里的,静态类随jvm启动后就在那,不会说程序停止了,它就被垃圾回收器回收,而new 是实例化的命令,它会在java中的内存中的堆区,创建一个对象,注意它们的位置,一个是在静态代码区,一个是在堆区,new出来的对象,一旦程序运行完,它就会被垃圾回收器回收。
在一个类的里面,一个静态嵌套类就像其它的类方法和变量一样,是和它的外部类相联系的。
和一个类的静态方法一样,一个静态嵌套类不能够直接引用定义在外部类里面的实例变量或方法,它只能通过一个类的实例引用。
一个内部类的对象只能存在于它外部类的对象里面,而且可以引用它外部类的成员,包括私有成员。
下面的表格表明嵌套类的类型:一个内部类的实例只能存在于包含它的外部类的实例之中,并且该实例能够对外部类的方法和字段的直接引用。
下图说明这个概念:一个内部类的实例是存在于其外部类的实例之中的实例化一个类要用到关键字new,用它来分配内存,它的使用形式为:new packgename.classname();例如new workplace.demo.myClass();这里要保证new 所在位置能够找到要实例化的类,对于嵌套静态类应该是:new packagename.outerclassname.staticnestedclassname();这里,嵌套类的外部类名称,就像一级包一样。
这也是静态嵌套类的实质所在。
对于内部类来说它们是外部类的实例成分,应该在外部类的对象里,所以应该保证先创建外部类的对象,再在对象内部进行内部类的实例化。
outclassObject.new innerclassname();在new的前面加上一个类的对象名作为定位符,让new到类的对象里面去找构造函数,在对象所在的堆里去分配内存。
这时要建立对象的类一定是该对象的类的内部类。
不然编译会报错的。
下面我们通过例子来说明如何实例化嵌套类,先看看在外部类的内部是如何实例化嵌套类的,这包括从外部类的构造函数,从外部类的方法里,以及从外部类的main()函数:package workplace.demo;public class OuterClass{private int i = 1;private static int j = 2;public OuterClass(){System.out.println("从外部类的构造器实例化嵌套静态类");new StaticNestedClass();System.out.println("从外部类的构造器实例化内部类");new InnerClass();}public static class StaticNestedClass{StaticNestedClass(){System.out.println("静态嵌套类实例化");//System.out.print("i = "+i);错误:无法从静态上下文中引用非静态变量iSystem.out.println("j = "+j);}}public class InnerClass{InnerClass(){System.out.println("内部类实例化");System.out.println("i = "+i+" j = " +j);}}void test(){System.out.println("从内部的方法实例化静态嵌套类");new StaticNestedClass();//这里new前面不能加thisSystem.out.println("从内部方法实例化内部类");this.new InnerClass(); //这里可以加this表示是外部类的对象,因为没有二义性,也可以不加。
这样是可以的}public static void main(String[] args){//实例化静态嵌套类,这里并不需要先实例化外部类StaticNestedClass nestedObject =new StaticNestedClass();//要实例化内部类必须先实例化外部类OuterClass outer=new OuterClass ();// 实例化内部类//InnerClass innerObject=new outer.InnerClass ();//上面这行编译时显示错误: 程序包outer不存在。
//只有改为下面形式:InnerClass innerObject=outer.new InnerClass ();//StaticNestedClass nestedObject =outer.new StaticNestedClass();// 上面一行编译时显示错误: 限定的新静态类outer.test();}}似乎实例化外部类以后应该将实例化内部类InnerClass的语句写成:InnerClass innerObject=new outer.InnerClass ();但上面这行的语句写法出现编译错误: “程序包outer不存在”。
编译程序认为构造函数前面的引用符是包名,构造函数不是类的成员,不同于类的方法。
加在它前面的“outer.”被认为是包名。
但加在静态嵌套类前面的外部类名,按包名处理却是对的,静态嵌套类就和一般的顶层类一样,只是为了包装的方便才被嵌套在一个顶层类的内部的。
外层类名对它就像个包名一样。
前面实例化静态嵌套类的语句写成OuterClass.StaticNestedClass nestedObject =newOuterClass.StaticNestedClass();是一样的只是在可以直接引用而没有必要。
执行结果:静态嵌套类实例化j = 2从外部类的构造器实例化嵌套静态类静态嵌套类实例化j = 2从外部类的构造器实例化内部类内部类实例化i = 1 j = 2内部类实例化i = 1 j = 2从内部的方法实例化静态嵌套类静态嵌套类实例化j = 2从内部方法实例化内部类内部类实例化i = 1 j = 2首先要说明嵌套类的初衷是这些类仅为一个类所使用时,才将它们定义在这个类的内部,这样从包装来看要紧凑多了。
从另外一个类去应用一个类的内部嵌套类的机会并不多。
只是着重从概念上理解,下面再看看从另外一个外部类中是如何实例化一个类的内部嵌套类的。
为了试验我们仅从一个类的main()函数里,是如何实例化一个类的嵌套类。
如果你的内部类是非静态的。
格式也是:Outer.Inner inner=outer.new Inner(); 如果你的内部类是静态的,则语法是Outer.Inner inner=new Outer.Inner();还继续使用上面的例子:package workplace.test;import workplace.demo.OuterClass;public class AnotherClass{public static void main(String[] args){//实例化静态嵌套类OuterClass.StaticNestedClass nestedObject =new workplace.demo.OuterClass.StaticNestedClass() ;//要实例化一个内部类就必须先实例化包含它的外部类OuterClass outer=new OuterClass();//实例化非静态的内部类OuterClass. InnerClass innerObject=outer.new InnerClass();}}执行结果:静态嵌套类实例化j = 2从外部类的构造器实例化嵌套静态类静态嵌套类实例化j = 2从外部类的构造器实例化内部类内部类实例化i = 1 j = 2内部类实例化i = 1 j = 2。