强哥说Java--Java内部类

目标


  1. 什么是内部类

  2. 内部类的分类作用

  3. 内部类如何定义

  4. 如何实例化以及各自的特点

  5. 要注意区分不同类型内部类的异同

  6. 为什么需要内部类

1. 概念


在 Java 语言中,可以将一个类定义在另一个类里面或者一个方法里面,我们把这样的类称为内部类。

与之对应的,包含内部类的类被称为外部类。请阅读下面的代码:

// 外部类 Car

public class Car {

// 内部类 Engine

class Engine {

private String innerName = “发动机内部类”;

}

}

代码中,Engine 就是内部类,而 Sky 就是外部类。

2. 分类


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 种方法:

  1. 我们可以通过 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();

}

}

运行结果:

发动机启动了!

  1. 我们可通过先实例化外部类、再实例化内部类的方法获取内部类的对象实例:

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

发动机启动了!

  1. 我们也可以在外部类中定义一个获取内部类的方法 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();

}

}

观察 Enginefly() 方法,调用了外部类的成员属性 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开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)

image

Java面试精选题、架构实战文档

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-SstgIt4h-1713678794028)]

[外链图片转存中…(img-dARivUUP-1713678794028)]

[外链图片转存中…(img-TYJg7dWD-1713678794028)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)

[外链图片转存中…(img-jHBiqr90-1713678794029)]

Java面试精选题、架构实战文档

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值