您的位置:首页 > 编程语言 > Java开发

JAVA 学习笔记 第三篇 内部类

2012-03-10 17:17 267 查看
  这一段时间工作一直忙的不可开胶,下载的食品看的比较少,基本上都是在公交车或者睡觉前看看书。上次提到的一本《JAVA语言程序设计》中没有到内部类,现在必须道歉,愿望它了。是在图形界面应用程序中事件驱动的应用程序设计中讲到的。不过总体上来说,也就是很短的一小节。也许是JAVA中内部类规则比较复杂,作者不愿多说,毕竟是一本基础入门书籍。于是我在互联网上找了一些资料,这里记录一下学习成果。

  所谓内部类,就是在一个类的内部再声明一个类类型。

class OuterClass
{
private int outData =0;
public OuterClass(){
System.out.println("创建一个外部类的实例");
}

public void outInstanceMothed(){
System.out.println("外部类的实例方法");
}

public static void  outStaticMothed(){
System.out.println("内部类的静态方法");
}

//声明内部类型
public class InnerClass
{
public InnerClass(){
System.out.println("创建一个内部类的实例");
}

public void innerMothed(){
System.out.printf("内部类的实例方法可以访问外部类的任何可访问级别的成员变量%d",outData);
}
}
}

这样一个包含内部类的JAVA源文件 编译之后 会得到两个class文件:

OuterClass.class  和 OuterClass$InnerClass.class


我反编译了这两个类文件,查看内容是 解决的一些疑惑的同事也带了了一些疑惑(如图所示)。可能是反编译器的问题,类名应该是OuterClass$InnerClass,其中的编码其实是汉字。



解决的疑惑是:1,在外部来的 外部,非静态的内部类的创建为什么一定要绑定外部类,也就是说,必须县创建外部类,然后通过外部类的实例才能创建内部类的实例。

从反编译后的代码 可以看到,内部多了一个 this$0 字段,它是外部类型 的,而且 构造方法中 多出了一个为 this$0赋值的语句,看到这里我们就应该能够推理出 内部类的不少规则了

1.非静态内部类必须 通过外部类的实例来创建,或者通过 内部类的一个实例方法 在外部类内部创建 并返回一个内部非静态类的实例。但是无论如何,必须在外部类的实例上基础上创建内部类。

public class  InnerClassTest
{
public static void main(String[] args)
{
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
OuterClass.InnerClass inner2 = outer.getInnderClass();
}
}


2、内部类可以访问 外部类的 成员变量。这一点也很容易理解了,内部类中的this$0关键则应该是和 this关键字一样的作用,用于方位实例的数据字段的。也就是说 内部类其实是通过 这个thie$0这个成员变量访问外部类的实例成员的。那么是不是这样的,我们来测试一下 下面是完整代码

import java.lang.*;
import java.lang.reflect.*;
public class  InnerClassTest
{
public static void main(String[] args)
{
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
OuterClass.InnerClass inner2 = outer.getInnderClass();
try
{
Class classOfInner = inner2.getClass();
Field[]  fields = classOfInner.getFields();
Field f1 = classOfInner.getDeclaredField("this$0");
System.out.println(f1.getName());
System.out.println(f1.toString()); 这里的输出 与反编译看到的代码一直
System.out.println(f1.getType());
f1.setAccessible(true);
Object value = f1.get(inner2);

OuterClass out = (OuterClass)value;
System.out.println(outer == value); //
}
catch (Exception ex)
{
System.out.println("出错了");
System.out.println(ex.getMessage());
}
}
}

class OuterClass
{
private int outData =0;
public OuterClass(){
System.out.println("创建一个外部类的实例");
}

public void outInstanceMothed(){
System.out.println("外部类的实例方法");
}

public static void  outStaticMothed(){

System.out.println("内部类的静态方法");
}

public  InnerClass getInnderClass()
{
return new InnerClass();
}
//声明内部类型
public class InnerClass
{
private int innerData;
public InnerClass(){
System.out.println("创建一个内部类的实例");
}

public void innerMothed(){
//System.out.print(this$0);
System.out.printf("内部类的实例方法可以访问外部类的任何可访问级别的成员变量%d",outData);
}
}

public static class  InnerStaticClass
{

public static void innerStaticMothed()
{
System.out.println("InnerStaticClass");
}
}
}


以上代码的结果证明了从反编译器中得到的结果。这个有点儿像是javascript中的闭包呵呵。

不过 我也产生了一个疑问,为什么内部类不能声明任何静态成员呢。这个确实是百思古德其解,如果可能问老师吧.

2/静态 的内部类型

静态的内部类型 编译之后 与 非静态的内部类 编译后 生成的文件一样,但是他们有本质的不同,就是体现在 静态内部类型编译后与普通的静态类一样,编译器没有做更多的干涉,没有添加 this$0之类的东西。 起调用方法也不需要 外部类的实例。直接使用 OutClas.InnerClass 就可以了。 也因此,静态内部类只能访问 外部类的 静态成员,不能访问外部类的任何实例成员。

3、生命在方法或者语句块的内部类,则更像是 方法中的局部变量,可以相见,除非 起所在的方法返回 其内部类的实例,否则,不管是在内部类的其它方法或代码块中是无法创建内部类的实例的。

作者:duanmengchao 发表于2012-3-10 17:16:50 原文链接

阅读:8 评论:0 查看评论
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: