引言

内部类,嵌套在另一个类的里面,所以也称为 嵌套类;

内部类分为以下四种:

  • 静态内部类
  • 成员内部类
  • 局部内部类
  • 匿名内部类

一、静态内部类

静态内部类: 一般也称”静态嵌套类“,在类中用static声明的内部类。

因为是static,所以不依赖于外围类对象实例而独立存在,静态内部类的可以访问外围类中的所有静态成员,包括private的静态成员。

同时静态内部类可以说是所有内部类中独立性最高的内部类,其创建对象、继承(实现接口)、扩展子类等使用方式与外围类并没有多大的区别。

public class OuterClass {//外围类

	public int aa; //实例成员
private static float f = 1.5f;//private的静态成员 static void println() {
System.out.println("这是静态方法");
} protected static class StaticInnerClass{//protected的静态内部类 float a; public StaticInnerClass() {
a = f;// 外围类的private静态变量
println();//外围类的静态方法
}
}
} class OtherClass{ public static void main(String[] args) {
//创建静态内部类的对象
OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();
}
}

二、成员内部类

成员内部类: 定义在类的内部,而且与成员方法、成员变量同级,即也是外围类的成员之一,因此 成员内部类 与 外围类 是紧密关联的。

注意:

这种紧密关联指的是,成员内部类的对象的创建必须依赖于外围类的对象(即没有外围类对象,就不可能创建成员内部类)。因此,成员内部类有以下3个特点:

  • 成员内部类可以访问外围类的所有成员,包括私有成员;
  • 成员内部类是不可以声明静态成员(包括静态变量、静态方法、静态成员类、嵌套接口),但有个例外---可以声明 static final的变量, 这是因为编译器对final类型的特殊处理,是直接将值写入字节码;
  • 成员内部类对象都隐式地保存了一个引用,指向创建它的外部类对象;或者说,成员内部类的入口是由外围类的对象保持着(静态内部类的入口,则直接由外围类保持着)

成员内部类中的 this,new关键字:

  • 获取外部类对象:OuterClass.this
  • 明确指定使用外部类的成员(当内部类与外部类的名字冲突时):

    OuterClass.this.成员名
  • 创建内部类对象的new:外围类对象.new
//先创建外围类对象
OuterClass outer=new OuterClass();
//创建成员内部类对象
OuterClass.InnerClass inner=outer.new InnerClass();

1. 成员内部类的对象创建

  我们知道,成员内部类就像外围类的实例成员一样,一定要存在对象才能访问,即成员内部类必须绑定一个外围类的对象。上面已经介绍了成员内部类的创建格式了,我们直接看一个例子

public class OuterClass {//外围类

	public int aa; //实例成员
private static float f = 1.5f;//private的静态成员 public void initInnerClass() {
System.out.println("内部类的初始化方法");
} public void createInnerClass() {//
//外围类的成员方法中创建成员内部类对象
InnerClass innerClass = new InnerClass();
} class InnerClass{//成员内部类
private double aa; //与围类的变量aa的名字重复 public InnerClass(){
this.aa = OuterClass.this.aa + f;//明确指定两个aa的所属
initInnerClass();
}
}
} //其他类
class OtherClass{
public static void main(String[] args) {
//其他类中创建成员内部类
OuterClass oc = new OuterClass();//外部类对象
//创建内部类对象
OuterClass.InnerClass innerClass = oc.new InnerClass();
}
}

  注意上面的例子中,在外围类的成员方法中创建成员内部类 与 在其他类中或静态方法中创建成员内部的方式是不一样的。

补充几点:

  • 成员内部类可以继续包含成员内部类,而且不管一个内部类被嵌套了多少层,它都能透明地访问它的所有外部类所有成员;
  • 成员内部可以继续嵌套多层的成员内部类,但无法嵌套静态内部类;静态内部类则都可以继续嵌套这两种内部类。

下面的例子是基于上面的例子进行改造:

class InnerClass{//成员内部类
private double aa; //与围类的变量aa的名字重复 public InnerClass(){
this.aa = OuterClass.this.aa + f;//明确指定两个aa的所属
initInnerClass();
} public class InnerInnerCalss2{//成员内部类中的成员内部类
protected double aa = OuterClass.this.aa;//最外层的外围类的成员变量
}//InnerInnerCalss2
}//InnerClass

2. 继承成员内部类

在内部类的访问权限允许的情况下,成员内部类也是可以被继承的。由于成员内部类的对象依赖于外围类的对象,或者说,成员内部类的构造器入口由外围类的对象把持着。因此,继承了成员内部类的子类必须要与一个外围类对象关联起来。同时,子类的构造器是必须要调用父类的构造器方法,所以也只能通过父类的外围类对象来调用父类构造器。

下面的例子也是基于上面的例子的,只贴出多出的部分代码。

class ChildClass extends OuterClass.InnerClass{

	//成员内部类的子类的构造器的格式
public ChildClass(OuterClass outerClass) {
outerClass.super();//通过外围类的对象调用父类的构造方法
}
}

三、局部内部类

局部内部类: 就是在方法、构造器、初始化块中声明的类,在结构上类似于一个局部变量。因此局部内部类是不能使用访问修饰符。

局部内部类的两个访问限制:

  • 对于局部变量,局部内部类只能访问final的局部变量。不过,后期JDK(忘了是JDK几了)局部变量可不用final修饰,也可以被局部内部类访问,但你必须时刻记住此局部变量已经是final了,不能再改变。
  • 对于类的全局成员,局部内部类定义在实例环境中(构造器、对象成员方法、实例初始化块),则可以访问外围类的所有成员;但如果内部类定义在静态环境中(静态初始化块、静态方法),则只能访问外围类的静态成员。
public class OuterClass {

	private int a = 21;

	static {//静态域中的局部内部类
class LocalClass1{
// int z = a; //错误,在静态的作用域中无法访问对象成员
}
} {//实例初始化块中的局部内部类
class localClass2{
}
} public OuterClass(){
int x = 2;
final int y = 3;
// x = 3;//若放开此行注释,编译无法通过,因为局部变量x已经是final类型
//构造器中的局部内部类
class localClass3{
int z = y; //可以访问final的局部变量
int b = a;//可以访问类的所有成员
//访问没有用final修饰的局部变量
int c = x;
}
} public void createRunnable() { final int x = 4;
//方法中的局部内部类
class LocalClass4 implements Runnable {//
@Override
public void run() {
System.out.println("局部final变量:"+x);
System.out.println("对象成员变量:"+a);
} }
}
}

四、匿名内部类

匿名内部类: 与局部内部类很相似,只不过匿名内部类是一个没有给定名字的内部类,在创建这个匿名内部类后,便会立即用来创建并返回此内部类的一个对象引用。

作用:匿名内部类用于隐式继承某个类(重写里面的方法或实现抽象方法)或者实现某个接口。

匿名内部类的访问限制: 与局部内部类一样,请参考局部内部类;

匿名内部类的优缺点:

优点: 编码方便快捷;

缺点:

  • 只能继承一个类或实现一个接口,不能再继承其他类或其他接口。
  • 只能用于创建一次对象实例;

下面的例子是我们创建线程时经常用到的匿名内部类的方式来快速地创建一个对象的例子:

 class MyOuterClass {

	private int x = 5;

	void createThread() {

		final int a = 10;
int b = 189; // 匿名内部类继承Thread类,并重写Run方法
Thread thread = new Thread("thread-1") { int c = x; //访问成员变量
int d = a; //final的局部变量
int e = b; //访问没有用final修饰的局部变量 @Override
public void run() {
System.out.println("这是线程thread-1");
}
}; // 匿名内部类实现Runnable接口
Runnable r = new Runnable() { @Override
public void run() {
System.out.println("线程运行中");
}
};
}
}

总结

类 型 访问修饰符 声明静态成员 绑定外围类
静态内部类 四种访问修饰符 可以声明 不绑定
成员内部类 四种访问修饰符 final static 的变量外,其余静态成员都不行 绑定
局部内部类 不可以声明 不可以声明 取决于此内部类的声明环境
匿名内部类 不可以声明 不可以声明 取决于此内部类的声明环境

类与接口(二)java的四种内部类详解的更多相关文章

  1. java的四种内部类详解

    引言 内部类,嵌套在另一个类的里面,所以也称为:嵌套类; 内部类分为以下四种: 静态内部类 成员内部类 局部内部类 匿名内部类 一.静态内部类 静态内部类: 一般也称"静态嵌套类" ...

  2. java四种内部类详解

    一般来说,有4中内部类:常规内部类.静态内部类.局部内部类.匿名内部类. 一.常规内部类:常规内部类没有用static修饰且定义在在外部类类体中.   1.常规内部类中的方法可以直接使用外部类的实例变 ...

  3. Java基础(54):java四种内部类详解(转)

    一般来说,有4中内部类:常规内部类.静态内部类.局部内部类.匿名内部类.  一.常规内部类:常规内部类没有用static修饰且定义在在外部类类体中. 1.常规内部类中的方法可以直接使用外部类的实例变量 ...

  4. Java的四种内部类

    Java的四种内部类包括如下: 成员内部类 静态内部类 局部内部类 匿名内部类 成员内部类: 定义在另一个类(外部类)的内部,而且与成员方法和属性平级叫成员内部类,......相当于外部类的非静态方法 ...

  5. Java的四种内部类(含代码实例)

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  6. Java魔法堂:内部类详解

    一.前言 对于内部类平时编码时使用的场景不多,比较常用的地方应该就是绑定事件处理程序的时候了(从C#.JS转向Java阵营的孩子总不不习惯用匿名内部类来做事件订阅:().本文将结合Bytecode对四 ...

  7. Java解析XML的四种方法详解 - 转载

    XML现在已经成为一种通用的数据交换格式,平台的无关性使得很多场合都需要用到XML.本文将详细介绍用Java解析XML的四种方法 在做一般的XML数据交换过程中,我更乐意传递XML字符串,而不是格式化 ...

  8. Java线程同步的四种方式详解(建议收藏)

    ​ Java线程同步属于Java多线程与并发编程的核心点,需要重点掌握,下面我就来详解Java线程同步的4种主要的实现方式@mikechen 目录 什么是线程同步 线程同步的几种方式 1.使用sync ...

  9. JAVA:23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

随机推荐

  1. JAVA面试精选【Java算法与编程二】

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来.算法是一系列解决问题的清晰指令,也就是说,能够对一定规范的输入,在有限时 ...

  2. koa2 接收post参数

    koa2接收Post参数由于没有在上下文对象上解析,所以需要用node 原生req解析. 获取到的参数,要注意转码问题. const Koa = require('koa'); const app = ...

  3. 安装python-devel开发包

    1.概述 有时在安装某些软件的时候,会报错: Error: must have python development packages -devel, python2.-devel, python2. ...

  4. ASP.NET MVC View中的标签(tag)

    在编辑View的时候会用到各种HTML标签,如<a>,<input>,<p>等待,这些标签在ASP.NET MVC中都有对应的编程语法,它叫Razor,它是帮助我们 ...

  5. ng-app与ng-app='myApp'的区别

    ng-app与ng-app=""是一样的,都是没定义应用名的,例如 <div ng-app="" ng-init="firstName='ech ...

  6. Qt编写自定义控件12-进度仪表盘

    前言 进度仪表盘主要应用场景是标识一个任务进度完成的状况等,可以自由的设置范围值和当前值,为了美观还提供了四种指示器(圆形指示器/指针指示器/圆角指针指示器/三角形指示器),各种颜色都可以设置,其中的 ...

  7. Java面试——你必须知道的122题

    1.Java面向对象中所有类的最终基类是什么? 参考答案 object,所有类都默认最终继承object,object是所有类的基类 2.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语 ...

  8. office web app server部署和简单操作

    部署环境:windows server 2012 R2,服务器在AD域中 参考网址: https://msdn.microsoft.com/zh-cn/magazine/jj219455(office ...

  9. 你得学会并且学得会的Socket编程基础知识

    这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...

  10. Asp.Net WebForm生命周期的详解

    一.Asp.Net页面生命周期的概念 当我们在浏览器地址栏中输入网址,回车查看页面时,这时会向服务器端IIS)发送一个request请求,服务器就会判断发送过来的请求页面,当完全识别 TTP页面处理程 ...