JavaSE-13 内部类
学习要点
- 内部类的定义
- 内部类的应用
内部类
定义
Java的一个类中包含着另一类。

A类和B类是C类的外部类。B类是C类的外部类。A类也称为顶层类。
如何使用内部类
public class MyFatherClass {
}
public interface MyInterface {
public abstract int getValue();
}
public class MyClass extends MyFatherClass implements MyInterface {
int value = 0;
public int getValue() {
return value;
}
public String getValue() {
return "这是一个神奇的时代!";
}
}
以上代码会存在什么问题?编译器提示出错,提示方法重复。即编译器搞不清楚getValue()是继承接口重写的还是重载的。如何解决?使用内部类。
public class MyClass extends MyFatherClass {
int value = 0;
public int getValue() {
return value;
}
public class MyInnerClass implements MyInterface {
public int getValue() {
return 0;
}
}
}
内部类可以访问外部类的所有资源,如果内部类是继承其他类或者接口,不影响外部类的继承和接口实现。轻松实现Java的“多继承”。
例如:
class A{}
class B{}
public class S extends A {
public class E extends B{
}
}
内部类主要作用
- 访问外部类所有成员,包括private成员。
- 多重继承。
- 封装类型。
- 编写事件驱动程序。
- 回调。
内部类的分类

- 内部类主要分为成员内部类、局部内部类。
- 其中,成员内部类根据数据访问权限的不同,又分为静态内部类和非静态内部类。
- 还有一种称为匿名内部类,匿名内部类在程序运行过程中只使用一次,用完即销毁。
- 成员内部类和类的属性、方法、构造方法一样,属于类的成员。而局部内部类或者匿名内部类则不属于类的成员。
- 因此,成员内部类就同其他成员一样,可以采用private、public等修饰,可以被继承。
- 例如:直接把抽象类Person在Demo类中实现了。
abstract class Person {
public abstract void read();
}
public class MyClass {
public static void main(String[] args) {
Person p = new Person() {//匿名内部类
public void read() {
System.out.println("读书!");
}
};
p.read();
}
}
内部类的语法结构
[访问修饰符] 外部类类名{
………
[访问修饰符] 内部类类名{
……
}
……
}
语法示例
/**外部类A*/
public class A {
private String mess = "这是外部类私有成员变量mess";
/**内部类B*/
class B {
public String getMess() {
return mess;
}
}
private B b = new B();//类A的私有成员变量
/**通过外部类访问内部类获取信息方法*/
public void showMess() {
System.out.println(b.getMess());
}
/**测试方法*/
public static void main(String[] args){
A a=new A();
a.showMess();
}
}
直接访问内部类
/**测试方法*/
public static void main(String[] args){
//A a=new A();
//a.showMess();
A.B in=new A().new B();//如果内部类不希望被外部访问,使用private修饰
System.out.println(in.getMess());
}
非静态内部类
定义
非静态内部类不采用static修饰。
特性
内部类和外部类同名成员变量的访问
示例代码:
class Outer {
int number=2000;
public class Inner{
int number=1888;
public int getNum(){
return number;
}
}
}
public class Test{
public static void main(String[] args){
Outer.Inner in = new Outer().new Inner();
System.out.println(in.getNum());
}
}
在测试类中,输出的number值是多少?---1888
当内部类的方法访问同名变量时,采用就近原则,先访问最近的一个成员,如果满足条件,就取最近一个成员变量的值,如果不满足,再依次向外部类寻找同名变量。如果找不到,编译器则报错。
外部类访问内部类成员
需要显示的实例化非静态内部类,通过对象名访问内部类成员。例如语法示例中的代码:
/**外部类A*/
public class A {
private String mess = "这是外部类私有成员变量mess";
/**内部类B*/
class B {
public String getMess() {
return mess;
}
}
private B b = new B();//类A的私有成员变量
/**通过外部类访问内部类获取信息方法*/
public void showMess() {
System.out.println(b.getMess());
}
/**测试方法*/
public static void main(String[] args){
A a=new A();
a.showMess();
}
}
非静态内部类不允许有静态成员:包括静态属性、方法、代码块。
外部类的静态成员不能访问非静态内部类。
静态内部类(嵌套内部类)
定义
静态内部类采用static修饰,他是属于类成员。而非静态内部类则属于类的某个对象。
语法结构
class Outer {
public static class Inner{
}
}
特性
静态内部类不能访问外部非静态成员,只能访问外部类的静态成员,即类成员。
示例代码:
class Outer {
static int number=1000;
public static class Inner{
static void printNumber(){
System.out.println(number);
}
}
}
public class Test{
public static void main(String[] args){
Outer.Inner.printNumber();
}
}
实例化静态内部类,不需要创建外部类引用。
示例代码:
class Outer {
static int number=1000;
public static class Inner{
static void printNumber(){
System.out.println(number);
}
}
}
public class Test{
public static void main(String[] args){
//Outer.Inner in = new Outer().new Inner();
Outer.Inner in = new Outer.Inner();
in.printNumber();
}
}
局部内部类
定义
如果将一个类定义在一个方法内部,则称为局部内部类。和局部变量类似,局部内部类是不允许采用访问修饰符的。(局部变量只允许使用final修饰)。
特性
局部内部类不能在外部类以外的地方使用。局部内部类的作用域只在方法内部,方法外部无法访问局部内部类。
示例代码
class Outer {
int number = 1000;
public void method(){
class LocalInner{
int count=10;
}
LocalInner localInner=new LocalInner();
System.out.println("count="+localInner.count);
}
}
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
局部内部类可以访问外部类的所有资源
局部内部类只能访问所在方法final修饰的局部变量(包括方法的形参)
示例代码:
class Outer {
int number = 1000;
public void method(){
int money=100;//局部内部类无法访问局部变量
final int score=168;//局部内部类可以访问final修饰的局部变量
class LocalInner{
int count=10;
public void printNum(){
System.out.println(number);//局部内部类访问外部类成员
System.out.println(money); //无法访问,报错
System.out.println(score);
}
}
LocalInner localInner=new LocalInner();
System.out.println("count="+localInner.count);
localInner.printNum();
}
}
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
匿名内部类
定义
匿名内部类是一种特殊的内部类,没有名字。
例如:
public class Test {
public static void main(String[] args) {
Test test = new Test(){
};
}
}
在直接“实例化”接口或者抽象类的时候,可以采用匿名类的方式进行实例化。
特性
匿名内部类必须继承一个父类或者实现一个接口。当且仅当只能继承一个父类,或者实现一个接口。
匿名类定义中的示例,匿名类继承了Test类。
创建完匿名类对象,匿名类自动消失。
匿名类本身没有构造方法,但他会调用父类的构造方法。
代码示例:
public class Test {
public Test(){
System.out.println("这是父类Test的构造方法!");
}
public void method(){
System.out.println("这是父类普通方法!");
}
public static void main(String[] args) {
Test test = new Test(){
};
test.method();
}
以上代码将会输出:

匿名类本身没有构造方法,但可以有初始化代码。
代码示例:
public class Test {
public Test(){
System.out.println("这是父类Test的构造方法!");
}
public void method(){
System.out.println("这是父类普通方法!");
}
public static void main(String[] args) {
Test test = new Test(){
{System.out.println("匿名内部类的初始化代码块!");}
};
test.method();
}
}
初始化代码使用{}标识,其初始化的顺序类似继承关系构造方法的执行顺序,输出结果:

成员变量定义成匿名内部类
除了可以在外部类的方法中定义匿名内部类,还可以在成员变量定义匿名内部类。
abstract class AC{}
public class Test {
AC ac = new AC(){};//匿名类成员变量
public static void main(String[] args) {
}
}
封装数据类型
常见的顶层类只能用public或者默认访问修饰符,而成员内部类可以使用任意访问级别的修饰符。
如果一个类仅仅只是为一个方法提供服务,那么这个类就可以定义为方法内的局部内部类,只在该方法内可见。
面向对象核心思想是封装,我们已经学习了属性和方法的封装,内部类也是一种封装方式。
示例代码:
interface Tool{}
public class Outer {
private class InnerTool implements Tool{//实现了工具接口的内部类
}
public Tool getTool(){
return new InnerTool();
}
}
测试类访问不了private修饰的InnerTool内部类,但是可以通过Outer外部类提供的getTool()方法访问获得InnerTool对象。从而实现数据类型的封装,即把Tool类型封装成InnerTool类型。
回调(闭包)
定义
某个方法获得内部类对象的引用后,就可以在合适的时候反过来调用外部类对象的引用。即,允许测试类通过内部类引用来调用其外部类的方法。
示例代码:
/**修改英语成绩接口*/
public interface ReMarkENAble {
/**修改成绩*/
public abstract void modify(int score);
}
/** 修改语文成绩类 */
public class ReMarkCN {
private int scoreCN;//语文成绩
/**修改语文分数*/
public void modify(int scoreCN) {
this.scoreCN = scoreCN;
}
public int getScoreCN(){
return this.scoreCN;
}
}
问题:如果一个学生类既想修改语文成绩又想修改英语成绩要如何实现?定义一个学生类,继承ReMarkCN类,实现ReMarkENAble接口,问题是这两个类中modify方法重名,导致学生类只能实现修改语文成绩的方法。
如何实现学生类既可以修改语文成绩,又可以修改英语成绩?使用内部类回调。
示例代码:
/** 学生类 */
public class Student extends ReMarkCN {
private int scoreEN;//英文成绩
public void outerModify(int scoreEN) {
this.scoreEN = scoreEN;
}
/**闭包:接口+内部类*/
private class Inner implements ReMarkENAble {
@Override
public void modify(int scoreEN) {
outerModify(scoreEN);
}
}
/**获得修改英语成绩内部类对象*/
public ReMarkENAble getReMarkENAble(){
return new Inner();
}
/**打印成绩单*/
public void print(){
System.out.println("*****成绩单*****");
System.out.println("语文成绩:"+this.getScoreCN());
System.out.println("英语成绩:"+this.scoreEN);
}
}
/**测试类*/
public class Test {
public static void main(String[] args) {
Student student=new Student();
//修改语文成绩
student.modify(60);
//修改英语成绩
ReMarkENAble reMarkENAble=student.getReMarkENAble();
reMarkENAble.modify(61);
//输出成绩
student.print();
}
}
JavaSE-13 内部类的更多相关文章
- javase(13)_网络编程
一.概述 1.网络编程的核心是IP.端口(表示应用程序).协议三大元素 2.网络编程的本质是进程间通信 3.网络编程的2个主要问题:1是定位主机,2是数据传输 二.网络通信的概念 1.网络通信协议 计 ...
- JavaSE自学笔记
ch03 [Thu Aug 18 2016 11:22:26 GMT+0800] 对象变量与对象之间是指代关系,对象变量并不能完全说明有无对象可用.这种指代关系是通过赋值运算建立起来的.对象变量保存的 ...
- java学习札记
java学习札记 0x0 学习原因 本来打算大三再去跟着课程去学习java的,但是现在题目越来越偏向java,所以迫于无奈开启了java的学习篇章,同时也正好写个笔记总结下自己学习一门语言的流程. ...
- JAVA(一)JAVA基础/面向对象基础/高级面向对象
成鹏致远 | lcw.cnblog.com |2014-01-23 JAVA基础 1.开发环境搭建 JAVA程序的执行流程 JAVA命令->要使用一个*.class文件(类文件)->通过c ...
- 黑马程序员_java基础笔记(03)...面向对象
—————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流!—————————— 1:面向对象的概念,2 : 类和对象的关系,3 : 封装,4 : 构造函数,5 : ...
- spring-framework-core-ioc Container
阅读须知 实例化bean xml方式实例化bean 注解方式实例化bean java方式实例化bean ClassPathXmlApplication和AnnotationConfigApplicat ...
- 玩好JDK[转]
ref: https://www.cnblogs.com/zuoxiaolong/p/life53.html java-reference:https://docs.oracle.com/en/jav ...
- CMS总结
过程 初始标记 从roots(例如:thread stack引用的对象,static对象),新生代对象,标记直接引用的老年代对象. 并发标记 利用初始标记阶段标记的对象,递归标记整个老年代. 该阶段与 ...
- 为实践javaweb项目,搭建了相应环境
为实践javaweb项目,搭建了相应环境,现总结一下. JDK与JRE的安装与配置 前提准备: 1.我们下载的JDK安装包里面既包含JDK又包含JRE: 2.要确认你的电脑里面没有JDK和JRE的残留 ...
- Java常用的文档地址
https://docs.oracle.com/en/ https://docs.oracle.com/en/java/javase/13/ specifications--->langua ...
随机推荐
- 并不对劲的字符串专题(二):kmp
据说这些并不对劲的内容是<信息学奥赛一本通提高篇>的配套练习. 先感叹一句<信息学奥赛一本通提高篇>上对kmp的解释和matrix67的博客相似度99%(还抄错了),莫非mat ...
- P4844 LJJ爱数数 数论
思路: 化简后得到(a+b)c=ab,设g=(a,b),A=a/g,B=b/g,则g(A+B)c=ABg^2,即(A+B)c=ABg 由题目已知条件:(a,b,c)=1,即(g,c)=1,g|(A+B ...
- Mysql数据库的用户和日志管理
Mysql数据库的用户和日志管理 数据库的用户管理 1.mysql用户账号管理 用户账号 user@host user:账户名称 host:此账户可通过哪些客户端主机请求创建连接线程,可以是ip.主机 ...
- 设计模式-Template Method Pattern
将generic部份放在abstract base class中的实现的方法中,而将和具体context相关的部份作为abstract base class的虚方法,由derivatives去实现. ...
- springMvc中实现拦截器Interceptor以及添加静态资源映射
这个代码写了很久了,多久呢?2018年12-20号写的.... 废话不多说,简化一下,作为笔记. 注: public class springmvcConfig extends WebMvcConfi ...
- 《开源自主OdooERP部署架构指南》试读:第二章数据库服务构建
文/开源智造联合创始人老杨 本文来自<开源自主OdooERP部署架构指南>的试读章节.书籍尚未出版,请勿转载.欢迎您反馈阅读意见. 使用apt.postgresql.org 您可以选择使用 ...
- 【原创】《从0开始学RocketMQ》—集群搭建
用两台服务器,搭建出一个双master双slave.无单点故障的高可用 RocketMQ 集群.此处假设两台服务器的物理 IP 分别为:192.168.50.1.192.168.50.2. 内容目录 ...
- jira以及jira API简单介绍
最近需要预言:是否可以通过jira API实现用例管理,对jira的应用.API.扩展等进行了一定的了解. Jira介绍: jira是目前比较流行的基于Java架构的管理系统(Atlassian公司支 ...
- Hdu 5358 First One (尺取法+枚举)
题目链接: Hdu 5358 First One 题目描述: 数组a有n个元素,S[i,j]定义为a[i]+a[i+1]+.....+a[j],问:这个死东西等于多少? 解题思路: 二分肯定超,这个题 ...
- poj 1511 Invitation Cards spfa 邻接矩阵
题目链接: http://poj.org/problem?id=1511 题目大意: 这道题目比较难理解,我读了好长时间,最后还是在队友的帮助下理解了题意,大意就是,以一为起点,求从一到其他各点的最短 ...