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 对象进行遍历。
所以,内部类 + 接口就很好的实现了多继承。
使用内部类的优势:
- 内部类可以继承父类、实现接口
- 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立
- 内部类提供了更好的封装,除了该外围类,其他类都不能访问
- 创建内部类对象的时刻并不依赖于外围类对象的创建
2. 如何使用内部类
2.1 成员内部类
之所以称之为“成员内部类”,是因为这个类是作为外部类的一个成员,就像成员变量、成员方法一样。如:
public class OuterClass {
// 成员变量
private String name;
// 成员方法
public void sleep() {
System.out.println("SLEEP ~~~");
}
// 成员内部类
private class InnerClass {
}
}
成员内部类的特点:
- 它可以使用
private
修饰,表示私有,只能在当前的外部类中使用
// 外部类
public class OuterClass {
// 内部类
private class InnerClass {
}
}
- 成员内部类编译后会生成一个 class 文件,例如:OuterClass$InnerClass。
内部类命名规则:外部类$内部类.class
构建成员内部类
那么,如何构建内部类呢?
方法有 2:
- 在外部类的非静态方法中 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);
}
}
- 通过外部类对象去构造一个内部类对象
构建规则:外部类. 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);
}
}
【总结】:
- 内部类可以直接调用外部类成员方法、属性。因为内部类中拥有了外部类对象的引用
private class VedioProcessTask {
// 启动任务
public void start() {
System.out.println(VedioProcess.this);
System.out.println("启动视频处理任务~~~");
printVedioInfo();
// 处理任务过程中
// 获取处理结果
processResult = new VedioProcessResult(1, "成功", "http://www.baidu.com");
}
...
}
方式:外部类名.this
成员内部类的使用场景
使用内部类,可以达到多继承的效果。
改造上面案例:
- 首先,将视频处理类抽象出一个父类:Process,再由 NewVedioProcess 类去继承;
- 将处理结果抽象出一个父类: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);
}
}
成员内部类就到这了~~~