🔥作者主页:小林同学的学习笔录
🔥小林同学的专栏:JAVA之基础专栏
目录
1.内部类
1.1 概述
1.1.1 什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类,其他称为外部其他类。可以把内部类理解成寄生,外部类理解成宿主。
1.1.2 什么时候使用内部类
一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用
-
人里面有一颗心脏。
-
汽车内部有一个发动机。
-
目的为了实现更好的封装性。
1.2 内部类的分类
按定义的位置来分
-
成员内部类,类定义在了成员位置 (类中方法外称为成员位置,无static修饰的内部类)
-
静态内部类,类定义在了成员位置 (类中方法外称为成员位置,有static修饰的内部类)
-
局部内部类,类定义在方法内
-
匿名内部类,没有名字的内部类,可以在方法中,也可以在类中方法外。
1.3 成员内部类
类定义在成员位置上
1.3.1 获取成员内部类对象的两种方式
- 方式一:外部直接创建成员内部类的对象
- 外部类.内部类 变量 = new 外部类().new 内部类();
- 方式二:在外部类中定义一个方法提供内部类的对象(一般用在内部类用private修饰才用到)
代码演示:
方式一:
public class Test {
public static void main(String[] args) {
// 宿主:外部类对象。
// Outer out = new Outer();
// 创建内部类对象。
Outer.Inner oi = new Outer().new Inner();
oi.method();
}
}
class Outer {
// 成员内部类,属于外部类对象的。
// 拓展:成员内部类不能定义静态成员。
public class Inner{
// 这里面的东西与类是完全一样的。
public void method(){
System.out.println("内部类中的方法被调用了");
}
}
}
方式二:
public class Outer {
String name;
private class Inner{
static int a = 10;
}
public Inner getInstance(){
return new Inner();
}
}
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
System.out.println(o.getInstance());
}
}
1.3.2 经典面试题
public class Test {
public static void main(String[] args) {
Outer.inner oi = new Outer().new inner();
oi.method();
}
}
class Outer { // 外部类
private int a = 30;
// 在成员位置定义一个类
class inner {
private int a = 20;
public void method() {
int a = 10;
System.out.println(???); // 10 答案:a
System.out.println(???); // 20 答案:this.a
System.out.println(???); // 30 答案:Outer.this.a
}
}
}
执行原理:
1.4 静态内部类
静态内部类可以直接访问外部类的静态成员。
静态内部类不可以直接访问外部类的非静态成员,如果要访问需要创建外部类的对象。
静态内部类中没有虚拟机所创建的Outer.this
如何调用静态内部类的方法?
- 非静态方法:创建对象,并调用方法
- 静态方法:外部类名.内部类名.方法名()
1.4.1 静态内部类对象的创建格式
外部类.内部类 变量 = new 外部类.内部类构造器;
代码演示:
// 外部类:Outer01
class Outer01{
private static String sc_name = "小白";
private String sc_age = 24;
// 内部类: Inner01
public static class Inner01{
// 这里面的东西与类是完全一样的。
private String name;
public Inner01(String name) {
this.name = name;
}
public void showName(){
System.out.println(this.name);
// 拓展:静态内部类可以直接访问外部类的静态成员。
System.out.println(sc_name);
//访问外部类的非静态的变量需要创建外部类的对象
Outer01 outer01 = new Outer01();
System.out.println(outer.sc_age);
}
}
}
public class InnerClassDemo01 {
public static void main(String[] args) {
// 创建静态内部类对象。
// 外部类.内部类 变量 = new 外部类.内部类构造器;
Outer01.Inner01 in = new Outer01.Inner01("张三");
in.showName();
}
1.5 局部内部类
将内部类定义在方法里面就叫做局部内部类,类似于方法中的局部变量
外部类是无法直接获取局部内部类的,需要创建该类的对象,然后再进行使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
代码示例:
public class Outer {
private int outerField = 10;
public void outerMethod() {
final int localVar = 20;
//局部内部类
class LocalInner {
void display() {
System.out.println("Outer Field: " + outerField);
System.out.println("Local Variable: " + localVar);
}
}
//外部类获取内部类信息,需要创建对象
LocalInner inner = new LocalInner();
inner.display();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.outerMethod();
}
}
1.6 匿名内部类
1.6.1 引出匿名内部类
正常类:
匿名内部类(Student被匿名):
代码演示:
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 使用匿名内部类对象,并且调用匿名内部类里面的方法
new Swim() {
@Override
public void swimming() {
System.out.println("自由泳...");
}
}.swimming();
// 接口 变量 = new 实现类(); // 多态,走子类的重写方法
Swim s2 = new Swim() {
@Override
public void swimming() {
System.out.println("蛙泳...");
}
};
s2.swimming();
s2.swimming();
}
}
注意:
new Swim(){
@Override
public void swim() {
System.out.println("Demo01匿名内部类");
}
};
这样的话是不会有打印数据的,因为整体只是一个匿名内部类对象,需要再去调用相应的成员
匿名内部类字节码文件反编译看到的效果
实际案例:
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("11");
list.add("12");
list.add("13");
//下面就是一个匿名内部类
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
}
反编译之后
1.6.2 匿名内部类用处
匿名内部类在Java中有着一些重要的用途,其中包括:
-
简化代码:使用匿名内部类可以减少代码量,避免编写大量的类定义。
-
事件处理器:在GUI编程中常常使用匿名内部类来实现事件处理器,如按钮点击事件、菜单项选择等。
-
回调函数:匿名内部类也可以用作回调函数的实现,例如对异步任务的处理。
-
接口实现:如果只需要使用接口的一次实例,可以直接使用匿名内部类来实现接口的抽象方法。
-
方法重写:可以在匿名内部类中重写父类或接口的方法,以实现特定的逻辑。
总之,匿名内部类提供了一种简洁、灵活的方式来实现某些具体功能,通常用于临时、一次性的场景中。
1.6.3 匿名内部类的使用场景
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 普通方式传入对象
// 创建实现类对象
Student s = new Student();
goSwimming(s);
// 匿名内部类使用场景:作为方法参数传递
Swim s3 = new Swim() {
@Override
public void swimming() {
System.out.println("蝶泳...");
}
};
// 传入匿名内部类
goSwimming(s3);
// 完美方案: 一步到位
goSwimming(new Swim() {
public void swimming() {
System.out.println("大学生, 蛙泳...");
}
});
goSwimming(new Swim() {
public void swimming() {
System.out.println("小学生, 自由泳...");
}
});
}
// 定义一个方法,模拟请一些人去游泳
public static void goSwimming(Swim s) {
s.swimming();
}
}
总结: