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

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

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

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. Codechef Racing Horses题解

    找一个数组中两数之间最小的不同值. 思路: 1 排序 2 后前相减,比較得到最小不同值 三个数甚至很多其它数之间的不同值都是这么求了,时间效率都是O(nlgn) -- 排序使用的时间 原题: http ...

  2. 科普:google的数字图书馆

    https://books.google.com/ngrams Google Ngram Viewer,她利用google所拥有的所有图书作为资源,为你提供单词和短语历年使用次数的展示图标.数据化了数 ...

  3. [办公应用]如何设置IE打印时的默认页边距,并设置纸张为横向(会计票据打印)

    最近一个做会计的同事询问,如何将IE打印时的默认页边距更改,并且每次都要是横向的纸张. 这是因为她已经测试好纸张的大小,并据此调整好了页边距.可惜的是下一次打印时,又要重新调整一遍. 经过研究,方法如 ...

  4. 一起talk C栗子吧(第九十回:C语言实例--使用管道进行进程间通信三)

    各位看官们,大家好,上一回中咱们说的是使用管道进行进程间通信的样例.这一回咱们说的样例是:使用管道进行进程间通信.只是使用管道的方式不同样.闲话休提,言归正转.让我们一起talk C栗子吧! 我们在前 ...

  5. cssTest

    html <!doctype html> <html> <head> <meta charset="utf-8"> <meta ...

  6. Android实战技巧之八:Ubuntu下切换JDK版本【转】

    本文转载自:http://blog.csdn.net/lincyang/article/details/42024565 Android L之后推荐使用JDK7编译程序,这是自然发展规律,就像是4年前 ...

  7. 在mac上安装gradle(超详细,直接按步骤操作即可轻松搞定)

    第一步, 就是先download最新版本的gradle,网址如下: http://gradle.org/gradle-download/ 然后将下载下来的zip包放解压到本地任意的路径上, 例如,我本 ...

  8. [翻译]NUnit--前言(一)

    前言: 翻译这个系列主要是自己在学习NUnit之时看英文文档大部分能看懂但是有些还是功底不足,所以在方便自己以后再学习的时候可以快速查找,也能够加深印象以及掌握的更好.同时在搜索网上关于NUnit系列 ...

  9. luence全文检索(数据库检索)

    注解:从数据库中查询所有数据然后放入luence中,然后在luence来检索 package com.zhu.demo; import java.io.IOException; import java ...

  10. 【bug】Android版QQ浏览器广告过滤

    省流加速 - 广告过滤   默认开启 设别广告是添加的标签最外层标签带有adv download