java内部类

一、基本介绍

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员

类的五大成员:属性、方法、构造器、代码块、内部类

内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系

基本语法:

copy
class Outer{ //外部类 class Inner{ //内部类 } } class Other{ //外部其他类 }

示意图:

基本代码演示:

copy
// 外部其他类 public class InnerClass01 { public static void main(String[] args) { } } //外部类 class Outer{ //属性 private int n1 = 10; //构造器 public Outer(int n1) { this.n1 = n1; } //方法 public void m1(){ System.out.println("m1() 方法"); } //代码块 { System.out.println("外部类代码块"); } //内部类,在Outer类的内部 class Inner{ } }

二、内部类的四大分类

基本说明:

定义在外部类局部位置上(比如方法内):

1、局部内部类(有类名)

2、匿名内部类(没有类名,开发中用的很多)

定义在外部类的成员位置上:

1、成员内部类(没有static修饰)

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

1、局部内部类

说明:局部内部类是定义在外部类的局部位置,比如说方法中,并且有类名。

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

2、不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用 final 修饰,因为局部变量也可以使用 final

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

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

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

6、外部其他类------不能访问-------->局部内部类(因为局部内部类地位是一个局部变量)

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

原因:

示例代码:代码中的注释就是解释

copy
public class LocalInnerClass { public static void main(String[] args) { Outer02 outer02 = new Outer02(); outer02.m1(); } } class Outer02 { //属性 private int n1 = 100; private int n2 = 1; //外部类的私有方法 private void m2(){ System.out.println("我是外部类的私有方法"); } //方法 public void m1(){ //1、局部内部类是定义在外部类的局部位置,通常是在方法 //3、不能添加访问修饰符(public、private等),但是可以用final修饰,但是修饰过后的内部类不允许被继承 class Inner02{ //局部内部类(本质仍然是一个类) //内部类的成员变量,与外部类成员变量同名 private int n1 = 20; //这个成员变量会最先被访问到,遵循就近原则 //2、可以直接访问外部类的所有成员,包含私有 public void f1(){ //属于局部内部类的方法 System.out.println("内部类的n1 = " + n1); //输出的是内部类的成员变量的值,因为外部类和内部类的成员变量同名 //由于同名的缘故,需要(外部类.this.属性)进行访问 //那个类调用了m1这个方法,那么内部类的this指向就是指向调用了m1方法的类 //这里是Outer02调用了m1方法,所以this指向的就是Outer02 System.out.println("外部类的n1 = " + Outer02.this.n1); //直接访问外部类的私有成员 System.out.println("外部类的n2 = " + n2); m2();//调用外部类的私有方法 } } //final关键字修饰过后的内部类是不可以被继承的 //内部类可继承其他内部类,但仅限于在它定义的方法和代码块中 class Inner03 extends Inner02{} //4、外部类在方法中,可以创建内部类对象,然后调用方法即可 Inner02 inner02 = new Inner02(); //调用内部类的方法 inner02.f1(); } public void m3(){ //代码块 { //内部类中仍然可以定义内部类 class Inner04{ class Inner06{ class Inner07{} } } //代码块中的内部类可以继承其他存在代码块的内部类 class Inner05 extends Inner04{} } } }

记住:

1、局部内部类定义在方法中、代码块中

2、作用域在方法体内或者代码块中

3、内部类的本质其实还是一个类,内部类中仍然可以定义内部类

2、匿名内部类(重点)

说明:

(1)本质还是一个类

(2)定义在一个类的内部,本质还是一个内部类

(3)该类没有名字,名字是由系统起的

(4)匿名内部类同时还是一个对象

匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名

1、匿名内部类的基本语法

copy
new 类或接口(参数列表){ 类体 };

2、匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,因此可以调用匿名内部类方法

演示:

copy
public class AnonymousInnerClassDetail { public static void main(String[] args) { Outer05 outer05 = new Outer05(); outer05.f1(); } } class Outer05{ private int n = 99; // Outer05 方法 public void f1(){ //第一种调用方法 //创建一个基于类的匿名内部类 Person p = new Person() { //重写 hi 方法 @Override public void hi() { System.out.println("匿名内部类重写了hi方法"); } }; p.hi(); //动态绑定 //第二种调用方法 new Person(){ @Override public void hi() { System.out.println("我是第二种调用方法"); } }.hi(); //匿名内部类传参 new Person(){ @Override public void ok(String str) { System.out.println("重写ok方法,接收的参数是 " + str); } }.ok("outer05穿传参"); } } class Person{ public void hi(){ System.out.println("person say hi~"); } public void ok(String str){ System.out.println("person接收参数 " + str); } }

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

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

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

6、匿名内部类----访问----->外部类成员 [直接访问]

7、外部其他类----不能访问---->匿名内部类(因为匿名内部类地位是一个局部变量)

8、如果外部类和匿名内部类的成员重名是,内部类访问的话,遵循就近原则,如果想访问外部类其他成员,则可以使用(外部类名.this.成员)访问

使用匿名内部类的原因:

为了简化开发,当开发中遇到有一个类指向使用一次,后面不再使用,就是用匿名内部类的方式

基于接口的匿名内部类示例代码:

copy
public class AnonymousInnerClass { public static void main(String[] args) { //基于接口的匿名内部类,简化开发 Outer04 outer04 = new Outer04(); outer04.method(); } } class Outer04{ //外部类 private int n1 = 10; //属性 public void method(){ //方法 //问题:tiger的编译类型 :接口类型IA //问题:tiger的运行类型:匿名内部类 Outer04$1 /* 匿名内部类底层: xxx 是底层分配的名: Outer04$1 系统分配的名字 class xxx implements IA{ @Override public void cry() { System.out.println("老虎叫。。。"); } } */ // jdk底层在创建匿名内部类 Outer04$1 ,立即马上创建了 Outer04$1 实例,并且把地址返回给tiger // 匿名内部类使用一次就不能再使用了,但是对象tiger可以使用 IA tiger = new IA() { @Override public void cry() { System.out.println("老虎叫。。。"); } }; System.out.println("tiger的运行类型---> " + tiger.getClass()); tiger.cry(); } } //接口 interface IA{ public void cry(); }

基于类的匿名内部类示例代码:

copy
public class AnonymousInnerClass { public static void main(String[] args) { //基于接口的匿名内部类,简化开发 Outer04 outer04 = new Outer04(); outer04.method(); } } class Outer04{ //外部类 private int n1 = 10; //属性 public void method(){ //方法 //基于类的匿名内部类 //father的编译类型:Father //father的运行类型:Outer04$2 匿名内部类 //底层会创建一个匿名内部类 /* 底层: class Outer04$2 extends Father{} */ //同时也直接返回了匿名内部类 Outer04$2 的对象 //参数列表会传递给Father的构造器 Father father = new Father("tom") { //匿名内部类重写test方法 @Override public void test() { System.out.println("我重写了test方法"); } }; System.out.println("father对象的运行类型---> " + father.getClass()); father.test(); } } //类 class Father{ public Father(String name){//构造器 System.out.println("Father的--name ==> " + name); } public void test(){ //方法 } }

基于抽象类的匿名内部类:

copy
public class AnonymousInnerClass { public static void main(String[] args) { //基于接口的匿名内部类,简化开发 Outer04 outer04 = new Outer04(); outer04.method(); } } class Outer04{ //外部类 private int n1 = 10; //属性 public void method(){ //方法 //基于抽象类的匿名内部类 Animal animal = new Animal() { //必须要实现抽象类中的抽象方法 @Override void eat() { System.out.println("我是抽象类中的抽象方法"); } }; animal.eat(); } } //抽象类 abstract class Animal{ abstract void eat(); }

练习一:

copy
public class InnerClassExercise01 { public static void main(String[] args) { //接口当做实参进行传递,通过匿名内部类重写方法 f1(new IL() { //这里重写了接口中的show方法,实现自己的逻辑 @Override public void show() { System.out.println("我是接口show方法的重写"); } }); //传统的写法 //首先有一个实现了IL的实现类,再将这个类传入 f1 这个方法 Pictrue pictrue = new Pictrue(); f1(pictrue); } //静态方法,方法的参数是接口类型 public static void f1(IL il){ //调用接口的方法 il.show(); } } // 接口 interface IL{ void show(); } //实现 IL的类 class Pictrue implements IL{ @Override public void show() { System.out.println("这是一幅名画。。。"); } }

练习二:

要求:

1、有一个铃声接口 Bell,里面有一个 ring 方法

2、有一个手机类 CellPhone,具有闹钟功能 alarmclock,参数是 Blee类型

3、测试手机类闹钟功能,通过匿名内部类(对象)作为参数,打印:闹钟响了

4、再传入另一个匿名内部类(对象),打印:上课了

实现代码:

copy
public class InnerClassExercise02 { public static void main(String[] args) { //实例化手机 CellPhone cellPhone = new CellPhone(); //调用手机的闹钟功能并传入铃声接口,实现匿名内部类的接口方法 cellPhone.alarmclock(new Bell() { @Override public void ring() { System.out.println("闹钟响了"); } }); cellPhone.alarmclock(new Bell() { @Override public void ring() { System.out.println("要上课了"); } }); } } // 铃声接口 interface Bell{ // ring 方法 void ring(); } //手机类 class CellPhone{ // 闹钟功能,参数是 Bell 类型 public void alarmclock(Bell bell){ //调用接口的 ring 方法 bell.ring(); } }

3、成员内部类

基本介绍:

1、成员内部类是定义在外部类的成员位置,并且没有static修饰,可以直接访问外部类的所有成员,包含私有的

2、成员内部类可以添加任一访问修饰符(public、protected、默认、private),因为它的地位就是一个成员

示例代码:

copy
public class MemberInnerClass01 { public static void main(String[] args) { Outer08 outer08 = new Outer08(); outer08.m1(); } } class Outer08{ private int n1 = 100; public String name = "tom"; //可以用修饰符进行修饰 /*public*/ /*protected*/ /*private*/ class Inner08{ public void say(){ System.out.println("Outer08的 n1 = " + n1 + " Outer08的 name = " + name); } } //在Outer08的 m1 方法中,实例化成员内部类 Inner08 public void m1(){ Inner08 inner08 = new Inner08(); //调用成员内部类的 say 方法 inner08.say(); } }

3、作用域和外部类的成员一样,为整个类体,比如之前的案例,在外部类的成员方法中创建成员内部类对象,再调用方法

4、成员内部类----访问---->外部类(比如属性)[访问方式:直接访问]

copy
public class MemberInnerClass01 { public static void main(String[] args) { Outer08 outer08 = new Outer08(); outer08.m1(); } } class Outer08{ //私有方法 private void hi(){ System.out.println("我是外部类的私有方法 hi()"); } class Inner08{ //内部类方法 public void say(){ //调用外部类的私有方法,直接调用 hi(); } } //在Outer08的 m1 方法中,实例化成员内部类 Inner08 public void m1(){ Inner08 inner08 = new Inner08(); //调用成员内部类的 say 方法 inner08.say(); } }

5、外部类-----访问---->内部类(说明)[访问方式:创建对象,再访问]

6、外部其他类---->访问----成员内部类

copy
public class MemberInnerClass01 { public static void main(String[] args) { Outer08 outer08 = new Outer08(); // outer08.m1(); //外部其他类调用成员内部类的三种方式 //第一种方式 Outer08.Inner08 inner08 = outer08.new Inner08(); //new Outer08().new Inner08(); inner08.say(); //第二种方式 在外部类中编写一个方法,返回Inner08对象实例 Outer08.Inner08 getInner08 = outer08.getInner08(); getInner08.say(); } } class Outer08{ //私有方法 private void hi(){ System.out.println("我是外部类的私有方法 hi()"); } class Inner08{ public void say(){ //调用外部类的私有方法,直接调用 hi(); } } //方式二 public Inner08 getInner08(){ return new Inner08(); } //在Outer08的 m1 方法中,实例化成员内部类 Inner08 public void m1(){ Inner08 inner08 = new Inner08(); //调用成员内部类的 say 方法 inner08.say(); } }

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

copy
public class MemberInnerClass01 { public static void main(String[] args) { Outer08 outer08 = new Outer08(); outer08.m1(); } } class Outer08{ private int n1 = 100; class Inner08{ private int n1 = 6; public void say(){ //就近原则 System.out.println("n1的值是内部类的n1 = " + n1); //访问外部类重名的属性 System.out.println("外部类n1的值 = " + Outer08.this.n1); } } //在Outer08的 m1 方法中,实例化成员内部类 Inner08 public void m1(){ Inner08 inner08 = new Inner08(); //调用成员内部类的 say 方法 inner08.say(); } }

4、静态内部类

说明:静态内部类是定义在外部类的成员位置,并且有static修饰

1、可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员

2、可以添加任一访问修饰符(public、protected、默认、private),因为它的地位就是一个成员

3、作用域:同其他的成员一样,为整个类体

示例代码:

copy
public class StaticInnerClass01 { public static void main(String[] args) { Outer09 outer09 = new Outer09(); outer09.show(); } } class Outer09{ private int n1 = 10; private static String name = "张三"; //1、放在外部类的成员位置 //2、使用static修饰 //4、可以添加任一访问修饰符(public、protected、默认、private),因为它的地位就是一个成员 /*public*/ /*private*/ /*protected*/ static class Inner02{ public void say(){ //3、可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员 System.out.println("访问外部类静态成员属性:" + name); //不能直接访问外部类的非静态成员 //System.out.println("外部类非静态成员属性:" + n1); } } //5、作用域:同其他的成员一样,为整个类体 //外部类方法 public void show(){ //外部类使用内部类 new Inner02().say(); } }

4、静态内部类----访问----外部类(比如:静态属性)[访问方式:直接访问所有静态成员]

5、外部类----访问----静态内部类 [访问方式:创建对象,再访问]

6、外部其他类-----访问----->静态内部类

copy
public class StaticInnerClass01 { public static void main(String[] args) { Outer09 outer09 = new Outer09(); outer09.show(); //外部其他类访问静态内部类 //方式一 因为静态内部类,是可以通过类名直接访问(前提是满足访问权限) Outer09.Inner02 getInner02 = new Outer09.Inner02(); getInner02.say(); //方式二 通过编写一个方法,返回静态内部类的对象实例 Outer09.Inner02 inner021 = outer09.getInner02(); inner021.say(); } } class Outer09{ private int n1 = 10; private static String name = "张三"; //外部类静态方法 private static void f1(){ System.out.println("我是外部类静态方法 f1()"); } //1、放在外部类的成员位置 //2、使用static修饰 //4、可以添加任一访问修饰符(public、protected、默认、private),因为它的地位就是一个成员 /*public*/ /*private*/ /*protected*/ static class Inner02{ public void say(){ //3、可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员 System.out.println("访问外部类静态成员属性:" + name); //不能直接访问外部类的非静态成员 //System.out.println("外部类非静态成员属性:" + n1); //可以直接调用外部类静态方法 f1(); } } //5、作用域:同其他的成员一样,为整个类体 //外部类方法 public void show(){ //外部类使用内部类 new Inner02().say(); } //方式二 返回静态内部类的对象实例 public Inner02 getInner02(){ return new Inner02(); } }

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

copy
public class StaticInnerClass01 { public static void main(String[] args) { Outer09 outer09 = new Outer09(); outer09.show(); } } class Outer09{ private static String name = "张三"; static class Inner02{ //内部类的静态属性 private static String name = "李四"; public void say(){ //就近原则 System.out.println("我是内部类的静态成员变量:" + name); System.out.println("外部类的静态成员变量:" + Outer09.name); } } //5、作用域:同其他的成员一样,为整个类体 //外部类方法 public void show(){ //外部类使用内部类 new Inner02().say(); } }

三、小结

1、内部类有四种

局部内部类、匿名内部类(重要)、成员内部类、静态内部类

2、重点还是掌握匿名内部类的使用

语法:

copy
new 类/接口(参数列表){ //.... };

3、成员内部类、静态内部类 是放在外部类的成员位置,本质上还是一个成员

练习:

copy
public class TestInnerClass01 { public static void main(String[] args) { TestInner testInner = new TestInner(); TestInner.Inner inner = testInner.new Inner(); System.out.println("main方法中的值:" + inner.a); } } class TestInner{ public TestInner(){ Inner inner01 = new Inner(); inner01.a = 10; Inner inner02 = new Inner(); System.out.println("外部类的test方法中的值:" + inner02.a); } class Inner{ public int a = 5; } }
posted @   花椒蛋炒饭  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起