详解 内部类 —— 内部类 与 匿名内部类
在本人之前的篇博文《详解 抽象类》中,讲到的对抽象类的使用手段是:
1.继承抽象类,并且实现其抽象方法,产生新类(子类)
2.实例化这个子类,完成抽象方法的实现。
但是,对抽象类的使用手法并不是唯一的,还有一种更直接、更犀利的实现手段,但这种手段是建立在内部类的知识基础上的,所以,在讲这种手段前,本人有必要先讲解一下 内部类 这个知识点。
并且本人谈到:这篇博文中所要讲解的知识,将会在本篇博文中提现到作用。
那么,废话不多说,现在就开始本篇博文主题的讲解吧!
[toc]
内部类:
定义: 把类定义在其他类的内部,这个类就被称为内部类。
内部类 和 外部类 之间的访问特点:
访问特点:
- 内部类可以直接访问外部类的成员,包括私有。
- 外部类要访问内部类的成员,必须创建对象。
而我们可以根据内部类的位置,对内部类分为如下两类:
按照内部类位置分类
- 成员位置:
在成员位置定义的类,被称为成员内部类- 局部位置:
在局部位置定义的类,被称为局部内部类
而对于这两种内部类,他们的修饰符也略有差别:
首先是 成员内部类:
成员内部类的修饰符:
- private 为了保证数据的安全性
- static 为了方便访问数据
注意事项:
- 静态内部类访问的外部类数据必须用静态修饰
- 成员方法可以是静态的也可以是非静态的
接下来是局部内部类:
final修饰:
- 因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。
为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。注意事项:
JDK1.8之后,final会默认加上,不需要手动去加
那么,我们如何在 外部类中 直接访问内部类的成员呢?
外部类访问内部类成员的手段:
格式:
- 一般格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;- 成员内部类 被 静态修饰后:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
那么,本人还是通过一段代码来讲解内部类的使用方法:
OuterClass类:
package com.mec.about_inner.core;
public class OuterClass {
private int privateMember;
protected int protectedMember;
public int publicMember;
public OuterClass() {
//这里定义三种不同的权限修饰符的成员
privateMember = 1;
protectedMember = 2;
publicMember = 3;
}
//这里定义三种不同的权限修饰符的方法
private void privateFun() {
System.out.println("privateMember:" + privateMember);
}
protected void protectedFun() {
privateFun();
System.out.println("protectedMember:" + protectedMember);
}
public void publicFun() {
privateFun();
System.out.println("publicMember:" + publicMember);
}
public class InnerClass {
private int innerMember;
public InnerClass() {
innerMember = 4;
}
private void InnerFun() {
privateMember++;
protectedMember++;
publicMember++;
privateFun();
protectedFun();
publicFun();
System.out.println("innerMember:" + innerMember);
}
}
//外部类可以定义其内部类对象的成员
private InnerClass innerObject;
public void fun() {
//外部类可以实例化该成员,并且可根据内部类的对象,引用内部类的成员和方法
innerObject = new InnerClass();
innerObject.InnerFun();
System.out.println(innerObject.innerMember++);
}
}
上面代码的注意点,本人已经在注释中写清楚了,所以在这里不再进行详细解释。
在这里本人只提醒一点:
内部类中的任何成员和方法,都可以被直属外部类调用。
外部类中的任何成员和方法,都可以被其所包含的内部类调用。
但是,在这里,本人要展示下bin目录下所生成的*.class文件:
可见,这里额外生成了一个名为“OuterClass$InnerClass”的类,而这个名称,就表明这个类是在OuterClass类中的内部类InnerClass类。
那么,为什么本人在讲解直接使用抽象类的手段前,要讲解内部类呢?
那是因为,这种直接使用抽象类的手段,被称为“匿名内部类”
匿名内部类:
首先,本人来解释下,什么是匿名内部类:
定义:就是局部内部类的简化写法
匿名内部类也存在着特定的格式:
格式:
new 类名或者接口名(){
重写方法;
} ;
根据这个格式,我们大概能够看的出来:
所谓的匿名内部类 是一个继承了该类 或者 实现了该接口 的 子类匿名对象。
本人在这里再提醒一点:
在匿名内部类中出现的this,代表的是该匿名内部类 这个对象
现在,本人来给一个抽象类:
Bird类:
package com.mec.about_inner.core;
public abstract class Bird {
private String name;
public Bird(String name) {
this.name = name;
}
public abstract String cry();
public void print( ) {
System.out.println("(" + name + ")" + "的叫声:" + cry());
}
}
接下来,本人通过Test类,来展示直接使用抽象类的手段:
Test类:
package com.mec.about_inner.core;
public class Test {
public static void main(String[] args) {
//第一种手段的展示
Bird lark = new Bird("百灵鸟") {
@Override
public String cry() {
return "百灵既洽,祚我王国";
}
};
lark.print();
//第二种手段的展示
new Bird("乌鸦") {
@Override
public String cry() {
return "月影笼缁衣, 寒鸦枝上啼";
}
}.print();
//第三种手段的展示
new Bird("黄鹂") {
public Bird fun() {
System.out.println("这里是第三种调用抽象类的方法");
return this;
}
@Override
public String cry() {
return "烟红露绿晓风香,燕舞莺啼春日长";
}
}.fun().print();
}
}
这里对上面的代码做一些解释:
这三种手段,其实是一种手段,都利用了如下模式:
new 抽象类构造方法() {
抽象类的所有抽象方法的实现;
}
剩下的操作,都是建立于这中方式的基础上才产生的,但是本质是一样的。
下面,本人再来展示下现在的bin目录下的*.class文件:
可以看到,多生成了三个内部类,但是这三个内部类却没有有意义的名称,所以,这三个类被称为“匿名内部类”。
本人在这里做一下说明:
一个 匿名内部类 最好对应 一种 抽象方法的实现,这样使得我们的工具的功能更加单一化,在修改时不容易导致其他工具出错。
但是本人在这里想要提醒一句话,到了这里,Java的“工具化”思想想必是非常突出的了,所以,同学们时刻要注意无论Java学习到哪种程度,“工具化”思想都要时刻铭记,只有这样,才能真正地掌握Java地精髓!