个人主页:Nezuko627的博客主页
❤️ 支持我: 点赞 收藏 关注
格言:立志做一个有思想的程序员
作者介绍:本人本科软件工程在读,博客将主要分享JavaSE、JavaEE、MySQL、SpringBoot、算法等知识。专栏内容长期更新,如有错误,欢迎评论区或者私信指正!感谢大家的支持~~~
本篇学习目标:
- ⭐️ 熟悉内部类的划分及分类;
- ⭐️ 掌握四种内部类的基本使用方式;
- ⭐️ 理解四种内部类的应用场景;
- ⭐️ 重点掌握匿名内部类的使用与本质。
基本介绍:
一个类的内部又完整的嵌套了另一个类的结构。 被嵌套的类称为内部类,嵌套其他类的类称为外部类。内部类的最大特点是 可以直接访问其私有属性,并且体现类与类的包含关系。
Tips: 类的五大成员: 属性、方法、构造器、代码块、内部类。
️ 基本语法:
class Outer{ // 外部类
class Inner{ // 内部类
}
}
说明: 局部内部类是定义在外部类的局部位置,比如定义在方法中,且有类名。
局部内部类的特性:
1️⃣ 局部内部类可以直接访问外部类的所有成员,包含私有的;
2️⃣ 不能添加访问修饰符, 因为局部内部类的地位实际是一个局部变量。但是可以用 final
修饰;
3️⃣ 作用域:定义的方法或者代码块中;
4️⃣ 外部类在方法中,可以通过创建内部类的对象,访问内部类的成员。
6️⃣ 如果外部类和内部类的成员重名,则遵循就近原则。如果想访问外部类成员,则可以通过 外部类名.this.成员名
的方式访问;
示例代码:
public class LocalInnerClass { // 外部其他类
public static void main(String[] args) {
Outer outer = new Outer();
outer.method1();
}
}
class Outer{ // 外部类
private int attribute = 20; // 外部类私有属性
public void method1(){ // 成员方法
class Inner{ // 内部类
private int attribute = 100; // 内部部类私有属性
// 可以直接访问外部类所有成员,包括私有的
public void m1(){
System.out.println(attribute); // 就近原则 100
System.out.println(Outer.this.attribute); // 20
}
}
new Inner().m1(); // 使用内部类的m1
}
}
实现结果:
100
20
解释: 外部类名.this.成员名
本质就是外部类的对象,示例中 Outer.this 指代外部其他类创建的对象 outer。
与局部内部类相类似的是,匿名内部类也是定义在外部类的局部位置,但是其 没有类名。 其本质还是一个内部类, 同时也是一个对象。
️ 匿名内部类的基本语法:
new 类名或接口名(参数列表){
类体
};
❓ 看到这,你可能就会问 ,接口不是不能实例化吗,为啥匿名内部类可以直接写接口名? 实际上,当你写接口名的时候,需要同时实现接口的所有抽象方法, 示例代码如下:
public class AnonymousInnerClass {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
outerClass.method();
}
}
// 接口
interface Animals{
void say();
}
// 外部类
class OuterClass{
void method(){
Animals dog = new Animals() {
@Override
public void say() {
System.out.println("汪汪汪~~~");
}
};
dog.say();
System.out.println("匿名内部类名称:" + dog.getClass());
}
}
其实匿名内部类是有类名的,只不过是被系统底层隐藏起来了,类名为 外部类名称$1
, 上述代码中 jdk 底层在创建匿名内部类 OuterClass$1 立马创建了其实例,返回给了 dog , 实现结果如下:
汪汪汪~~~
匿名内部类名称:class outerinner.OuterClass$1
❓ 为什么要使用匿名内部类?
为了简化开发,有些类我们不需要反复使用,只需要使用一次,就会使用匿名内部类。匿名内部类只能使用一次,但匿名内部类的引用却可以多次使用。在刚刚的示例中,
dog
对象可以反复使用,但是new
的匿名内部类只创建了一次,当dog
不再使用的时候,由于匿名内部类缺少类名,我们将没有其他途径访问到它。
示例中我们也可以不使用 dog
来引用匿名内部类,而是直接使用一次!修改后的参考代码如下:
public class AnonymousInnerClass {
public static void main(String[] args) {
new OuterClass().method();
}
}
// 接口
interface Animals{
void say();
}
// 外部类
class OuterClass{
void method(){
new Animals() {
@Override
public void say() {
System.out.println("汪汪汪~~~");
}
}.say();
}
}
将匿名内部类 当作实参直接传递:
示例代码:
public class AnonymousInnerClass {
public static void main(String[] args) {
show(new Animals() {
@Override
public void say() {
System.out.println("传进来啦!");
}
});
}
public static void show(Animals animal){
animal.say();
}
}
// 接口
interface Animals{
void say();
}
实现结果:
传进来啦!
✋ 成员内部类是定义在外部类的成员位置,且没有 static
修饰的类。
成员内部类的特性:
1️⃣ 成员内部类 可以直接访问外部类的所有成员, 包括私有的;
2️⃣ 由于其本质是成员,所以 对于访问修饰符没有限制;
3️⃣ 外部类可以通过创建对象的方式访问内部类的成员,且不受修饰符的影响;
4️⃣ 外部其他类也可以通过创建对象的方式来访问内部类的成员,但是,受到访问修饰符的影响,内部类的私有成员不能直接被访问;
外部其他类创建访问内部类对象的形式:
外部类名.内部类名
对象名
=new
外部类名().new 内部类名()
;
示例:
也可以 在外部类中提供一个获取内部类对象的方法,同样可以获取内部类对象:
5️⃣ 如果外部类和内部类成员重名时,内部类被访问的话,遵循就近原则;如果想访问外部类的成员,可以使用 外部类名
.this
.成员
的方式;
下面的代码中,say()
方法访问的是内部类的 name
,即 Dog
:
class Animal{ // 外部类
private String name = "Animal";
class Dog{ // 内部类
private String name = "Dog";
public void say(){
System.out.println("My name is " + name);
}
}
}
✈️ 与成员内部类的区别在于,静态内部类有 static
修饰,具有类变量的特性。
静态内部类的特性:
1️⃣ 可以直接访问外部类的所有静态成员,但不能访问外部类的非静态成员;
2️⃣ 外部类可以通过创建对象的方式访问静态内部类, 该点与前面其他内部类的叙述类似,不再赘述;
3️⃣ 外部其他类访问静态内部类的方式:
⭐️方式1(在不考虑访问修饰符的前提下,静态内部类是可以通过类名直接访问的):
外部类名.内部类名
对象名
=new
外部类名.内部类名()
;
4️⃣ 如果外部类与静态内部类的成员重名时,静态内部类访问该成员,同样遵守就近原则;如果想要访问外部类的成员,则使用 外部类名
.成员
;
以上便是本文的全部内容啦,后续内容将会持续免费更新,如果文章对你有所帮助,麻烦动动小手点个赞 + 关注,非常感谢 ❤️ ❤️ ❤️ !
如果有问题,欢迎私信或者评论区!
共勉:“你间歇性的努力和蒙混过日子,都是对之前努力的清零。”