内部类简单来说就是把一个类的定义放到另一个类的定义内部

内部类分为:成员内部类、局部内部类、匿名内部类、静态内部类

成员内部类:最常见的内部类

public class Outter {
private int i = 0;
public static String name = "sam";
public Outter(int i) {
this.i = i;
}
class Inner{
public Inner() {
System.out.println("Inner Class");
}
public void add() {
System.out.println(i + " Name: " + name);
System.out.println("add()");
}
}
}

测试类:

public static void main(String[] args) {
Outter outter = new Outter(1);
Outter.Inner inner = outter.new Inner();
inner.add();
}

结果:

Inner Class
1 Name: sam
add()

成员内部类Inner看起来是外部类Outter的成员,所以以此命名

内部类可以访问外部类的所有属性和方法(包含private和static)

外部类访问内部类一般就是通过上述代码的方式

  当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同

名成员,需要以下面的形式进行访问:this表示当前对象,如果Outter方法为static,不需要this

外部类.this.成员变量
外部类.this.成员方法
public class Outter {
private int i = 0;
public static String name = "sam";
public Outter(int i) {
this.i = i;
}
private static void del() {
System.out.println("Outter del()");
}
class Inner{
private int i = 2;
public Inner() {
System.out.println("Inner Class");
}
private void del() {
System.out.println("Inner del()");
}
public void add() {
del();
Outter.del();
System.out.println("Inner Class: " + i + " Name: " + name);
System.out.println("Outter Class: " + Outter.this.i + " Name: " + name);
System.out.println("add()");
}
}
}

  内部类的修饰符可以是任意的,但是如果为private,只能在外部类的内部进行访问,其他地方不可以。这一点不同和外部类,外部类的修饰符

只能是public和默认,应该是因为此时的内部类相当于外部类的成员,而成员可以是任意的

局部内部类:

定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

为什么要使用局部内部类?

1、实现某个接口,可以创建并返回对其的作用

2、要解决一个复杂的问题,创建一个类来辅助解决,但又不希望这个类是公共可用的

内部类位于方法内:

public interface Destination {
String readLine();
}
public class Outter {
public Destination destination(String s) {
class Inner1 implements Destination {
private String label;
public Inner1(String whereTo) {
this.label = whereTo;
}
@Override
public String readLine() {
return label;
}
}
return new Inner1(s);
} public static void main(String[] args) {
Outter outter = new Outter();
Destination destination = outter.destination("aaa");
} }

Inner属于Destination,而不是Outter的一部分,所以在destination()之外无法访问Inner

也可以位于作用域内,例如if()

PS:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的

PS:在jdk1.8之前这个参数s需要final修饰,否则会编译报错,jdk1.8不需要

匿名内部类:

public class Outter {
public Destination destination() {
return new Destination() { //插入一个类的定义
private int i = 11;
public int value() {
return i;
}
};
} public static void main(String[] args) {
Outter outter = new Outter();
Destination destination = outter.destination();
}
}

在讲接口的时候,曾经说过,接口无法被实例化,直接new只是生成一个匿名内部类而已。

这里产生一个类,这个类是匿名的。创建了一个继承自Destination的匿名类对象,返回的引用自动向上转型为对Destination的引用。

下面是简化形式:

public class Outter {
public Destination destination() {
return new MyDestination();
}
class MyDestination implements Destination {
private int i = 11;
public int value() {
return i;
}
}
}

PS:简化形式有点像成员内部类,但是这里区别就是class要实现一个接口

传递参数:

public class Outter {
public Destination destination(int i1) {
return new Destination() { //插入一个类的定义
private int i = i1;
public int value() {
return i1;
}
};
} public static void main(String[] args) {
Outter outter = new Outter();
Destination destination = outter.destination(2);
}
}

PS:在jdk1.8之前这个参数i1需要final修饰,否则会编译报错,jdk1.8不需要,和局部内部类相同

  唯一一个没有构造器的类,感觉这句话有问题,通过javap查看字节码指令,发现编译器会为匿名内部类生成类名,带有引用的构造函数

  匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类(抽象类)或是实现接口,并不需要增加额外的方法

,只是对继承方法的实现或是重写。

应用:  

Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("run()");
}
};

还有就是添加监听,进行接口回调,这个很常见,例如在rabbitMQ中使用confirm和return机制

//6 添加一个return监听
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.err.println("---------handle return----------");
System.err.println("replyCode: " + replyCode);
System.err.println("replyText: " + replyText);
System.err.println("exchange: " + exchange);
System.err.println("routingKey: " + routingKey);
System.err.println("properties: " + properties);
System.err.println("body: " + new String(body));
}
});
//6 添加一个确认监听
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.err.println("-------no ack!-----------");
} @Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.err.println("-------ack!-----------");
}
});

静态内部类:

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。如果不需要内部类对象和外部类对象有联系,可以使用static

普通内部类:内部类对象隐式地保存一个指向外部类对象的引用

静态内部类:创建对象,不需要依赖外部类对象,不能访问非静态的外部类变量和方法,因为非static依赖对象,而静态内部类又不依赖外部类对象

public class Outter {
private static String s1;
private String s3;
static class Inner {
private static String s = s1;
private String s2 = s3;
public static void add() {
System.out.println("add()");
}
public void del() {
System.out.println("del()");
}
}; public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
inner.del();
Outter.Inner.add();
}
}

结果:

  1、印证里上面所说,静态内部类不能引用外部类非static字段,这里s2 = s3会编译报错

  2、static方法和非static方法调用区别,要访问静态内部类的非static方法,必须通过静态内部类的实例对象去调用

命名规则:

  匿名内部类:Outter$1.class,数字依次递增

  非匿名内部类:Outter$Inner.class

除此之外还包含一个Outter.class

为什么在Java中需要内部类?

1、Java可以多实现,不能多继承,可以通过接口实现多继承,而内部类是多继承另一种实现方案。无论外部类是否继承接口,内部类都可以继承

2、方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏(可以访问外部类的private变量)

3、方便编写事件驱动程序

4、方便编写线程代码

本文参考:Java编程思想,Java内部类详解

很多内容来自海子的这篇博客,算是转载,原文也更加详细,内容更多一点,也加了一点自己的理解

Java基础(五)--内部类的更多相关文章

  1. 面渣逆袭:Java基础五十三问,快来看看有没有你不会的!

    大家好,我是老三, 面渣逆袭 系列继续.这节我们回到梦开始的地方--Java基础,其实过了萌新阶段,面试问基础就问的不多,但是保不齐突然问一下.想一下,总不能张口高并发.闭口分布式,结果什么是面向对象 ...

  2. java基础之 内部类

    Java中的内部类共分为四种: 静态内部类static inner class (also called nested class) 成员内部类member inner class 局部内部类loca ...

  3. Java基础(53):内部类(转)

    java中的内部类总结 内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类 如同一个人是由大脑.肢体.器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行 ...

  4. Java基础五(方法)

    今日内容介绍1.方法基础知识2.方法高级内容3.方法案例 ###01方法的概述 * A: 为什么要有方法 * 提高代码的复用性 * B: 什么是方法 * 完成特定功能的代码块. ###02方法的定义格 ...

  5. Java基础(五) final关键字浅析

    前面在讲解String时提到了final关键字,本文将对final关键字进行解析. static和final是两个我们必须掌握的关键字.不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提 ...

  6. java基础之 内部类 & 嵌套类

    参考文档: 内部类的应用场景 http://blog.csdn.net/hivon/article/details/606312 http://wwty.iteye.com/blog/338628 定 ...

  7. java基础随笔-内部类

    今天来复习下内部类的一些基础知识. 首先是内部类的分类: 1.成员内部类 2.静态内部类 3.匿名内部类 4.局部内部类 下面逐一来介绍下. 首先是成员内部类,就是将内部类作为一个成员变量来处理.具体 ...

  8. Java基础(五)-Java序列化与反序列化

    .output_wrapper pre code { font-family: Consolas, Inconsolata, Courier, monospace; display: block !i ...

  9. java基础(五)-----关键字static

    在Java中并不存在全局变量的概念,但是我们可以通过static来实现一个“伪全局”的概念,在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,当然也可以修饰代码块. ...

随机推荐

  1. java 学习第一步---安装JDK以及配置环境变量

    1.下载jdk 链接:https://pan.baidu.com/s/1FiTGhxdHK0KTFawdkLT26g    提取码:zcy0    我已经在官网上面下载了1.8的jdk,通过百度云盘分 ...

  2. web container和spring container之间的关系

    1 tomcat是一个web container,它提供java web应用的运行环境,因为它实现了好多java ee规范,比如java Servlet.JSP等,也就是说,没有它,java web应 ...

  3. Grunt学习日记

    Grunt和 Grunt 插件是通过npm安装并管理的, npm是Node.js的包管理器. 第一步:先安装node.js环境 第二步:安装Grunt-CLI 在node.js命令工具中输入npm i ...

  4. 【149】ArcGIS Desktop 10.0 & Engine 10.0 安装及破解

    写在前面:可能会出现按照此方法无法破解的情况,那请确保您有将 ArcGIS 10.0 已经完全卸载干净,直接通过控制面板进行卸载的时候并不能将其卸载干净,需要进行更深层次的卸载,包括删除注册表,各种文 ...

  5. Rails5 任务注释

     任务注释  格式  # TODO: ...  # FIXME: ...  # OPTIMIZE ...  查看   rails notes  个别查看  rails notes:todo  rail ...

  6. Python基础 — NumPy

    NumPy--简介  Numpy(Numerical Python的简称)是一个由多维数组对象和用于处理数组的例程集合组成的库.  Numpy内部解除了Python的PIL(全局解释器锁),运算效率极 ...

  7. bzoj 1682: [Usaco2005 Mar]Out of Hay 干草危机【并查集+二分】

    二分答案,把边权小于mid的边的两端点都并起来,看最后是否只剩一个联通块 #include<iostream> #include<cstdio> using namespace ...

  8. 解决phpmyadmin数据文件导入有限制的问题(只能导入2M以下)

    修改配置php.ini文件中三个参数: 1.upload_max_filesize 2.memory_limit 3.post_max_size 建议根据实际需要进行设置.

  9. (博弈论)51NOD 1066 Bash游戏

    有一堆石子共有N个.A B两个人轮流拿,A先拿.每次最少拿1颗,最多拿K颗,拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出N和K,问最后谁能赢得比赛. 例如N = 3 ...

  10. [转]C语言/C++中如何产生随机数

    C语言/C++怎样产生随机数:这里要用到的是rand()函数, srand()函数,和time()函数. 需要说明的是,iostream头文件中就有srand函数的定义,不需要再额外引入stdlib. ...