❤️ 【内部类】干货满满,本章内容有点难理解,需要明白类的实例化,学完本篇文章你会对内部类有个清晰的认知
💕 内容涉及内部类
的介绍、局部内部类
、匿名内部类
(重点)、成员内部类
、静态内部类
🌈 跟着B站一位老师学习的内部类内容,先写这篇文章为学习内部类的小伙伴提供思路支持,希望可以一起感受java
的魅力,爱上java
编程!!!
文章目录
- 1、内部类
- 1.1、快速入门
- 1.2、内部类的分类
- 1.2.1、局部内部类的使用
- 1.3、匿名内部类!!!!
- 1.4、匿名内部类-最佳实践
- 1.5、成员内部类
- 作用域
- 1.6、静态内部类
- 1.7、小结
- 1.8、一道小小题
- 共勉
1、内部类
内部类基本介绍:一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(
inner class
),嵌套其他类的类称为外部类(outer class
)。是我们类的第五大成员。
其中类的五大成员为:变量、方法、构造器、代码块和内部类
内部类的最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系
1.1、快速入门
了解内部类的结构
- 外部类
Outer
中内嵌一个内部类Inner
package com.fhsedu.innerclass;
public class InnerClass01 {//外部其他类
public static void main(String[] args) {
}
}
class Outer{//外部类
private int n1 = 100;//属性
public Outer(int n1) {
this.n1 = n1;
}
{//代码块
System.out.println("代码块...");
}
class Inner{//内部类,在Outer类的内部
}
}
1.2、内部类的分类
- 匿名内部类—>重点!!!!
1.2.1、局部内部类的使用
package com.fhsedu.innerclass;
public class LocalInnerClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
}
}
class Outer02{//外部类
private int n1 = 100;
private void m2() {
System.out.println("this is outer02 m2()");
}//私有方法
public void m1() {//方法
//1、局部内部类是定义在外部类的局部位置,通常在方法
//3、不能添加访问修饰符,但是可以使用final 修饰
//4、作用域:仅仅在定义它的方法或代码中
final class Inner02{//局部内部类(本质任然是一个类)
//2、可以直接访问外部类的所有成员,包括私有的
public void f1() {
//5、局部内部类可以直接访问外部类的成员、比如下面 外部类属性n1 和 方法m2()
System.out.println("n1 = " + n1);
m2();
}
}
//6、外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
/*class Inner03 extends Inner02{}*///可以的
}
}
记住:
- 局部内部类定义在方法中/代码块
- 作用域在方法体或者代码块中
- 本质仍然是一个类
- 外部其他类----> 不能访问局部内部类(因为 局部内部类地位是一个局部变量,就好像private修饰的属性只能提供共有的
get
方法才能访问) - 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(
外部类命.this.成员
)去访问
System.out.println("外部类的n2=" + 外部类命.this.n2);
代码演示获取Outer的属性:
class Outer02 {//外部类
private int n1 = 100;
public void m1() {//方法
final class Inner02 {//局部内部类(本质任然是一个类)
//2、可以直接访问外部类的所有成员,包括私有的
private int n1 = 800;
public void f1() {
// 如果想访问外部类的成员,则可以使用(外部类命.this.成员)去访问
// 解读: Outer02.this 本质就是外部类的对象,即:哪个对象调用了m1,Outer02就是哪个对象
System.out.println("n1 = " + n1 + "外部类属性=" + Outer02.this.n1);
System.out.println("Outer02.this 的 Hashcode=" + Outer02.this.hashCode());
}
}
}
}
1.3、匿名内部类!!!!
Anonymous:匿名的
思考一个小问题:为什么java接口不能被实例化?
Java中的接口不能被实例化
这是因为接口是一种抽象类型,它定义了一组方法的签名,但不包含任何方法的实现。接口的主要目的是规定类应该实现哪些方法,而不是提供一个具体的实现。因此,接口本身并不能被实例化,也就是说不能使用new
关键字来实例化一个接口。接口只能被类实现,并且类必须实现接口中定义的所有方法。然后通过类的实例来调用接口中定义的方法。
接口IA:定义了一个抽象方法cry()
interface IA{
void cry();
}
定义一个主类
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
外部类和匿名内部类
class Outer04{//内部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类
//匿名内部类使用一次,就不能再使用
// 即不能 new tiger$1()
IA tiger = new IA(){
@Override
public void cry() {
System.out.println("老虎...");
}
};
tiger.cry();
IA dog = new IA(){
@Override
public void cry() {
System.out.println("小狗...");
}
};
dog.cry();
//打印两个匿名内部类的类类型
//dog的运行类型:class com.fhsedu.Outer04$1
System.out.println("dog的运行类型:" + dog.getClass());
//cat的运行类型:class com.fhsedu.Outer04$2
System.out.println("cat的运行类型:" + cat.getClass());
}
}
小结:
匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
一般语法:
new 类或接口(参数列表){
类体;
};
小结:
- 本质是类,内部类
- 该类没有名字,同时还是一个对象
- 可以直接访问外部类的所有成员,包括私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量。
- 作用域:仅仅在定义它的方法或代码块中。
- 匿名内部类—>访问---->外部类成员【访问方式:直接访问或
外部类名.this.属性
】 - 外部其他类---->不能访问---->匿名内部类【因为匿名内部类地位就是一个局部变量】
- 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
1.4、匿名内部类-最佳实践
Exercise01
package com.fhsedu.innerclass;
public class AnonymousInnerClassExercise01 {
public static void main(String[] args) {
f1(new IL() {
@Override
public void show() {
System.out.println("this is a picture!!!");
}
});
//传统方法
f1(new Picture());
}
//静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
//接口
interface IL {
void show();
}
//传统方法-》类实现IL-》编程领域(硬编码)
class Picture implements IL {
@Override
public void show() {
System.out.println("this is a picture!");
}
}
自己可以先思考一下实现思想,重要的是培养编程思维
代码实现
- 接口
//定义一个接口
interface Bell{
//默认抽象方法
void ring();
}
//定义一个类
class Cellphone{
//参数是Bell
public void alarmClock(Bell bell){
bell.ring();
}
}
- 实现类
public class homework02 {
public static void main(String[] args) {
//创建一个对象,并调用它里面的alarmClock(..)方法,
// 进行传入一个匿名内部类
new Cellphone().alarmClock(new Bell() {
@Override
public void ring() {
System.out.println(this.getClass());
System.out.println("小伙伴,别熬夜了!");
}
});
//跟上面一样
new Cellphone().alarmClock(new Bell() {
@Override
public void ring() {
System.out.println(this.getClass());
System.out.println("明天吃火锅!");
}
});
}
}
(这里我把接口也打印出来了,复习一下接口的名字)
- 如果有两个类:类1 和 类2 都有匿名内部类,那么分别为各自的类起名字(Java内部)如:类1种的匿名内部类为 Outer$1、Outer$2 此时下面的为:Inner$1、Inner$2。。。
- 匿名内部类中编译类型是赋予的,运行类型是系统给的
1.5、成员内部类
说明:成员内部是定义在外部类的成员位置,并且没有static修饰
- 可以直接访问外部类的所有成员
- 可以添加访问修饰符(public、protected、默认、private),因为它的地位就是一个成员
代码演示
package com.fhsedu.innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
}
}
class Outer08 {//外部类
private int n1 = 10;
public String name = "张三";
class Inner08{//成员内部类
public void say() {
//成员内部类可以访问所有外部类的成员、包含私有的
System.out.println("Outer08 的 n1 =" +
Outer08.this.n1 + "Outer08 的 name = " + Outer08.this.name);
}
}
public void t1() {
Inner08 inner08 = new Inner08();
inner08.say();
}
}
成员内部类的使用:在外部类创建方法创建对象调用方法
作用域
作用于和外部类的其他成员一样,为整个类体
比如之前我们在外部类的成员方法中创建成员内部类对象,再调用对象
- 外部其他类访问内部类
package com.fhsedu.innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
//外部类自己的方法直接调用
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类,使用成员内部类的三种方式
//new Inner08();错误方法
//第一种语法,不要特别的纠结
//Outer08.new Inner08()
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
//第二种方法:
//在外部类中创建一个方法用于返回匿名内部类
Outer08.Inner08 inner08Instance = outer08.getInner08();
inner08Instance.say();
}
}
class Outer08 {//外部类
private int n1 = 10;
public String name = "张三";
protected class Inner08{//成员内部类 //可以使用访问修饰符
public void say() {
//成员内部类可以访问所有外部类的成员、包含私有的
System.out.println("Outer08 的 n1 =" +
Outer08.this.n1 + "Outer08 的 name = " + Outer08.this.name);
}
}
public Inner08 getInner08() {
return new Inner08();
}
public void t1() {
Inner08 inner08 = new Inner08();
inner08.say();
}
}
重要的事情说三遍!!!
如果外部类和内部类成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。
代码演示
(看高亮块)
1.6、静态内部类
- 静态类只能访问静态成员
- 静态内部类—>访问—>外部类(静态属性)【访问方式:直接访问所有静态成员】
- 外部类—>访问—>静态内部类 访问方式:创建对象,再访问
外部其他类访问静态内部类:
- 外部类访问静态内部类,跟之前的不一样
外部类&&内部类
class Outer10 {
private int n1 = 10;
private static String name = "张三";
private static void cry() {
System.out.println("cry静态成员方法");
}
//Inner10就是静态内部类
//1、放在外部类的成员位置
//2、使用static 修饰
//3、可以直接访问外部类的所有静态成员包括私有的,但不能直接访问非静态成员
//4、可以添加任意访问修饰符(public、protected、默认、private)因为它的地位就是一个成员
static class Inner10 {
public void say() {
cry();
System.out.println(name);
}
}
public void m1() {
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10() {//非静态的可以访问静态和非静态
return new Inner10();
}
public static Inner10 getInner10_() {//静态只能访问静态
return new Inner10();
}
}
测试类
public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类 使用静态内部类
//方式1
//因为静态内部类,是可以通过哦类命直接访问(前提是满足访问权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式2
Outer10.Inner10 inner101 = outer10.getInner10();
inner101.say();
Outer10.Inner10 inner10_ = Outer10.getInner10_();//访问静态的
inner10_.say();
}
}
注意细节点
7.如果外部类和静态内部类的成员重名时,
静态内部类
(之前是局部内部类和匿名内部类)访问时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员) 去访问
- 此时不用加this了,因为访问的是静态的
1.7、小结
小结:
- 内部类有四种 局部内部类,匿名内部类,成员内部类,静态内部类
- 重点还是掌握 匿名内部类使用
- new 类/接口(参数列表){ //… }
- 成员内部类,静态内部类 是放在外部类的成员位置,本质就是一个成员
- 其他细节:看笔记…
1.8、一道小小题
分别指向不同的对象空间:答案:5,5
package com.fhsedu;
public class Test_ {
public Test_() {
Inner s1 = new Inner();
s1.a = 10;
Inner s2 = new Inner();
System.out.println(s2.a);
}
class Inner {
public int a = 5;
}
public static void main(String[] args) {
Test_ t = new Test_();//5
Inner r = t.new Inner();
System.out.println(r.a);//5
}
}
共勉
整理心情,再次出发!!!
老黄牛精神,持之以恒坚持