Java中的嵌套类、内部类、静态内部类

在Java中我们在一个类的内部再定义一个类,如下所示:

class OuterClass {
    ...
    class NestedClass {
        ...
    }
}

那么在上面的例子中我们称OuterClass为外围类(enclosing class),里面的那个类称之为嵌套类(Nested Class).

嵌套类可以分为两种,静态的和非静态的,即静态嵌套类和非静态嵌套类。非静态嵌套类又叫做内部类(Inner Class)。我们通常所说的静态内部类其实是不严格的,严格的说应该叫做静态嵌套类(Static Nested Class)。

class OuterClass {
    ...
    class InnerClass {
        ...
    }

    static class StaticNestedClass {
        ...
    }
}

上述代码中的InnerClass就是内部类,StaticNestedClass就是静态嵌套类。

内部类与静态嵌套类虽然都是嵌套类,但在使用上是有一些区别的。

内部类

比如有如下内部类的定义,

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

OuterClass是InnerClass的外围类,InnerClass是OuterClass的内部类。内部类的实例对象都会绑定一个外围类的实例对象,并且InnerClass可以访问其所绑定的OuterClass的所有成员属性以及方法,包括私有成员属性以及方法。在InnerClass中通过OuterClass.this显式的引用其所绑定的OuterClass的实例。要实例化内部类InnerClass,必须首先实例化其外围类OuterClass,然后用如下的语法创建内部类的实例:

OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

注意,上面写得是outerObject.new InnerClass(),而不是new OuterClass.InnerClass();

我们在执行代码OuterClass.InnerClass innerObject = outerObject.new InnerClass()的时候,其实做了两件事,一件事是创建一个内部类的实例innerObject,第二件事是让innerObject绑定outerObject作为其外围类的实例。这样innerObject就可以访问outerObject内的所有成员属性以及方法了。

那如果想直接跳过外围类去初始化内部类会怎么样呢?代码如下所示:

如果执行代码InnerClass innerObject = new InnerClass(),会出现如下的编译错误:

No enclosing instance of type OuterClass is accessible. Must qualify the allocation with an enclosing instance of type OuterClass (e.g. x.new A() where x is an instance of OuterClass).

编译器给出的错误提示很明确,就是我们没有外围类OuterClass的实例就去初始化内部类了。要写成x.new InnerClass()的形式,其中x是外围类OuterClass的一个实例对象。

静态嵌套类

有些人把静态嵌套类成为静态内部类,其实静态内部类这个称呼不严谨,因为内部类都是非静态的。静态嵌套类与内部类有很大的不同,静态嵌套类说到底就是一个静态类,只不过是其位置位于某个类的内部罢了。

假设有如下静态嵌套类的定义:

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
}

那么我可以像正常使用一个一般的静态类那样使用一个静态嵌套类,只不过要通过其外围类的名字来访问静态嵌套类的名字。所以,外围类更像是静态嵌套类的命名空间。比如要获取静态嵌套类,要使用OuterClass.StaticNestedClass。

如果要创建静态嵌套类的实力对象,使用如下的语法:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

由于静态嵌套类的本质就是一个静态类,所以其实例对象的初始化不需要也不能像内部类那样需要绑定一个外围类对象。由于静态嵌套类没有像内部类那样绑定外部类对象,所以也就不存在静态嵌套类不能访问其外围类的成员这种说法。

如果我们像初始化内部类那样初始化静态嵌套类,也就是在创建静态嵌套类的时候给其绑定其外围类的实例对象,会怎么样呢?代码如下所示:

可以发现,如果我们在初始化静态嵌套类时强行给其绑定外围类的实例对象,编译器就会报错:

Illegal enclosing instance specification for type OuterClass.StaticNestedClass

我们给静态嵌套类OuterClass.StaticNestedClass指定了非法的外围类的实例。

综上所述,虽然内部类和静态嵌套类都属于嵌套类,但是二者有本质区别:内部类的实例化对象需要绑定一个外围类的实例化对象,而静态嵌套类的实例化对象不能也无法绑定外围类的实例化对象。

时间: 2024-10-21 07:09:29

Java中的嵌套类、内部类、静态内部类的相关文章

Java中的嵌套类和内部类

以前看<Java编程思想>的时候,看到过嵌套类跟内部类的区别,不过后来就把它们的概念给忘了吧.昨天在看<数据结构与算法分析(Java语言版)>的时候,又遇到了这个概念,当时就很大的疑惑:嵌套类跟内部类有什么区别?只有是否有关键字static的区别吗? 所以今天找了个时间查了一下两者的详细区别,总结在这篇博客中,既方便自己的复习和学习,也启示他人吧. 1,概念: 定义在一个类内部的类,叫作"嵌套类".嵌套类分为两种:static的和非static的.后者又有一个专

Java中为什么要使用内部类

一.前言 关于Java的内部类,要说的东西实在太多,这篇博文中也无法一一具体说到,所以就挑些重点的讲.关于内部类的使用,你可能会疑问,为什么我们要使用内部类?为了回答这个问题,你需要知道一些关于内部类的重点.所以本篇文章首先介绍了一些关于内部类的一些与众不同的地方,后面再解答为什么我们要使用内部类这个问题.各位看官,文章稍微有点长,深吸一口气.来,我们开始吧! 二.内部类定义 内部类定义非常简单,就是把一个类的定义放在另外一个外围类定义的里面.如下面代码所示: class OutterClass

java中的 FileWriter类 和 FileReader类

java中的 FileWriter类 和 FileReader类的一些基本用法 1,FileWriter类(字符输出流类) 构造方法:FileWriter fw = new FileWriter(String fileName);//创建字符输出流类对象和已存在的文件相关联.文件不存在的话,并创建. 如:FileWriter fw = new FileWriter("C:\\demo.txt"); FileWriter fw = new FileWriter(String fileNa

使用myeclipse开发java,解决java中继承JFrame类出现The type JFrame is not accessible due to restriction的问题

在java中创建窗体,导入了java中的JFrame类,之后会出现错误: Access restriction: The type QName is not accessible due to restriction on required library D:\myeclipse professer2014 可以解决的办法为: Project—>Properties—>选中Java Build Path—>选择Libraries,出现下面界面: 选中窗口中原有的JRE库,点击Remov

C++ 中的嵌套类和局部类

C++ 中的嵌套类和局部类 最近趁着春节假期空闲,找了本C++ Primer 学了几章,发现C++ 中的许多特性自己都不知道.其中嵌套类和局部类感觉还是蛮有用的,简单的写写他们的用法. 嵌套类 所谓嵌套类就是可以在一个类中定义另一个类.这个被嵌套的类的作用域就只在它的上一级类中.下面是个例子: #include <iostream> using namespace std; class c1 { public: int a; void foo(); class c2 { public: int

java中的File类

File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真正操作,还得需要I/O流的实现. 1.目录列表 如果我们想查看某个目录下有那些文件和目录,我们可以使用File中提供的list方式来查看,这很像linux下的ls命令. 查看E:/html文件夹下所有的php文件,执行的时候输入的参数为正则表达式 1 package com.dy.xidian; 2

java 中的String类

String a = "aaa"; 用这种方式的时候java首先在内存中寻找"aaa"字符串,如果有,就把aaa的地址给它 如果没有则创建 String a = new String("aaa"); 是不管内存中有没有"aaa" 都开辟一块新内存保存它 可以用以下方法验证下 String a = "aaa"; String b = "aaa"; String c = new String

Java中的Object类

关于Object类的equals()方法的特点: 1) 自反性:对于非空引用x来说,x.equals(x)一定返回true: 2) 对称性:对于非空引用x和y来说,如果x.equals(y)返回true,那么y.equals(x)一定返回true: 3) 传递性:对于非空引用x.y和z来说,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)一定返回true: 4) 一致性:对于非空引用x和y来说,如果x.equals(y)返回true,那么

【Java】Java中的Collections类——Java中升级版的数据结构【转】

一般来说课本上的数据结构包括数组.单链表.堆栈.树.图.我这里所指的数据结构,是一个怎么表示一个对象的问题,有时候,单单一个变量声明不堪大用,比如int,String,double甚至一维数组.二维数组无法完全表达你要表达的东西,而定义一个类Class有太过麻烦,这时候,你可以考虑一下用Java中的Collections类.使用Collections类,必须在文件头声明import java.util.*;   一.动态.有序.可变大小的一维数组Vector与ArrayList Collecti