什么是内部类

什么是内部类?

顾名思义,就是将一个类的定义放在另一个类的内部

概念很清楚,感觉很简单,其实关键在于这个内部类放置的位置,可以是一个类的作用域范围、一个方法的或是一个代码块的作用域范围。

所以理解了概念只是第一步,掌握细节才能彻底搞定Java的内部类特性。

看例子,这是最普通的内部类:

  1. public class Product1 {
  2. class Design{
  3. private String name = "P30 pro";
  4. public String showName() {
  5. return name;
  6. }
  7. }
  8. class Content{
  9. private int i;
  10. Content(int value){
  11. i = value;
  12. }
  13. int value() {return i;}
  14. }
  15. public void show(int value) {
  16. Content c = new Content(value);
  17. Design d = new Design();
  18. System.out.println(d.showName());
  19. System.out.println(c.value());
  20. }
  21. public static void main(String[] args) {
  22. Product1 p = new Product1();
  23. p.show(6000);
  24. }
  25. }

说明:

上面这个示例展示了内部类最基础的用法,就是将一个或多个类的定义放在了外围内的内部。可以看到在show()方法中的使用和普通类一样,没有区别。

另外,在外围类的非静态方法之外的任意位置,不能通过直接new 内部类的方式创建内部类对象。会报编译错误。

像这样:



还有这样:



如果想要在外围类非静态方法之外创建内部类对象。怎么办呢?

正确的姿势是这样子:

在外围类中增加两个公共方法,返回内部类的引用。

  1. public Design design() {
  2. return new Design();
  3. }
  4. public Content content(int value) {
  5. return new Content(value);
  6. }

然后通过外部类对象调用方法的方式获取内部类对象。

  1. public static void main(String[] args) {
  2. Product2 p = new Product2();
  3. p.show(6000);
  4. Product2.Content c1 = p.content(100);
  5. Product2.Design d1 = p.design();
  6. }

值得注意的是,外部类之外的其他类,也是不能直接访问到该外部类的内部类对象的。

会报编译错误。这也符合内部类的定义,就是为外围类服务的嘛!

内部类的特性

1.可以链接到外部类

当生成一个内部类对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问外围对象的所有成员,而不需要任何特殊的条件。

下面的例子是《Java编程思想》中的示例

首先定义一个Selector接口

  1. public interface Selector {
  2. boolean end();
  3. Object current();
  4. void next();
  5. }

然后定义一个Sequence类,其中定义有一个private的内部类。

  1. public class Sequence {
  2. private Object[] items;
  3. private int next = 0;
  4. public Sequence(int size) {items = new Object[size];}
  5. public void add(Object x) {
  6. if(next < items.length) {
  7. items[next++] = x;
  8. }
  9. }
  10. private class SequenceSelector implements Selector{
  11. private int i = 0;
  12. public boolean end() {
  13. return i == items.length;
  14. }
  15. public Object current() {
  16. return items[i];
  17. }
  18. public void next() {
  19. if(i < items.length) {i++;}
  20. }
  21. }
  22. public Selector selector() {
  23. return new SequenceSelector();
  24. }
  25. public static void main(String[] args) {
  26. Sequence sequence = new Sequence(10);
  27. for(int i = 0; i < 10; i++) {
  28. sequence.add(Integer.toString(i));
  29. }
  30. Selector selector = sequence.selector();
  31. while(!selector.end()) {
  32. System.out.print(selector.current() + " ");
  33. selector.next();
  34. }
  35. }
  36. }

说明:

可以看到SequenceSelector是一个内部类,其end()、current()和next()都用到了外围类中private的items字段。

2.使用.this和.new

.this的用法

如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this。

如下所示:

  1. public class DotThis {
  2. void name() {System.out.println("name");}
  3. public class Inner{
  4. public DotThis outer() {
  5. return DotThis.this;
  6. }
  7. }
  8. public Inner inner() {return new Inner();}
  9. public static void main(String[] args) {
  10. DotThis dt = new DotThis();
  11. DotThis.Inner inner = dt.inner();
  12. inner.outer().name();
  13. }
  14. }

需要注意DotThis.this只是产生了正确的外部类引用。并没有创建外部类对象。

.new的用法

可以通过该语法创建内部类对象,不过要注意的是要使用外部类的对象去创建。

  1. public class DotNew {
  2. public class Inner{}
  3. public static void main(String[] args) {
  4. DotNew dn = new DotNew();
  5. DotNew.Inner dnInner = dn.new Inner();
  6. }
  7. }

内部类分类

1、局部内部类

定义在一个方法中或是方法中某一作用域内的类。称作局部内部类。

  1. public class Product3 {
  2. public Section section(String inputName) {
  3. class ASection implements Section{
  4. private String name;
  5. private ASection(String name) {
  6. this.name = name;
  7. }
  8. @Override
  9. public String hello() {
  10. return name + " say hello";
  11. }
  12. }
  13. return new ASection(inputName);
  14. }
  15. public static void main(String[] args) {
  16. Product3 p = new Product3();
  17. Section section = p.section("aaaaa");
  18. System.out.println(section.hello());
  19. }
  20. }

ASection是一个Section接口的实现,Section接口代码如下:

  1. public interface Section {
  2. String hello();
  3. }

说明:

  • 该内部类在section()方法中,该方法之外不能访问ASection类;
  • 方法内部类不允许使用访问权限修饰符(public、private、protected);
  • 注意方法返回的是Section 的引用,即有向上转型。

另外还可以将内部类的定义放在方法中某一语句块中,如if语句块中。

  1. public class Product4 {
  2. public String check(boolean flag) {
  3. String checkId = null;
  4. if(flag) {
  5. class DetailCheck{
  6. private String id;
  7. private DetailCheck(String id) {
  8. this.id = id;
  9. }
  10. String getId() {
  11. return id;
  12. }
  13. }
  14. DetailCheck dc = new DetailCheck("1111");
  15. checkId = dc.getId();
  16. }
  17. return checkId;
  18. }
  19. public static void main(String[] args) {
  20. Product4 p = new Product4();
  21. System.out.println(p.check(true));
  22. }
  23. }

说明:

DetailCheck内部类在if语句块中,因此它的作用范围也在if语句块的范围之内。超出该范围是不可用的。比如这样就会编译报错:

2、匿名内部类

匿名内部类其实是一种特殊的方法内部类(局部内部类)。它特殊在于将内部类的定义和其对象创建结合在了一块。没有通过class关键字显示声明内部类名称,故谓之“匿名”。

看代码示例:

  1. public class Product5 {
  2. public Section section() {
  3. return new Section() {
  4. private String name = "hayli";
  5. @Override
  6. public String hello() {
  7. // TODO Auto-generated method stub
  8. return name + " haha";
  9. }
  10. };
  11. }
  12. public static void main(String[] args) {
  13. Product5 p = new Product5();
  14. p.section();
  15. }
  16. }

说明:

此处Section可以是接口,也可是基类。

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

使用static关键字修饰的内部类,叫做静态内部类,也称作嵌套类。

嵌套类和普通内部类之间最大的区别是:

  • 普通内部类对象隐式地保存了一个引用,指向创建它的外部类对象。而嵌套类创建对象,并不需要外部类对象。
  • 不能从嵌套类的对象中访问非静态的外部类对象。
  • 普通内部类不能有static数据和static字段,也不能包含嵌套类,但是嵌套类可以包含所有这些东西。
  1. public class Product6 {
  2. private static int id = 100;
  3. private static class BSection implements Section{
  4. private String name = "bbbb";
  5. @Override
  6. public String hello() {
  7. return name + " hello";
  8. }
  9. // 只能访问外部类的静态数据或字段
  10. public int getId() {return id;}
  11. // 可以包含静态数据或方法
  12. static int x = 200;
  13. public static void test1() {}
  14. // 可以再嵌套一层
  15. static class BInner{
  16. private String name;
  17. static void test1() {System.out.println("inner ===");}
  18. }
  19. }
  20. public static void main(String[] args) {
  21. Section section = new BSection();
  22. section.hello();
  23. }

总结

本篇介绍了什么是内部类、内部类最普通定义方法和Java内部类的几种具体类型详解。虽然工作中使用内部类的机会不会,但是了解这些最基础的知识,真的在项目中遇到内部类的写法,也能看懂是怎么回事了。

扫码关注微信公众号:二营长的笔记。回复“二营长”,可领取Java相关技术资料。

Java内部类超详细总结(含代码示例)的更多相关文章

  1. 超详细的Xcode代码格式化教程,可自定义样式。

    超详细的Xcode代码格式化教程,可自定义样式. 为什么要格式化代码 当团队内有多人开发的时候,每个人写的代码格式都有自己的喜好,也可能会忙着写代码而忽略了格式的问题.在之前,我们可能会写完代码后,再 ...

  2. java 多线程超详细总结——阿里大牛熬夜整理

    引 如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个 ...

  3. Java——HTTP超详细总结

    HTTP协议概述 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的 ...

  4. SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码)

    准备工作 环境准备 JAVA版本 java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121 ...

  5. Java多线程超详细总结

    目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么 ...

  6. Java——Spring超详细总结

    Spring概述 一.简化Java开发 Spring为了降低Java开发的复杂性,采用了以下四种策略 基于POJO的轻量级和最小侵入性编程: 通过依赖注入和面向接口实现松耦合: 基于切面和惯例进行声明 ...

  7. 超详细的Xcode代码格式化教程,可自定义样式

    为什么要格式化代码 当团队内有多人开发的时候,每个人写的代码格式都有自己的喜好,也可能会忙着写代码而忽略了格式的问题. 在之前,我们可能会写完代码后,再一点一点去调格式,很浪费时间. 有了ClangF ...

  8. Java异常超详细总结

    1.1,什么是异常:   异常就是Java程序在运行过程中出现的错误. 骚话: 世界上最真情的相依就是你在try我在catch,无论你发什么脾气,我都静静接受,默默处理(这个可以不记) 1.2,异常继 ...

  9. Java——多线程超详细总结

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 一.线程概述 几乎所 ...

随机推荐

  1. Apicloud 接入海康摄像头

    1准备工作 , 加载apicloud 海康视频模块. 引入 SDK 重新生成项目测试 再config.xml写入appid 话不多说直接上代码 video=api.require("haik ...

  2. 【前端优化】js图片懒加载及优化

    一.前言 为啥要对图片使用懒加载?我们首先来聊聊这个问题,对于页面来说架子啊速度影响着最大的就是图片,一张普通的图片可以达到4-5M的大小,而代码压缩也就只有几十KB.当页面图片过多的时候,页面加载速 ...

  3. vue-cli初始化项目

    vue init webpack cnpm install npm run dev   初始化项目 我们用vue init命令来初始化项目,具体看一下这条命令的使用方法. vue init <t ...

  4. hive 常用的 join 操作 实例

    test_a 表 id value 1 java 2 python 3 c++ test_b 表 id value 1 java 2 go 3 php 4 c++ 1. join 计算的是笛卡尔积,不 ...

  5. kafka入门(三)备份

    一.相关概念 备份相关的角色 Kafka消息备份分三个角色:分别是Leader副本.Follower副本.ISR集合 Leader副本 负责直接响应client端的读写请求,即和生产者和消费者直接对接 ...

  6. POJ 1966:Cable TV Network(最小点割集)***

    http://poj.org/problem?id=1966 题意:给出一个由n个点,m条边组成的无向图.求最少去掉多少点才能使得图中存在两点,它们之间不连通. 思路:将点i拆成a和b,连一条a-&g ...

  7. idea-Java文件结构

    从项目目录来看 ,分级为project-module-package-classname.java 其中.java文件中包含至多一个publicclass.class文件和多个普通.class文件 . ...

  8. Ubuntu系统 apt-get update失败解决办法

    使用apt-get的时候发现ubuntu和阿里云均已经不提供该版本的源,所以需要找到其他的替代源. 使用的ubuntu版本是14.10,属于非LTS(长期支持版本),因此前一段时间还可以使用apt-g ...

  9. Java底层技术系列文章-总揽

    对于工作中经常用到的东西,还是多看看实现原理,这样用着才能放心. 源码思想学习计划: 1.java基础库  HashCode深入理解 java线程框架窥探 2.集合类     java枚举类使用 递归 ...

  10. CDQZ集训DAY7 日记

    并没有考试然而心情比考试还糟糕…… 上午讲的基本就听不懂,讲课人迷之停顿.根本让人跟不上趟,声音好奇怪的说……好不容易讲到反演,Hzoi集体上线,等待装逼时刻的到来.然而,讲课人再次迷之停顿,讲一个p ...