【Java】山外有山,类外还有类

【Java】山外有山,类外还有类

内部类是Java语言中的一种特性,它允许在另一个类中定义一个类。

内部类可以是静态的(不依赖于外部类的实例),也可以是非静态的(依赖于外部类的实例)。

在本篇博客中,我们将首先介绍内部类的使用特点,而后介绍几种内部类:

静态成员内部类

非静态成员内部类

局部内部类

匿名内部类

首先来看看内部类的使用特点:

image-20240505175218453

内部类的使用特点

  1. 访问控制:内部类可以直接访问外部类的成员,包括私有成员。
  2. 封装性:内部类可以隐藏在外部类中,对外不可见,增加了封装性。
  3. 继承:内部类可以继承外部类的属性和方法,也可以继承其他类或实现接口。
  4. 多态:内部类可以实现外部类不能实现的接口,实现多态。
  5. 生命周期:内部类的生命周期与创建它的外部类对象的生命周期相关联。
  6. 作用域:内部类的作用域限定在外部类中,只能在外部类中被访问。

什么时候使用内部类

当一个事物内部,还有一个部分需要完整的结构去描述,而这个内部的完整结构又仅为外部事物提供服务,则整个内部的完整结构,最好使用内部类。

例如:人类都有心脏,人类本身需要用属性去描述,人类内部的心脏,也需要特殊的属性和行为去描述,则心脏可以被定义成内部类,人类中的一个心脏类。

在实际的开发场景中,可能会有以下情形:

  1. 实现回调:使用匿名内部类来实现一个回调接口。
  2. 创建辅助类:创建一些仅供外部类使用的辅助类。
  3. 实现多态:通过内部类实现多态,特别是在设计模式中,如适配器模式、观察者模式等。

格式例如:

public class Outer {
    class Inner {
        // ...
    }
}

静态成员内部类

格式:直接在定义内部类的时候加上static关键字

public class A{
    static class B{
        
    }
}

注意:

  1. 内部类可以定义属性,方法,构造等
  2. 静态内部类可以被final或者abstract修饰,被final修饰之后,不能被继承,被abstract修饰之后,不能new
  3. 静态内部类,不能调用外部类的非静态成员
  4. 内部类还可以被四种权限修饰符修饰

调用静态内部类成员:

外部类.内部类 对象名 = new 外部类.内部类()

使用示例:

public class OuterClass {
    public static int staticField = 10;

    static class StaticInnerClass {
        void display() {
            System.out.println(staticField);
        }
    }

    public static void main(String[] args) {
        StaticInnerClass inner = new StaticInnerClass();
        inner.display();
        //或者
        OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();
        inner.display();
    }
}

非静态成员内部类

格式:

public class A{
    class B{
        
    }
}

调用非静态内部类成员:

外部类.内部类 对象名 = new 外部类().new 内部类()

使用示例:

public class OuterClass {
    private String outerField = "外部类字段";

    class NonStaticInnerClass {
        void display() {
            System.out.println(outerField);
        }
    }

    public void createInner() {
        NonStaticInnerClass inner = new NonStaticInnerClass();
        inner.display();
    }
}

OuterClass outer = new OuterClass();
outer.createInner();
//或者
OuterClass.NonStaticInnerClass inner = new OuterClass().new NonStaticInnerClass();

局部内部类

局部内部类可以定义在方法中,代码块中,构造中。

例如:

  1. 辅助计算类
public class Calculator {
    public void calculate() {
        class Helper {
            int add(int a, int b) {
                return a + b;
            }
        }

        Helper helper = new Helper();
        int result = helper.add(5, 10);
        System.out.println("计算结果是: " + result);
    }
}
  1. 假如要完成临时任务
public class TaskRunner {
    public void runTask() {
        class Task {
            void execute() {
                System.out.println("执行临时任务");
            }
        }

        Task task = new Task();
        task.execute();
    }
}

内部类、接口、抽象类、普通类作方法参数

接口作为方法参数返回值,传递实参时,传递实现类对象。

接口作为返回值类型返回,实际返回的是实现类对象。

示例代码如下:

package com.hamburger.innerclass;

public class main {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        method(mouse);
        USB usb = method01();
    }
    /*
        接口作为方法参数,传递实参时,传递实现类对象
     */
    public static void method(USB usb){
        usb.open();
    }

    public static USB method01(){
        Mouse mouse = new Mouse();
        return mouse;

    }
}
package com.hamburger.innerclass;

public interface USB {
    public abstract void open();
}
package com.hamburger.innerclass;

public class Mouse implements USB{
    public void open(){
        System.out.println("haha");
    }
}

抽象类

  1. 作为方法参数传递,传递实参时,传递的是其子类对象。
  2. 作为方法返回值类型返回,实际返回的是其子类对象。

普通类

  1. 作为方法参数传递,传递的是对象
  2. 作为方法返回值返回,返回的是对象

匿名内部类

匿名内部类,可以理解为没有显式声明出类名的内部类。它没有类名,通常用于创建一次性使用的类对象,特别是当需要快速实现某个接口或继承某个类时。

使用场景:我们如果想要实现接口,简单使用一次抽象方法,就需要:

创建一个实现类

实现这个接口

重写抽象方法

new实现类方法

如果我们只想单纯使用一次接口中的方法,能不能不要这么麻烦?

使用匿名内部类的方法:

  1. 创建实现类,实现接口
  2. 重写方法
  3. 创建实现类对象
  4. 调用方法

匿名内部类格式:

new 接口/抽象类(){
    重写方法
}.重写的方法();
===============================
类名 对象名 = new 接口/抽象类(){
    重写方法
}
对象名.重写的方法();

匿名内部类作为参数传递

package com.ham.niminginnerclass;
public class test {
    public static void main(String[] args){

        method(new USB() {
            @Override
            public void open() {
                System.out.println("lzy");
            }

            @Override
            public void close() {
                System.out.println("dyp");
            }
        }); 
    }
    public static void method(USB usb){
        usb.open();
        usb.close();
    }
}

package com.ham.niminginnerclass;

public interface USB {
    public abstract void open();
    public abstract void close();
}

匿名内部类的使用场景:

  1. 事件监听器:在需要为事件添加监听器时,可以利用匿名内部类快速实现接口中的方法。
  2. 线程的实现:创建线程时,可以匿名内部类实现Runnable接口。
  3. 临时任务:当需要临时实现某个接口,且该实现不需要复用时。
  4. 回调函数:在需要提供回调函数时,可以使用匿名内部类快速实现。
  5. 实现策略模式:在实现策略模式时,可以使用匿名内部类来定义不同的策略。

使用示例

  1. 当需要创建一个线程来执行特定的任务时,可以使用匿名内部类实现Runnable接口:
// 使用匿名内部类创建线程
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("线程运行中");
    }
}).start();
  1. 在对对象数组进行排序时,可能需要提供一个自定义的比较器,这时可以使用匿名内部类:
// 使用匿名内部类实现比较器
String[] strings = {"banana", "apple", "orange"};
Arrays.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});
  1. 当需要临时实现一个接口,并且这个实现不需要在其他地方复用时,可以使用匿名内部类:
// 使用匿名内部类实现临时任务
public void performTask() {
    Task task = new Task() {
        @Override
        public void execute() {
            System.out.println("执行临时任务");
        }
    };
    task.execute();
}

结语

参考文档如下:

【Java】内部类的使用方法和使用特点-CSDN博客

Java内部类详解(含:成员内部类、局部内部类、匿名内部类、静态内部类)-CSDN博客

36.内部类介绍_哔哩哔哩_bilibili

本篇作为复习内部类时的一部分笔记与总结,在之后仍会对本文不够详细之处作修订与补充。

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值