java 四种内部类
四种内部类
基本介绍:一个类的内部又完整嵌套了了另一个类结构,被嵌套的类称为内部类
属性,方法,构造器,代码块,内部类 类的五大成员
内部类是学习的难点,同事也是重点,后面看底层源码时,有大量得到内部类
1.定义在外部类的局部位置上(比如方法内) :
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点!!!!!一把梭哈)
2.定义在外部类的成员位置上
- 成员内部类(没用 static 修饰)
- 静态内部类(static 修饰)
局部内部类(有类名)
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的位置就是一个局部变量,局部变量是不能使用访问修饰符的。但是可以使用 final 修饰,因为局部变量可以使用 final
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类----访问----> 外部类的成员[访问方式:直接访问]
- 外部类 ---- 访问 ----- > 局部内部类成员 访问方式 : 创建对象,在访问(注意:必须在作用域内)
package com.wxledu.innercass; /** * 演示局部内部类的使用 */ public class LocalInnerClass { public static void main(String[] args) { //演示一下 Outer02 outer02 = new Outer02(); outer02.m1(); } } class Outer02{//外部类 private int n1 = 100; private void m2(){}//私有方法 public void m1(){//方法 // 1. 局部内部类是定义在外部类的局部位置,通常在 方法 // 2. 不能添加访问修饰符,但是可以使用 final 修饰,因为局部变量可以使用 final 修饰 // 3. 作用域 : 仅仅在定义它的方法 和 代码块中 class Inner02{//局部内部类(本质还是一个类) // 4. 可以直接访问外部类的所有成员,包含私有的 public void f1(){ // 5. 局部内部类直接访问外部类的成员。 比如下面 n1 m2() System.out.println("n1 = " + n1); m2(); } } // 6. 外部类可以在这个方法中创建 Inner02 对象,然后调用方法即可 Inner02 inner02 = new Inner02(); inner02.f1(); } }
记住 (1) 局部内部类是定义在方法中 / 代码块. (2) 作用域在方法体或者代码块 (3) 本质仍然是一个类
- 外部其他类 --- 不能访问 ----> 局部内部类(因为局部内部类的地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就进原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员) 去访问
匿名内部类
- 本质是类
- 内部类
- 该类没有名字 (匿名)
- 同时还是一个对象
说明: 匿名内部类是定义在外部类的局部位置,比如在方法中,并且没有类名
为什么要使用匿名内部类?
很多时候是为了简化开发,或者基于一个类去创建一个新的类,有时候这个类只想使用一次
package com.wxledu.innercass; /** * 演示匿名内部类的使用 */ public class AnonymousInnerClass { public static void main(String[] args) { Outer04 outer04 = new Outer04(); outer04.method(); } } class Outer04{ private int n1 = 10; //属性 public void method(){//方法 //基于接口的匿名内部类 // 1. 需求:想使用接口 IA, 并创建对象 // 2. 传统方式:是写一个类,实现该接口,并创建对象 // 3. 希望 tiger 这个类值使用一次,以后再也不使用了 // 4. 可以使用匿名内部类简化开发 // 5. tiger 的编译类型:IA (看等号左边) // 6. tiger 的运行类型:就是匿名内部类 XXX => Outer04$1 /* 我们看底层 class XXXX implements IA{ @Override public void cry() { System.out.println("老虎叫唤......"); } } */ // 7. jdk 底层,在创建了匿名内部类 Outer04$1 ,立即马上创建了 Outer04$1 实例, 并且把地址返回给 tiger IA tiger = new IA(){ @Override public void cry() { System.out.println("老虎叫唤....."); } }; System.out.println("tiger的运行类型 = " + tiger.getClass()); tiger.cry(); tiger.cry(); // 演示基于类的匿名内部类 // 分析 // 1. 编译类型是 father // 2. 运行类型是 Outer04$2 // 3. 底层会会创建一个匿名内部类 /* class Outer04$2 extends father{} */ // 4. 同事也直接返回了 匿名内部类 Outer04$2 这个对象 // 5. 注意 : 参数列表会传递给 构造器 father jack = new father("jack"){ @Override public void test() { System.out.println("匿名内部类重写了 test() 方法"); } }; System.out.println("father对象的运行类型 = " + jack.getClass()); jack.test(); //基于抽象类的匿名内部类 Animal animal = new Animal(){ @Override void eat() { System.out.println("实现了 抽象类的 eat() 方法"); } }; animal.eat(); } } interface IA{ public void cry(); } class father{//类 public father(String name) {//构造器 System.out.println("接受到" + name); } public void test(){} } abstract class Animal{ abstract void eat(); }
- 匿名内部类的使用
- 匿名内部类的语法比较奇特,请大家注意,匿名内部类即是一个类的定义,同时他本身也是一个对象,因此从语法上看,他既有定义类的特征,也有创建对象特征,对代码分析可以看出这个特点,因此可以调用匿名内部类方法
- 可以直接访问外部类的所有成员,包括私有的
- 不能添加访问修饰符,因为他的地位就是一个局部变量
- 作用域:仅仅在定义它的代码块中
- 匿名内部类 ---- > 访问 ----> 外部类成员 [访问方式 直接访问]
- 外部其他类 ------ > 不能访问 -------> 匿名内部类
- 如果外部类和内部类的成员重名时,内部类访问的话,必须遵循就进原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问
匿名内部类的最佳实践
- 当做实参世界传递,简介高效
匿名内部类
- 继承
- 多态
- 动态绑定
- 内部类
3.成员内部类
说明:定义在外部类的成员位置。并且没有static修饰
-
可以直接访问外部类的所有成员,包含私有的
-
可以添加任意访问修饰符(public, protected, 默认,private),因为它的地位就是一个成员
-
作用域和外部类的其他成员一样,为整个类体,比如前面的案例,在外部类的成员方法中创建成员和内部类对象,在调用方法
-
成员内部类 ------> 访问 --------> 外部类的成员(比如:属性) 【访问方式 直接访问】
-
外部类 ----> 访问 -----> 内部类 【访问方式 创建对象在访问】
-
外部其他类 ----> 访问 -----> 成员内部类
package com.wxledu.innercass; public class MemberInnerClass { public static void main(String[] args) { Outer08 outer08 = new Outer08(); outer08.t1(); //外部其他类使用成员内部类的三种方式 // 解读 // 第一种方式 // outer08.new Inner08() 相当与 把 new Inner08() 当做 outer08 的成员 // 这就是一个语法,不用特别纠结 Outer08.Inner08 inner08 = outer08.new Inner08(); inner08.say(); // 第二种方式,在外部类中,编写一个方法,返回 Inner08 的对象池 Outer08.Inner08 inner08Instance = outer08.getInner08Instance(); inner08Instance.say(); // 第三种方式 } } class Outer08{//外部类 private int n1 = 10; public String name = "张三"; class Inner08{//成员内部类 private int n2 = 99; private int n1 = 66; public void say(){ //可以直接访问外部类的所有成员,包含私有的 // 如果内部类的成员和外部类成员重名,则遵循就进原则 System.out.println("Outer08 的 n1 = " + n1 + ",Outer08 的 name = " + name + "外部类 的 n1 = " + Outer08.this.n1); } } // 该方法返回一个 Inner08 实例 public Inner08 getInner08Instance(){ return new Inner08(); } //写方法 public void t1(){ //使用成员内部类 //创建成员内部类的对象,然后直接使用 Inner08 inner08 = new Inner08(); inner08.say(); System.out.println(inner08.n2); } }
4.静态内部类
说明:静态内部类是定义在外部类的成员位置,并且有 static 修饰
- 可以访问外部类的所有成员,包含私有的,但不能访问非静态成员
- 可以添加任意访问修饰符(public, protected, 默认 , private), 因为他的地位就是一个成员
- 作用域: 同其他成员,为整个类体
- 如果外部类和静态内部类成员重名时,静态内部类重名时默认遵循就进原则,如果想访问外部类名,(外部类名.成员)
package com.wxledu.innercass; public class StaticInnerClass { public static void main(String[] args) { Outer10 outer10 = new Outer10(); outer10.show(); //外部其他类-----> 访问 -----> 内部静态类 //方式一 //因为静态内部类,是可以通过类名直接访问的,(前提是满足访问条件) Outer10.Inner02 inner02 = new Outer10.Inner02(); inner02.say(); //方式二 //编写一个方法,可以返回静态类对象 Outer10.Inner02 inner021 = outer10.getInner02(); System.out.println("========"); inner021.say(); Outer10.Inner02 inner022 = Outer10.getInner02_(); System.out.println("******"); inner022.say(); } } class Outer10{//外部类 private int n1 = 10; private static String name = "张三"; static class Inner02{//静态内部类 public void say(){ System.out.println(name); // 不能访问外部类的非静态成员 //System.out.println(n1); } } public void show(){ // 外部类使用内部类 new Inner02().say(); } public Inner02 getInner02(){ return new Inner02(); } public static Inner02 getInner02_(){ return new Inner02(); } }
重点掌握匿名内部类的使用
本文作者:TomLove
本文链接:https://www.cnblogs.com/tomlove/p/17758391.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步