Java 内部类

学习自

《Java编程思想》

Overview

什么是内部类?

Thinking In Java 中如此定义: 将一个类的定义放在里另一个类的定义的内部,这就是内部类。

声明一个内部类

package com.company;

public class Parcel {
class Contents {
private int i = 11; public int value() {
return i;
}
} class Destination {
private String label; Destination(String whereTo) {
this.label = whereTo;
} String readLabel() {
return label;
}
} public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
} public static void main(String[] args) {
Parcel p = new Parcel();
p.ship("Tasmania");
}

上面是一个简单的内部的声明,并没有什么特殊的情况,除了将类定义在一类的声明中,这种比较奇怪的写法外。

创建内部类的对象

如果想要确切地指向一个内部类的语法是: OuterClassName.InnerClassName

根据这种个语法我们来创建内部类的对象来试试:

按照这种语法报了编译错误,显然这不是正确的方式,正确的方式如下(在外部类中暴露实例化内部类的方法):



public class Parcel {
class Contents {
private int i = 11; public int value() {
return i;
}
} class Destination {
private String label; Destination(String whereTo) {
this.label = whereTo;
} String readLabel() {
return label;
}
}
//!!注意这里,我们暴露了方法来实例化内部类
public Destination to(String dest) {
return new Destination(dest);
} public Contents contents() {
return new Contents();
} public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
} //实例化内部类
public static void main(String[] args) {
Parcel p = new Parcel();
Parcel.Destination destination = p.to("BeiJing");
}

我们知道了如果正确地实例化内部类,我们也应该知道为什么,直接通过 new 的方式不能实例化内部类:

这是因为,在内部类中是可以引用外部类的成员的(这个稍后会提到),如果直接实例化内部列的话,内部类,是无法访问到外部类的实例成员的,因为外部类还没有实例化。

不过,如果是想直接实例化内部类的话,也不是不可以,在后面我们会讲到那就是 静态内部类

链接到外部类

public class Sequence {
private Object[] items;
private int next = 0; public Sequence(int length) {
items = new Object[length];
} public void add(Object item) {
if (next < items.length) {
items[next++] = item;
}
} public SequenceSelector selector() {
return new SequenceSelector();
} class SequenceSelector {
private int i = 0; public boolean end() {
return i == items.length;
} public Object current() {
return items[i];
} public void next() {
if (i < items.length) {
i++;
}
}
}
} public static void main(String[] args) {
int length = 10; Sequence s = new Sequence(length);
for (int i = 0; i < length; i++) {
s.add(i);
} Sequence.SequenceSelector selector = s.selector();
while (!selector.end()) {
System.out.print(selector.current() + ",");
selector.next();
}
}
//输出结构
//0,1,2,3,4,5,6,7,8,9,

上面我们,我们使用内部类完成了一个简单的迭代器模式的代码,值得注意的是,在 Selector 我们用到了items对象,值得注意的是,此对象并不是Selector本身的,而是Sequence的一个private成员。内部类可以访问器外部类的方法和字段,就像是自身拥有的似的. 通过这一特性,我们在一些特定的情况下,可以完成一些非常优雅的设计,比如说迭代器模式。

为什么内部类可以访问外部类的对象

原因是,当一个外部类的对象,创建了一个内部对象时,内部类会秘密地捕获一个执行外部类的对象的应用。我们不必去关心细节,因为编译器已经帮助我们处理好了,如此一来,为什么不能通过 new 关键字来实例化非__静态内部类__的疑惑也就迎刃而解。

.this 和 .new

.this 关键字

如果在内部类中想要获取对外部类的引用,可以通过 OuterName.this 来获取。


public class Outer {
public void test() { } class Inner {
public void foo() {
//Outer.this 获取外部类的引用
Outer.this.test();
}
}
}

.new 关键字

如果想要实例化一个必须要用外部类的引用才行,所以我们一开始创建内部类的实例的时候是这样创建的

public class Parcel {
class Contents {
private int i = 11; public int value() {
return i;
}
} class Destination {
private String label; Destination(String whereTo) {
this.label = whereTo;
} String readLabel() {
return label;
}
}
//!!注意这里,我们暴露了方法来实例化内部类
public Destination to(String dest) {
return new Destination(dest);
}
}

上面的代码中,我们为了创建内部类的对象,我们不得不写了一个公开的方法,但是这无疑增加了我们的工作量,虽然并不多。现在有一个新的方式来创建内部类的实例---通过 .new 关键字。

Parcel parcel = new Parcel();
Parcel.Destination destination = parcel.new Destination("temp");

方法和作用域中的内部类

在我们想要创建一个类来辅助我们解决一个比较复杂得问题的时候,但是与此同时,又不希望这个类是公共的。

public static void main(String[] args) {
class Person {
private String name;
private String gender;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
} Person person = new Person();
person.setName("LD");
person.setGender("Male");
person.setAge(20);
}

就比如说Person类这个类仅仅能够在main方法中使用,在其他的地方是不能够被访问的。

匿名内部类

因为我主要在做一些Android的开发,在做一些小的Demo或者没有为了实现某些接口仅仅写较短的几句代码,就完全没有必要再新建一个类来解决了,我会使用匿名内部类来解决。

Button openBtn = this.findViewById(R.id.openBtn);
openBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { }
});

嵌套类

上面说到,为了访问外部类的种类,内部类会捕获外部类的引用。当时已经确定内部类不会调用外部类的对象的时候,可以将其声明为 嵌套类 。其有以下特点:

  • 嵌套类并不需要其外围类的对象
  • 不能从嵌套类中访问费静态类型的成员
  • 因为没有对外部类的引用,可以直接通过 new 关键字实例化
public class Parcel {
public static class Destination {
private String label; public Destination(String whereTo) {
label = whereTo;
} public void readLabel() {
System.out.print(label);
}
}
}
//因为Destination是嵌套类所以能够直接被实例化
public static void main(String[] args) {
Parcel.Destination destination = new Parcel.Destination("Beijing");
destination.readLabel();
}

Java 内部类.md的更多相关文章

  1. 简单谈一谈Java内部类的使用原因

    使用内部类的原因 学习总得知其所以然,前面的一篇文章中我有提到过关于java内部类的几种用法以及一些示例,但是不明白内部类具体可以做什么,显然学习起来很渺茫,今天的文章简单说一说使用内部类的几个原因, ...

  2. Java内部类final语义实现

    本文描述在java内部类中,经常会引用外部类的变量信息.但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索.本文从字节码层描述在内部类中是如何实现这些语义的. 本地临时变量 基本类型 fi ...

  3. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  4. 黑马----JAVA内部类

    黑马程序员:Java培训.Android培训.iOS培训..Net培训 黑马程序员--JAVA内部类 一.内部类分为显式内部类和匿名内部类. 二.显式内部类 1.即显式声明的内部类,它有类名. 2.显 ...

  5. java 内部类 *** 最爱那水货

    注: 转载于http://blog.csdn.net/jiangxinyu/article/details/8177326 Java语言允许在类中再定义类,这种在其它类内部定义的类就叫内部类.内部类又 ...

  6. java内部类和匿名内部类

    内部类即是包含在类里面的又一个类. java内部类分为: 成员内部类.静态嵌套类.方法内部类.匿名内部类 . 内部类的共性 (1).内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.clas ...

  7. Java内部类小程序(成员内部类,静态内部类,匿名内部类)

    /** * 测试java内部类(成员内部类,静态内部类,匿名内部类) * 局部内部类不常用,就不写了. * @package :java05 * @author shaobn * @Describe ...

  8. [转] Java内部类详解

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  9. java内部类的作用分析

    提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比.内部类从表面上看,就 ...

随机推荐

  1. 弹指之间 -- Slow Soul

    CHAPTER 16 慢灵魂乐 Slow Soul (8Beat) Slow Soul每小节内几乎都是以8分音符弹奏,又称之为8Beat节奏,80左右的速度最能表现此节奏特色. 示例曲目: 拥抱

  2. tp3 链接生成二维码

    https://packagist.org/packages/endroid/qr-code

  3. saltstack主机管理项目【day23】:主机管理项目需求分析-设计

    本节内容 一. 主机管理项目需求分析 二 .主机管理项目架构设计 三.主机管理项目初始构建 四. 主机管理项目编主机分发器 一. 主机管理项目需求分析 场景:我现在又一台裸机要实现一下人物 配置管理: ...

  4. HDU 4315 阶梯博弈变形

    n个棋子,其中第k个是红色的,每个棋子只能往上爬,而且不能越过.重叠其他棋子,谁将红色棋子移到顶部谁赢. 由于只能往上爬,所以很像阶梯博弈.这题有2个限制,棋子不能重叠,有红棋存在 首先不考虑红色棋, ...

  5. html总结(一)

    一.了解 HTML文档也被称为网页,包含html标签和纯文本,浏览器读取HTML文档,以网页的形式显示出来,而标签决定了所显示网页的格式. 二.要点 常用的HTML文档声明 HTML5 <!DO ...

  6. CSS规范 - 命名规则--(来自网易)

    使用类选择器,放弃ID选择器 ID在一个页面中的唯一性导致了如果以ID为选择器来写CSS,就无法重用. NEC特殊字符:"-"连字符 "-"在本规范中并不表示连 ...

  7. JavaScript执行优先顺序

    js在html中的加载执行顺序 1.加载顺序:引入标记<script />的出现顺序, 页面上的Javascript代码是HTML文档的一部分,所以Javascript在页面装载时执行的顺 ...

  8. PHP 设计模式 单例模式 工厂模式 注册模式

    1.工厂模式,工厂方法或者类生成对象,而不是在代码中直接new 2.单例模式,使某个类的对象仅允许创建一个 3.注册模式,全局共享和交换对象 项目文件目录 入口文件 index.php <?ph ...

  9. UVALive 6467

    题目链接 : http://acm.sdibt.edu.cn/vjudge/contest/view.action?cid=2186#problem/C 题意:对于斐波那契数列,每个数都mod m , ...

  10. lucene查询索引之QueryParser解析查询——(八)

    0.语法介绍: