编写java程序时,一般一个类(或者接口)都是放在一个独立的java文件中,并且类名同文件名(如果类是public的,类名必须与文件名一致;非public得,无强制要求)。如果想把多个java类放在一个java文件中,则只能有一个public类。如下面的两个类放在同一个文件中就会报错,无法编译通过。

可以看出,因为TestOne.java文件中已经有一个public类TestOne,这时再加了一个public类TestTwo就报错了。如果将类TestTwo前面的public修饰符去掉就没有问题了。

我们下面介绍内部类的概念和使用,所谓内部类,简单的说,就是一个类定义在另一个类的内部。与上面的两个类在同一个文件中不同(TestOne和TestTwo虽然在一个文件中,但相互没有嵌套,是并列的)。

采用内部类,有时会对代码的可读性带来一点问题,但很多场景下还是很有必要的。尤其在使用一些框架(如java的swing,集合框架中的排序操作)等,使用内部类(尤其是匿名内部类)会带来很多便利;再比如我们在开发Android app时,就会大量的使用内部类,如果不了解内部类的含义和使用规则,几乎无法顺利的进行Android app的开发。

内部类有其特别的地方,其中核心之一是,内部类实例可以访问包含它的外部类的所有成员,包括private成员。另外非常关键的一点是,内部类的使用必须与一个外部类的实例绑定,注意是实例,后面的例子中会说明这点。

内部类也分好几种情况,下面一一来解释。

一、一般内部类

例1:TestTwo就是一个内部类,它可以直接访问外部类中的私有成员a。

public class TestOne {

	private int a = 2;

	public static void main(String[] args) {
new TestOne().call();
} public void call(){
TestTwo two = new TestTwo();
two.show();
} class TestTwo {
public void show(){
System.out.println(a);
}
}
}

 例2:如果需要在外部类的静态方法中使用内部类,必须创建一个外部类的实例,通过该实例来new内部类。不能直接new,否则会报编译错误。

public class TestOne {

	private int a = 2;

	public static void main(String[] args) {
TestOne testOne = new TestOne();
TestTwo testTwo = testOne.new TestTwo();
testTwo.show();
} public void call(){
TestTwo two = new TestTwo();
two.show();
} class TestTwo {
public void show(){
System.out.println(a);
}
}
}

 例3:如何在内部类中引用外部类的实例。有两种方法,一是普通的方法,在new内部类时,将外部类的this作为内部类的构造函数参数传给内部类;还有一种更简单的方法,直接在内部类中通过 "外部类类名.this" 就可以使用外部类的实例。如下面代码:

public class TestOne {

	private int a = 2;

	public static void main(String[] args) {
new TestOne().call();
} public void call(){
new TestTwo(this).show();
} class TestTwo {
private TestOne one; public TestTwo(TestOne one){
this.one = one;
}
public void show(){
System.out.println(a);
System.out.println(one.a);
System.out.println(TestOne.this.a);
}
}
}

上述情况下使用内部类,通常该内部类只是被该外部类使用,这样可以对内部类起到隐藏作用,并且跟外部类绑定的更紧密。

二、方法内的内部类

就是内部类定义在一个方法的内部。这种情况下,只有在该方法内才能使用该内部类;内部类也可以访问外部类的成员;但注意不能访问包含它的方法的局部变量(包括参数),除非方法内的变量(或参数)是final的。 举例:

public class TestOne {
private int a = 2; public static void main(String[] args) {
new TestOne().call();
} public void call(){
final int b=3;
class TestTwo {
private TestOne one; public TestTwo(TestOne one){
this.one = one;
}
public void show(){
System.out.println(a);
System.out.println(one.a);
System.out.println(TestOne.this.a);
System.out.println(b);
}
}
new TestTwo(this).show();
}
}

  需要注意的是,如果是在静态方法中定义内部类,则该内部类只能使用外部类的静态成员。

三、匿名内部类

匿名内部类,其实也分很多情况。最常见的情况是,直接通过父类(比如抽象类)创建子类的实例,或直接通过接口创建对象,该对象可传递作为方法的参数,或者赋值给某个变量。实际上在内部类的使用中,匿名类是用途最广泛的。

因为我们都知道,在java中,一般情况下,不像c/c++一样,我们可以把一个方法作为一个变量进行传递或引用。

我们只能传递和引用java对象。比如我们定义了一个方法,有个参数是接口类型或抽象类,这样不使用匿名内部类,我们每次都需要先定义一个类实现该接口或抽象类,再创建该类的实例传递给该方法。当接口或抽象类中需要实现的方法数量比较少时(比如只有1个),这个先创建类,再使用就显的比较啰嗦了。而且这种场景下,往往创建的类就这一个地方使用。而通过匿名内部类,就可以让编写的代码简洁很多。 实际上,java本身提供的一些api(如多线程、io、集合框架等)就大量的使用了这个特性。 我们来看几个例子:

例1:通过接口创建对象

public class TestThread {
public static void main(String[] args) {
TestThread testThread = new TestThread();
testThread.fun1();
testThread.fun2();
}
public void fun1(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("fun1");
}
};
new Thread(runnable).start();
} public void fun2(){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("fun2");
}
}).start();
}
}

可以看出,方法fun1中直接通过Runnable接口创建了对象,供Thread类使用。fun2更简化了下,直接连变量名也省掉了,对象的创建直接在传入参数时创建。

例2:直接创建父类的子类对象

public class TestChild {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
System.out.println("thread is run");
}
}.start(); }
}

  可以看出,Thread类有一个run方法,但这个run方法是空的,我们如果要用继承Thread类来实现多线程,必须在子类中重载run方法。上面的代码我们实际上没有显示的定义一个Thread的子类,而是直接通过上述形式创建了一个线程实例,并启动它。

四、静态嵌套类(内部类)

也就是在一个类中定义一个静态类(注意不能在方法中定义)。 与前面介绍的内部类不同。这个嵌套类只是命名空间限制在外部类中。实质上它不需要与外部类的实例绑定,也无法访问外部类的实例成员,只能访问外部类的静态成员。代码如:

public class TestOne {
private int a = 2;
static private int b = 2; public static void main(String[] args) {
TestTwo testTwo = new TestTwo();
} public void call(){
TestTwo testTwo = new TestTwo();
} static class TestTwo {
public void show(){
System.out.println(b);
}
}
} class TestThree{
public static void main(String[] args) {
TestOne.TestTwo testTwo = new TestOne.TestTwo();
} public void call(){
TestOne.TestTwo testTwo = new TestOne.TestTwo();
}
}

可以看出,TestTwo的使用不需要依赖外部类TestOne的实例。

上面介绍了内部类的几种情况,使用的时候稍加注意即可。  

Java学习笔记:内部类/匿名内部类的全面介绍的更多相关文章

  1. Java学习笔记-内部类

    内部类在Android中有着大量的运用 内部类 内部类提供了更好的封装:内部类可以直接访问外部类的私有数据:匿名内部类适合那些只需要使用一次的类.非静态内部类不能拥有静态成员.内部类比外部类可以多使用 ...

  2. 2)Java学习笔记:匿名内部类

    为什么要使用匿名内部类 ①如果以前的类有一些缺陷,只是想在某一个模块进行修复,可以在引用该类的地方使用匿名内部类,在overRide方法进行修复. ②如果一个类,需要派生出很多类,而且这些类大多只是在 ...

  3. Java学习笔记——内部类及其调用方法

    一.static内部类的static方法 public class Test0719_Inner_Test { public static void main(String[] args) { //s ...

  4. 【Java学习笔记之二十六】深入理解Java匿名内部类

    在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意 ...

  5. Java学习笔记之---内部类

    Java学习笔记之---内部类 (一)成员内部类 内部类在外部使用时,无法直接实例化,需要借助外部类信息才能实例化 内部类的访问修饰符可以任意,但是访问范围会受到影响 内部类可以直接访问外部类的成员, ...

  6. java学习笔记(1)java的基础介绍 、JDK下载、配置环境变量、运行java程序

    java工程师是开发软件的 什么是软件呢? 计算机包括两部分: 硬件: 鼠标.键盘.显示器.主机箱内部的cpu.内存条.硬盘等 软件: 软件包括:系统软件和应用软件 系统软件:直接和硬件交互的软件:w ...

  7. 0028 Java学习笔记-面向对象-Lambda表达式

    匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...

  8. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  9. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

  10. java学习笔记9--内部类总结

    java学习笔记系列: java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对 ...

随机推荐

  1. jQuery validate和form插件配套使用

    参考 官网http://jqueryvalidation.org/documentation/ 博客http://www.cnblogs.com/buzzlight/archive/2010/06/3 ...

  2. sed(查找替换) 与awk(提取字段)

    通常: sed 处理列  awk处理行 比较方便 Sed是一个基本的查找替换程序     sed -i   "s/^@//g"     文件  #原地操作原文件,进行替换 cat ...

  3. 参照openRTSP写的一个RTSP client 加了一些注解

    #include "liveMedia.hh"  #include "BasicUsageEnvironment.hh"  #include "Gro ...

  4. ActionScript3游戏中的图像编程(连载十七)

    总文件夹:http://blog.csdn.net/iloveas2014/article/details/38304477 1.3.3 HSB与RGB之间的互转公式及HSL和HSV对色彩属性理解的异 ...

  5. 集团财务分析BI项目中的财务系统环境

    我国集团化经营模式起步较晚,集团管控模式及管控力度各异,集团范围内财务信息化水平及统一程度不尽相同,因此在实施集团财务分析一类的BI商业智能项目的过程中,在不同的集团之间遇到的财务系统及核算数据环境也 ...

  6. SQL Server(SSIS package) call .net DLL

    There are two method to call .net DLL in SQLSERVER. The first one is to use the sql clr but it has a ...

  7. MBProgressHUD简单使用

    使用HUD最多的情形用于请求等待提示 例如做登录的时候在确认登陆的时候可以用HUD提示正在登陆. 最基本的使用 初始化 //self.view代表在哪个view中显示hud MBProgressHUD ...

  8. Dojo实现Tabs页报错(三)

    用Dojo实现tab页的过程中,没有引用“on.js”,但是firebug调试时一直提示如下错误: on.js源码如下: define(["./has!dom-addeventlistene ...

  9. Python Extension Packages下载链接

    一.http://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载后可使用pip包管理器进行安装,在命令行中输入: pip install 安装包的路径

  10. php 自己写的好看的分页类

    自己写的一个分页类 ,不是很完整,个别没有做验证,但可以使用,分页效果见文章底部.除了链接数据库的代码没有粘贴上来,其他的都粘贴了.供学习使用- <?php /** * Created by P ...