Java 四大内部类总结——局部内部类,匿名内部类,成员内部类,静态内部类

Java 四大内部类总结

1. 内部类1.1 内部类概念1.2 内部类语法1.3 四种内部类(1) 局部内部类:定义在外部类的局部位置上(通常在方法/代码块内),且[有]类名(2) 匿名内部类:定义在外部类的局部位置上(通常在方法/代码块内),且[没有]类名基本语法:基于接口的匿名内部类基于类的匿名内部类一些其他解释匿名内部类使用场景

(3) 成员内部类:定义在外部类的成员位置上(属性 方法这些地方),且[没有]static修饰(4) 静态内部类:定义在外部类的成员位置上(通常在方法/代码块),且[有]static修饰

1. 内部类

1.1 内部类概念

一个类的内部又完整的嵌套了另一个类结构。 被嵌套的类称为内部类(inner class) 嵌套其他类的类称为外部类(outer class) 特点:内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。

1.2 内部类语法

class Outer{ // 外部类

class Inner{ // 内部类

}

}

class Other{ // 其他类

}

1.3 四种内部类

定义在外部类的局部位置上(比如方法/代码块内)

局部内部类(有类名)

匿名内部类(没有类名)🌟

定义在外部类的成员位置上(本质就是一个成员)

成员内部类(没用static修饰)

静态内部类(使用static修饰)

(1) 局部内部类:定义在外部类的局部位置上(通常在方法/代码块内),且[有]类名

👿​(1)局部内部类定义在方法中/代码块 (2) 作用域在方法体或者代码块中 (3)本质仍然是一个类!!!

可以直接访问外部类的所有成员,包含私有的

不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。 但是可以使用final 修饰,因为局部变量也可以使用final.(final就可以让类不可以被继承)

作用域:仅仅在定义它的方法或代码块中

局部内部类—访问---->外部类的成员【访问方式:直接访问】

外部类—访问---->局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】

外部其他类—不能访问----->局部内部类【因为 局部内部类地位是一个局部变量】

如果外部类和局部内部类的成员重名时,默认遵循就近原则, 如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问 : Outer02.this本质就是外部类的对象,于是就相当于用对象.n1去访问类的属性,就是 Outer02.this.n1

public class LocalInnerClass {//

public static void main(String[] args) {

//演示一遍

Outer02 outer02 = new Outer02();

outer02.m1();

System.out.println("outer02 的 hashcode=" + outer02);

// 对象outer02就是Outer02.this

}

}

class Outer02 { //外部类

private int n1 = 100;

private void m2() { //私有方法

System.out.println("Outer02 m2()");

}

public void m1() { //方法

//1.局部内部类是定义在外部类的局部位置,通常在方法

//3.不能添加访问修饰符,但是可以使用final 修饰

//4.作用域 : 仅仅在定义它的方法或代码块中

final class Inner02 { //局部内部类(本质仍然是一个类)

//2.可以直接访问外部类的所有成员,包含私有的

private int n1 = 800;

public void f1() {

//5. 局部内部类可以直接访问外部类的成员,比如下面可以直接访问:外部类n1 和 m2()

//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,

// 如果想访问外部类的成员,使用 外部类名.this.成员 去访问

// Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1,Outer02.this就是哪个对象,

// 于是就相当于对象.n1去访问类的属性,就是 Outer02.this.n1

System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer02.this.n1);

System.out.println("Outer02.this hashcode=" + Outer02.this);

m2();

}

}

//6. 外部类访问内部类:外部类在方法中,可以创建Inner02对象,然后调用方法即可

Inner02 inner02 = new Inner02();

inner02.f1();

}

}

class Outer01{}// 外部其他类 不能访问 局部内部类

(2) 匿名内部类:定义在外部类的局部位置上(通常在方法/代码块内),且[没有]类名

👿(1)定义在方法中 / 代码块; (2) 作用域在 方法体 / 代码块 中; (3)本质仍然是一个类; (4)该类没有名字(但其实在系统底层分配有名字); (5)同时还是一个对象; 匿名内部类—访问---->外部类的成员【访问方式:直接访问,包含私有的】 如果外部类和匿名内部类的成员重名时,默认遵循就近原则, 如果此时匿名内部类想访问外部类的成员,则可以使用(外部类名.this.成员)去访问 : Outer02.this本质就是外部类的对象,于是就相当于用对象.n1去访问类的属性,就是 Outer02.this.n1

​ 外部类—访问---->匿名内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】 ​ 外部其他类—不能访问----->匿名内部类【因为 匿名内部类地位是一个局部变量】 ​ 不能添加访问修饰符,因为其本身相当于一个局部变量

基本语法: 因为众所周知 抽象类和接口无法创建对象,所以这里面的new,其实是new的他们的实现类(子类 )对象,类名由系统分配

匿名内部类大括号内其本质上就是一个实现类(子类),new就会立即创建出一个实现类(子类)对象

new 抽象类名/接口名(参数列表){

重写抽象类或者接口中的抽象方法

};

基于接口的匿名内部类 package com.hspedu.innerclass;

/*

接口匿名内部类的使用

*/

public class AnonymousInnerClass {

public static void main(String[] args) {

Outer outer = new Outer();

outer.method();

}

}

class Outer{ // 外部类

private int n1 = 10; // 外部类属性

public void method(){ // 外部类方法

// 【基于接口的匿名内部类】 需求:想使用IA接口并创建对象,传统方式就是使用一个类实现该接口并创建对象

// Tiger tiger = new tiger();

// tiger.cry();

// 但是Tiger类只用一次,后面不再使用了,每次想要实现IA接口就定义一个类很繁琐

// 于是可以使用【匿名内部类】简化开发(既不创建Tiger类 又可以让老虎叫)

// tiger的编译类型是:IA

// tiger的运行类型是:匿名内部类XXX => Outer$1

/*

底层会分配一个类名 XXX => Outer$1

class XXX implements IA{

@Override

public void cry() {

System.out.println("老虎叫唤aowuaowu");

}

}

*/

// new 出来的就是接口的实现类对象 即:class XXX implements IA

// jdk底层创建匿名内部类Outer$1后,立马就创建了Outer$1的对象,把地址返回给tiger(多态:接口类型的变量tiger 可以指向 实现了IA接口类的对象实例)

// 匿名内部类创建完对象后,这个匿名内部类就没有了,但对象还在,可以反复使用。

IA tiger = new IA(){ // new了就是一个实现类对象

@Override // 大括号内本质上就是一个实现类

public void cry() {

System.out.println("老虎叫唤aowuaowu");

}

};

System.out.println("tiger 的运行类型" + tiger.getClass()); // 这里使用getClass获取对象 tiger 的运行类型 Outer$1

tiger.cry();

}

}

interface IA{ // 接口

public void cry();

}

//class Tiger implements IA{ // 繁琐

// @Override

// public void cry() {

// System.out.println("老虎叫唤aowuaowu");

// }

//}

基于类的匿名内部类

package com.hspedu.innerclass;

/*

匿名内部类的使用

*/

public class AnonymousInnerClass {

public static void main(String[] args) {

Outer outer = new Outer();

outer.method();

}

}

class Outer{ // 外部类

private int n1 = 10; // 外部类属性

public void method(){ // 外部类方法

// 【基于类的匿名内部类】 需求:想使用Father类并创建对象,传统方式就是使用这个类并创建对象↓

// Father father = new Father("爹名");

// 这里打了大括号{},那么{}中就相当于是抽象类的实现类(或者就说子类),new了就是new出来一个实现类(子类)对象,之后用类的引用指向这个实现类(子类)

// father的编译类型是:Father

// father的运行类型是:匿名内部类XXX => Outer$2 按顺序编号

// 底层会创建匿名内部类 class Outer$2 extends Father(){},并且直接返回了匿名内部类Outer$2的对象

// 参数列表默认会传递给类的构造器

Father father = new Father("爹名"){

@Override

public void test() {

System.out.println("匿名内部类重写了test方法,要输出一个" + name);

}

};

System.out.println("father 的运行类型" + father.getClass()); // 这里使用getClass获取对象 father 的运行类型 Outer$2

father.test();

}

}

abstract class Father{ // 类

public String name;

public Father(String name) { // 类的构造器

this.name = name;

}

public abstract void test();// 抽象方法

}

一些其他解释

​ 匿名内部类—访问---->外部类的成员【访问方式:直接访问,包含私有的】

​ 如果外部类和匿名内部类的成员重名时,默认遵循就近原则,

​ 如果此时匿名内部类想访问外部类的成员,则可以使用(外部类名.this.成员)去访问 :

​ Outer05.this本质就是外部类的对象,于是就相当于用对象.n1去访问类的属性,就是 Outer05.this.n1

​ 外部类—访问---->匿名内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】

​ 外部其他类—不能访问----->匿名内部类【因为 匿名内部类地位是一个局部变量】

​ 不能添加访问修饰符,因为其本身相当于一个局部变量

public static void main(String[] args) {

Outer05 outer05 = new Outer05();

outer05.f1();

System.out.println("main outer05 hashcode=" + outer05);

}

}

class Outer05 {

private int n1 = 99;

public void f1() {

//创建一个基于类的匿名内部类

//不能添加访问修饰符,因为它的地位就是一个局部变量

//作用域 : 仅仅在定义它的方法或代码块中

Person p = new Person(){

private int n1 = 88;

@Override

public void hi() {

//可以直接访问外部类的所有成员,包含私有的

//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,

//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问

System.out.println("匿名内部类重写了 hi 方法 n1=" +n1 + "外部内的n1=" + Outer05.this.n1 ); //和主函数中打印的一样

//Outer05.this 就是调用 f1 的对象,即:谁调用的f1 这个Outer05.this 就是谁————即为主函数中的outer05

System.out.println("Outer05.this hashcode=" + Outer05.this) //>>>>> 会输出:调用 f1 的对象的hashcode

}

};

p.hi();//调用时候:动态绑定, 运行类型是 Outer05$1 // >>>>> 会输出:匿名内部类重写了 hi 方法 n1=88 外部内的n1=99

}

"""''''''''''''''' 下面的这模块代码是和上面的代码或者关系存在演示的

//调用时候:也可以直接调用, 匿名内部类本身也是返回对象

new Person(){

@Override

public void hi() {

System.out.println("匿名内部类重写了 hi 方法,哈哈...");//>输出匿名内部类重写了 hi 方法,哈哈...【不输出Person hi()】

}

@Override

public void ok(String str) {

super.ok(str);

}

}.ok("jack"); // >>>>> 会输出Person ok()jack

"""''''''''''''''''''''

class Person { //类

public void hi() {

System.out.println("Person hi()");

}

public void ok(String str) {

System.out.println("Person ok()" + str);

}

}

匿名内部类使用场景 【传统的方法】

public class AnonymousInnerClass01 {

public static void main(String[] args) {

A a = new A(); // 创建实现类的对象

f1(a);

}

public static void f1(IL il){

il.show();

}

}

interface IL{

void show();

}

class A implements IL{ //类实现IL接口,硬编码方式

@Override

public void show() {

System.out.println("showwwww");

}

}

【匿名内部类的使用】

public class AnonymousInnerClass01 {

public static void main(String[] args) {

f1(new IL() { // 大括号里面就相当于是接口的实现类,给f1传入的就是接口的实现类对象 !!!!

@Override

public void show() {

System.out.println("showwwww");

}

});

}

public static void f1(IL il){ // 需要传入接口的实现类对象

il.show();

}

}

interface IL{

void show();

}

(3) 成员内部类:定义在外部类的成员位置上(属性 方法这些地方),且[没有]static修饰

成员内部类—访问---->外部类的成员【访问方式:直接访问,包含私有的】

如果外部类和内部类的成员重名时,默认遵循就近原则,如果此时内部类想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问

外部类—访问---->成员内部类的成员【访问方式:创建成员内部类的对象,再访问(注意:必须在作用域内)】外部其他类—访问----->成员内部类【两种方法】【外部类对象.new 内部类名()】可以添加任意的访问修饰符(public protected 默认 private),因为其本身相当于一个成员,其作用域范围也和外部类的其他成员一样

public class MemberInnerClass01 {

public static void main(String[] args) {

Outer08 outer08 = new Outer08();

outer08.t1();

// 方式一 外部其他类调用成员内部类的方式

Outer08.Inner inner = outer08.new Inner(); // 用外部类的对象new内部类Inner

inner.say();

// 方式二 在外部类中写一个编写一个方法可以返回一个Inner08 的对象实例

Outer08.Inner innerinstance = outer08.getInnerInstance();

innerinstance.say();

}

}

class Outer08{ // 外部类

private int n1 = 10;

public String name = "张三";

public class Inner{ // 成员内部类

private int n1 = 66;

public void say(){

// 成员内部类可以访问外部类的所有成员,包括私有的

System.out.println("Outer08的name=" + name);

System.out.println("内部类Inner 的n1=" + n1);

System.out.println("外部类Outer08 的n1=" + Outer08.this.n1); // 重名的时候,使用外部类名.this访问外部类属性

}

}

public Inner getInnerInstance(){ // 方法二 ,返回一个Inner 对象

return new Inner();

}

// 再写一个方法 外部类访问成员内部类 创建对象访问

public void t1(){

Inner inner = new Inner();

inner.say();

}

}

(4) 静态内部类:定义在外部类的成员位置上(通常在方法/代码块),且[有]static修饰

静态内部类—访问---->外部类的成员【访问方式:直接访问,包含私有的】【🔴但是只能访问静态成员!!!!】

如果外部类和内部类成员重名时,默认遵循就近,如果此时内部类想访问外部类成员,可以使用 (外部类名.成员)去访问 【因为成员是静态的,类名调用,就不用加this了】

外部类—访问---->静态内部类的成员【访问方式:创建内部类的对象,再访问(注意:必须在作用域内)】外部其他类—访问----->成员内部类【因为静态内部类是 可以通过类名直接访问(前提满足访问权限),所以new一个Outer08.Inner()对象,在调用方法】可以添加任意的访问修饰符(public protected 默认 private),因为其本身相当于一个成员,其作用域范围也和外部类的其他成员一样。

public class MemberInnerClass01 {

public static void main(String[] args) {

Outer08 outer08 = new Outer08();

outer08.m1();

// 外部其他类使用静态内部类 因为静态内部类是 可以通过类名直接访问(前提满足访问权限),所以new一个Outer08.Inner()对象,在调用方法

new Outer08.Inner().say();

}

}

class Outer08{ // 外部类

private int n1 = 10;

public String name = "张三";

private static int n2 = 99;

public static class Inner{ // 静态内部类 有static修饰

private int n2 = 1;

public void say(){

System.out.println("外部类的静态属性n2=" + Outer08.n2); // 重名访问外部类的属性 直接通过外部类名.成员访问

System.out.println("静态内部类的属性n2 = " +n2); // 因为外部类的n1和name都是非静态的,所以不能访问

}

}

public void m1(){ // 外部类访问静态内部类的成员:创建对象在访问

new Inner().say();

}

}

版本爆料 |【经典区】即将上线,全新赛季制降临海域
SO的英文缩写