-
什么是内部类
-
内部类的分类和作用
-
内部类如何定义
-
如何实例化以及各自的特点
-
要注意区分不同类型内部类的异同
-
为什么需要内部类
在 Java 语言中,可以将一个类定义在另一个类里面或者一个方法里面,我们把这样的类称为内部类。
与之对应的,包含内部类的类被称为外部类。请阅读下面的代码:
// 外部类 Car
public class Car {
// 内部类 Engine
class Engine {
private String innerName = “发动机内部类”;
}
}
代码中,Engine
就是内部类,而 Sky
就是外部类。
Java 中的内部类可以分为 4 种:
成员内部类
静态内部类
方法内部
匿名内部类
2.1 成员内部类
2.1.1 定义
成员内部类也称为普通内部类,它是最常见的内部类。可以将其看作外部类的一个成员。在成员内部类中无法声明静态成员。
如下代码中声明了一个成员内部类:
// 外部类 Car
public class Car {
// 内部类 Engine
private class Engine {
private void run() {
System.out.println(“发动机启动了!”);
}
}
}
我们在外部类 Sky
的内部定义了一个成员内部类 Engine
,在 Engine
下面有一个 fly()
方法,其功能是打印输出一行字符串:“发动机启动了!”。
另外,需要注意的是,与普通的 Java 类不同,含有内部类的类被编译器编译后,会生成两个独立的字节码文件:
Car$Engine.class
Car.class
内部类 Engine
会另外生成一个字节码文件,其文件名为:外部类类名 $ 内部类类名.class。
2.1.2 实例化
内部类在外部使用时,无法直接实例化,需要借助外部类才能完成实例化操作。关于成员内部类的实例化,有 3 种方法:
- 我们可以通过
new 外部类().new 内部类()
的方式获取内部类的实例对象:
实例演示
// 外部类 Car
public class Car {
// 内部类 Engine
private class Engine {
private void run() {
System.out.println(“发动机启动了!”);
}
}
public static void main(String[] args) {
// 1.实例化外部类后紧接着实例化内部类
Engine engine = new Car().new Engine();
// 2.调用内部类的方法
engine.run();
}
}
运行结果:
发动机启动了!
- 我们可通过先实例化外部类、再实例化内部类的方法获取内部类的对象实例:
public static void main(String[] args) {
// 1.实例化外部类
Car car = new Car();
// 2.通过外部类实例对象再实例化内部类
Engine engine = car.new Engine();
// 3.调用内部类的方法
engine.run();
}
编译执行,成功调用了内部类的 fly () 方法:
$javac Car.java
java Car
发动机启动了!
- 我们也可以在外部类中定义一个获取内部类的方法
getEngine()
,然后通过外部类的实例对象调用这个方法来获取内部类的实例:
实例演示
package com.caq.oop.demo10;
public class Outer {
private int id = 10;
public void out(){
System.out.println(“这是外部类的方法”);
}
//一个java类中可以有多个class类,但只能有一个public class
public class In {
public void in() {
System.out.println(“这是内部类的方法”);
}
}
public static void main(String[] args) {
//实例化内部类,调用内部类的方法
In In = new Outer().new In();
In.in();
}
}
运行结果:
这是内部类的方法
这种设计在是非常常见的,同样可以成功调用执行 fly()
方法。
2.1.2 成员的访问
成员内部类可以直接访问外部类的成员,例如,可以在内部类的中访问外部类的成员属性:
实例演示
// 外部类 Sky
public class Sky {
String name;
public Engine getEngine() {
return new Engine();
}
// 内部类 Engine
private class Engine {
// 发动机的起动方法
private void fly() {
System.out.println(name + “的发动机启动了!”);
}
}
public static void main(String[] args) {
// 实例化外部类
Sky Sky = new Sky();
// 为实例属性赋值
Sky.name = “张三”;
// 获取内部类实例
Engine engine = Sky.getEngine();
// 调用内部类的方法
engine.fly();
}
}
观察 Engine
的 fly()
方法,调用了外部类的成员属性 name
,我们在主方法实例化 Sky
后,已经为属性 name
赋值。
运行结果:
大奔奔的发动机启动了!
相同的,除了成员属性,成员方法也可以自由访问。这里不再赘述。
还存在一个同名成员的问题:如果内部类中也存在一个同名成员,那么优先访问内部类的成员。可理解为就近原则。
这种情况下如果依然希望访问外部类的属性,可以使用外部类名.this.成员
的方式,例如:
实例演示
// 外部类 Sky
public class Sky {
String name;
public Engine getEngine() {
return new Engine();
}
// 汽车的跑动方法
public void fly(String name) {
System.out.println(name + “跑起来了!”);
}
// 内部类 Engine
private class Engine {
private String name = “引擎”;
// 发动机的起动方法
private void fly() {
System.out.println(“Engine中的成员属性name=” + name);
System.out.println(Sky.this.name + “的发动机启动了!”);
Sky.this.fly(Sky.this.name);
}
}
public static void main(String[] args) {
// 实例化外部类
Sky Sky = new Sky();
// 为实例属性赋值
Sky.name = “张三”;
// 获取内部类实例
Engine engine = Sky.getEngine();
// 调用内部类的方法
engine.fly();
}
}
运行结果:
Engine中的成员属性name=引擎
张三的发动机启动了!
大奔奔跑起来了!
请观察内部类 fly()
方法中的语句:第一行语句调用了内部类自己的属性 name
,而第二行调用了外部类 Sky
的属性 name
,第三行调用了外部类的方法 fly()
,并将外部类的属性 name
作为方法的参数。
2.2 静态内部类
2.2.1 定义
静态内部类也称为嵌套类,是使用 static
关键字修饰的内部类。如下代码中定义了一个静态内部类:
public class Car1 {
// 静态内部类
static class Engine {
public void run() {
System.out.println(“我是静态内部类的run()方法”);
System.out.println(“发动机启动了”);
}
}
}
2.2.2 实例化
静态内部类的实例化,可以不依赖外部类的对象直接创建。我们在主方法中可以这样写:
// 直接创建静态内部类对象
Engine engine = new Engine();
// 调用对象下run()方法
engine.run();
运行结果:
我是静态内部类的run()方法
发动机启动
2.2.2 成员的访问
在静态内部类中,只能直接访问外部类的静态成员。例如:
实例演示
public class Sky1 {
String brand = “宝马”;
static String name = “外部类的静态属性name”;
// 静态内部类
static class Engine {
public void fly() {
System.out.println(name);
}
}
public static void main(String[] args) {
Engine engine = new Engine();
engine.fly();
}
}
在 fly()
方法中,打印的 name
属性就是外部类中所定义的静态属性 name
。编译执行,将会输出:
外部类的静态属性name
对于内外部类存在同名属性的问题,同样遵循就近原则。这种情况下依然希望调用外部类的静态成员,可以使用外部类名.静态成员
的方式来进行调用。这里不再一一举例。
如果想要访问外部类的非静态属性,可以通过对象的方式调用,例如在 fly()
方法中调用 Sky1
的实例属性 brand
:
public void run() {
// 实例化对象
Car1 car1 = new Car1();
System.out.println(car1.brand);
}
2.3 方法内部类
2.3.1 定义
方法内部类,是定义在方法中的内部类,也称局部内部类。
如下是方法内部类的代码:
实例演示
public class Sky2 {
// 外部类的fly()方法
public void fly() {
class Engine {
public void fly() {
System.out.println(“方法内部类的fly()方法”);
System.out.println(“发动机启动了”);
}
}
// 在Sky2.fly()方法的内部实例化其方法内部类Engine
Engine engine = new Engine();
// 调用Engine的fly()方法
engine.fly();
}
public static void main(String[] args) {
Sky2 Sky2 = new Sky2();
Sky2.fly();
}
}
运行结果:
方法内部类的run()方法
发动机启动了
如果我们想调用方法内部类的 fly()
方法,必须在方法内对 Engine
类进行实例化,再去调用其 fly()
方法,然后通过外部类调用自身方法的方式让内部类方法执行。
2.3.2 特点
与局部变量相同,局部内部类也有以下特点:
-
方法内定义的局部内部类只能在方法内部使用;
-
方法内不能定义静态成员;
-
不能使用访问修饰符。
也就是说,Sky2.getEngine()
方法中的 Engine
内部类只能在其方法内部使用;并且不能出现 static
关键字;也不能出现任何的访问修饰符,例如把方法内部类 Engine
声明为 public
是不合法的。
2.4 匿名内部类
2.4.1 定义
匿名内部类就是没有名字的内部类。使用匿名内部类,通常令其实现一个抽象类或接口。
实例演示
// 定义一个交通工具抽象父类,里面只有一个fly()方法
public abstract class Transport {
public void fly() {
System.out.println(“交通工具fly()方法”);
}
public static void main(String[] args) {
// 此处为匿名内部类,将对象的定义和实例化放到了一起
Transport Sky = new Transport() {
// 实现抽象父类的fly()方法
@Override
public void fly() {
System.out.println(“汽车跑”);
}
};
// 调用其方法
Sky.fly();
Transport airPlain = new Transport() {
// 实现抽象父类的fly()方法
@Override
public void fly() {
System.out.println(“飞机飞”);
}
};
airPlain.fly();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)
Java面试精选题、架构实战文档
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
易碰到天花板技术停滞不前!**
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-SstgIt4h-1713678794028)]
[外链图片转存中…(img-dARivUUP-1713678794028)]
[外链图片转存中…(img-TYJg7dWD-1713678794028)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)
[外链图片转存中…(img-jHBiqr90-1713678794029)]
Java面试精选题、架构实战文档
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!