【内部类】JAVA 中的四大内部类【上】

1. 内部类简介

什么是内部类?

可以将一个类的定义放在里另一个类的内部,这就是内部类。

那么,内部类有什么特点呢?

广义上,我们将内部类分为四种:成员内部类、局部(方法)内部类、静态内部类、匿名内部类。

在这里插入图片描述
如:

// 外部类
public class OuterClass {

    // 内部类
    class InnerClass {
        
    }
}

那么,为什么要使用内部类呢?

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。——《Think in java》

简单来说,内部类拥有类的基本特征(可以继承父类,实现接口)。在实际问题中,我们会遇到一些接口无法解决或难以解决的问题,此时,我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。

查看 HashMap 源码:

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
	...
	
	// 内部类
	static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
        ...
    }

Node 就是 HashMap 中的内部类,它是实现链表结构所需要的类

还有其它内部的迭代器类:

abstract class HashIterator {
    Node<K,V> next;        // next entry to return
    Node<K,V> current;     // current entry
    int expectedModCount;  // for fast-fail
    int index;             // current slot
    ...
}

final class KeyIterator extends HashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().key; }
}

final class ValueIterator extends HashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }
}

使用迭代器可以对 Map 对象进行遍历。

所以,内部类 + 接口就很好的实现了多继承。

使用内部类的优势:

  1. 内部类可以继承父类、实现接口
  2. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立
  3. 内部类提供了更好的封装,除了该外围类,其他类都不能访问
  4. 创建内部类对象的时刻并不依赖于外围类对象的创建

2. 如何使用内部类

在这里插入图片描述


2.1 成员内部类

之所以称之为“成员内部类”,是因为这个类是作为外部类的一个成员,就像成员变量、成员方法一样。如:

public class OuterClass {
    // 成员变量
    private String name;
    // 成员方法
    public void sleep() {
        System.out.println("SLEEP ~~~");
    }

	// 成员内部类
    private class InnerClass {

    }
}

成员内部类的特点:

  1. 它可以使用 private修饰,表示私有,只能在当前的外部类中使用
// 外部类
public class OuterClass {
    
    // 内部类
    private class InnerClass {
        
    }
}
  1. 成员内部类编译后会生成一个 class 文件,例如:OuterClass$InnerClass。

内部类命名规则:外部类$内部类.class

构建成员内部类

那么,如何构建内部类呢?

方法有 2:

  1. 在外部类的非静态方法中 new 一个内部类对象
public class OuterClass {

    public InnerClass getInnerClassObj() {
        return new InnerClass();
    }

    private class InnerClass {

    }

    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        InnerClass innerClassObj = outerClass.getInnerClassObj();
        // com.zzc.memberinnerclass.OuterClass$InnerClass@4141d797
        System.out.println(innerClassObj);
    }
}
  1. 通过外部类对象去构造一个内部类对象

构建规则:外部类. new 内部类名();

public class OuterClass {

    private class InnerClass {

    }

    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        InnerClass innerClass = outerClass.new InnerClass();
    }
}

成员内部类案例

场景:使用成员内部类处理某一个视频

视频处理类分析:

  • 视频处理任务 内部类:只会在视频处理类中使用,定义为 private
  • 处理结果 内部类:会在视频处理类之外使用,定义为 public

代码如下:
在这里插入图片描述

视频类:

// 视频类
public class Vedio {
    // 名称
    private String name;
    // 网址
    private String webSite;
    // 类型
    private String type;

    public Vedio(String name, String webSite, String type) {
        this.name = name;
        this.webSite = webSite;
        this.type = type;
    }
    ...
}

视频处理类:

public class VedioProcess {

    // 需要处理的视频
    private Vedio vedio;

    // 处理过后的结果
    private VedioProcessResult processResult;

    public VedioProcess(Vedio vedio) {
        this.vedio = vedio;
    }

    // 打印要处理的视频信息
    public void printVedioInfo() {
        System.out.println(vedio);
    }

    // 处理视频
    public void process() {
        VedioProcessTask task = new VedioProcessTask();
        task.start();
    }

    // 视频处理任务内部类
    private class VedioProcessTask {
        // 启动任务
        public void start() {
            System.out.println("启动视频处理任务~~~");
            printVedioInfo();
            // 处理任务过程中
            // 获取处理结果
            processResult = new VedioProcessResult(1, "成功", "http://www.baidu.com");
        }

        // 终止任务
        public void cancel() {
            System.out.println("终止视频处理任务~~~");
        }
    }

    // 处理结果内部类
    public class VedioProcessResult {
        // 处理结果  1:成功;0:失败
        private int code;
        // 结果信息
        private String msg;
        // 处理过后的新网址
        private String newWebsite;

        public VedioProcessResult(int code, String msg, String newWebsite) {
            this.code = code;
            this.msg = msg;
            this.newWebsite = newWebsite;
        }

        @Override
        public String toString() {
            return "VedioProcessResult{" +
                    "code=" + code +
                    ", msg='" + msg + '\'' +
                    ", newWebsite='" + newWebsite + '\'' +
                    '}';
        }
    }

    //getter()/setter()
}

测试类:

public class Test {

    public static void main(String[] args) {
        Vedio vedio = new Vedio("【内部类】JAVA 中的四大内部类【上】", "http://taobao.com", "avi");
        VedioProcess vedioProcess = new VedioProcess(vedio);
        vedioProcess.process();
        VedioProcess.VedioProcessResult processResult = vedioProcess.getProcessResult();
        System.out.println(processResult);
    }
}

【总结】:

  1. 内部类可以直接调用外部类成员方法、属性。因为内部类中拥有了外部类对象的引用
private class VedioProcessTask {
    // 启动任务
    public void start() {
        System.out.println(VedioProcess.this);
        
        System.out.println("启动视频处理任务~~~");
        printVedioInfo();
        // 处理任务过程中
        // 获取处理结果
        processResult = new VedioProcessResult(1, "成功", "http://www.baidu.com");
    }
    ...
}

方式:外部类名.this


成员内部类的使用场景

使用内部类,可以达到多继承的效果。

改造上面案例:

  1. 首先,将视频处理类抽象出一个父类:Process,再由 NewVedioProcess 类去继承;
  2. 将处理结果抽象出一个父类:ProcessResult,再由 VedioProcessResult 类去继承
public abstract class Process {
    abstract void process();
    abstract ProcessResult getProcessResult();
}
public class NewVedioProcess extends Process {

    // 需要处理的视频
    private Vedio vedio;

    // 处理过后的结果
    private ProcessResult processResult;

    public NewVedioProcess(Vedio vedio) {
        this.vedio = vedio;
    }

    // 打印要处理的视频信息
    public void printVedioInfo() {
        System.out.println(vedio);
    }

    // 处理视频
    @Override
    public void process() {
        VedioProcessTask task = new VedioProcessTask();
        task.start();
    }

    // 视频处理任务内部类
    private class VedioProcessTask {
        // 启动任务
        public void start() {
            System.out.println(NewVedioProcess.this);
            System.out.println("启动视频处理任务~~~");
            printVedioInfo();
            // 处理任务过程中
            // 获取处理结果
            processResult = new VedioProcessResult(1, "成功", "http://www.baidu.com");
        }

        // 终止任务
        public void cancel() {
            System.out.println("终止视频处理任务~~~");
        }
    }

    // 处理结果内部类
    public class VedioProcessResult extends ProcessResult{

        public VedioProcessResult(int code, String msg, String newWebsite) {
            this.code = code;
            this.msg = msg;
            this.newWebsite = newWebsite;
        }

        @Override
        public String toString() {
            return "VedioProcessResult{" +
                    "code=" + code +
                    ", msg='" + msg + '\'' +
                    ", newWebsite='" + newWebsite + '\'' +
                    '}';
        }
    }

    public Vedio getVedio() {
        return vedio;
    }

    public void setVedio(Vedio vedio) {
        this.vedio = vedio;
    }

    @Override
    public ProcessResult getProcessResult() {
        return processResult;
    }

    public void setProcessResult(ProcessResult processResult) {
        this.processResult = processResult;
    }
}
public class ProcessResult {

    // 处理结果  1:成功;0:失败
    protected int code;
    // 结果信息
    protected String msg;
    // 处理过后的新网址
    protected String newWebsite;

    public ProcessResult() {
    }

    public ProcessResult(int code, String msg, String newWebsite) {
        this.code = code;
        this.msg = msg;
        this.newWebsite = newWebsite;
    }
}

测试:

public class Test {

    public static void main(String[] args) {
        Vedio vedio = new Vedio("【内部类】JAVA 中的四大内部类【上】", "https://editor.csdn.net/md?articleId=118712190", "avi");
        Process process = new NewVedioProcess(vedio);
        process.process();
        NewVedioProcess.VedioProcessResult processResult = (NewVedioProcess.VedioProcessResult)process.getProcessResult();
        System.out.println(processResult);
    }
}

成员内部类就到这了~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值