三种内部类的使用
内部类是什么?
内部类(inner class)是定义在另一个类中的类,相当于在你的大书包里又放进了小钱包。那么为什么需要内部类呢?
- 内部类可以对同一个包中的内容进行隐藏(你的钱包里有很多钱,如果装入书包里,别人就不知道你有钱包,你钱包里的钱也就得到了隐藏)。
- 内部类方法可以访问定义在这个类的作用域的数据,包括原有的私有的数据(private)。
成员内部类
什么是成员内部类?
成员内部类,也就是最常见最普通的内部类,和它的名字一样,它是作为外部类的一个成员而存在的。相当于类中的一个成员变量。
public class Outer{
private int a;
...
public class Inner{
...
}//Inner就是Outer的成员内部类,地位与定义变量差不多。
}
那么问题来了,每一个类中都多多少少会有一些方法,那么我们可以直接调用内部类中的方法吗?如果不行,又应该怎么办呢?👀
下面的的代码中我们看到当我们new了一个Outer后,无法找到Outer类中的show()方法。😳😳😳其实可以这么来理解,还是书包和钱包的例子:你的唯一一张银行卡在钱包里,你的钱包在书包里。当你需要在超市刷那张银行卡的时候,如果你仅仅打开书包,你无法刷你的银行卡(当然不能用手机🤣)。
如何调用内部类中的public方法?
public class test {
public static void main(String[] args) {
Outer.Inner out=new Outer().new Inner();//这样就可以啦,相当于打开了你的钱包
out.show();
}
}
class Outer {
class Inner{
public void show() {
System.out.print("Success!");
}
}
}
现在的内部类Inner中的show()方法是public的,也就是说外部可以随意调用(相当于你的钱包没有上锁,任何人打开书包后都可以打开钱包刷你的银行卡)。如果我们将show()设为私有private会发生什么呢?👀
我们发现出现了这样的错误The method show() from the type Outer.Inner is not visible
Inner中的show()将会变得不可见。
如何调用内部类中的private方法?
直接调用内部类中的private方法会出现The method show() from the type Outer.Inner is not visible
的错误,那么我们应该怎么调用呢?
我们回想一下我们当初是怎么调用私有变量的。
public class test {
public static void main(String[] args) {
Outer out=new Outer();
//System.out.print(a); -->会报错❌
out.show();//调用show()方法显示私有变量a
}
}
class Outer{
private int a=100;//这个a不能直接用
public void show(){
System.out.print(a);
}
}
对于私有变量a,我们想要在屏幕上显示出这个a的数值的时候我们需要调用一个public方法来显示它。
回过头来,似乎对如何调用这个私有方法这个问题有了一个比较明确的方向😉
public class test {
public static void main(String[] args) {
Outer out=new Outer();
out.method();
}
}
class Outer {
class Inner{
private void show() {
System.out.print("Success!");
}
}
public void method() {
Inner in=new Inner();
in.show();
}
}
局部内部类
什么是局部内部类?
什么是局部内部类呢?先上代码:
class Outer {
public void method(){
class Inner{
...
}
}
}
在一个方法中局部地定义一个类被称为局部内部类。
这里要注意的是,声明局部类时不能有访问说明符(即public或private)。局部类的作用域被限定在声明这个局部类的块中。
怎么使用局部内部类?
public class test {
public static void main(String[] args) {
Outer out =new Outer();
out.method();
}
}
class Outer {
public void method() {
class Inner{
public void show() {
System.out.print("Success!");
}
}
Inner in = new Inner();
in.show();
}
}
Inner in = new Inner(); in.show();
这块代码不要忘了。想一下如果少了这两行代码,直接在main中调用method()方法,这时候的method()有什么作用吗?它仅仅在内部类中定义了一个方法,并没有实现。
匿名内部类
什么是匿名内部类?
使用局部内部类的时候,假如只想创建这个类的一个对象,那再另外new一下似乎变得不必要。这时候匿名内部类(annoymous inner class)就出现了。这时候甚至不用为类指定名字。【匿名内部类是一种特殊的局部内部类】
匿名内部类的本质:一个继承了该类或者接口的子类匿名对象。
先定义一个Show接口,有一个show()方法。
package testpackage;
public interface Show {
void show();
}
既然匿名内部类是一种特殊的局部内部类,那class当然也要写到方法里头去咯。
package testpackage;
public class test {
public static void main(String[] args) {
Outer out =new Outer();
out.method();
}
}
class Outer {
public void method() {
new Show() {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.print("Success!");
}
};//注意这里有分号
}
}
到这一步,我们已经定义好了匿名内部类,也重写了Show接口中的show()方法,但这仅仅只是写好了,并没有真的让它show出来(这时候运行控制台上一定是空白的),那么我们应该怎么样在控制台上显示出Success呢?
怎么调用匿名内部类的方法?
我们回到匿名内部类的本质:一个继承了该类或者接口的子类匿名对象。
我们之前的代码:Object obj = new Object();
之后如果要调用Object中的方法,我们会这样做:obj.method();
。其中obj就是一个对象变量。既然都是对象,只不过匿名内部类没有属于自己的名字(555匿名内部类好可怜居然没有名字😖)那么匿名内部类是不是也可以点一下来调用方法呢?
package testpackage;
public class test {
public static void main(String[] args) {
Outer out =new Outer();
out.method();
}
}
class Outer {
public void method() {
new Show() {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.print("Success!");
}
}.show();//注意这里有分号
}
}
事实证明这样是正确的!
那么问题又来了,如果我们要输出好几次Success呢?难道我们要不停地写Ctrl+c、Ctrl+v(Command+c、Command+v)这段代码吗?显然不合理。下面是解决方法:
package testpackage;
public class test {
public static void main(String[] args) {
Outer out =new Outer();
out.method();
}
}
class Outer {
public void method() {
Show si=new Show() {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("Success!");
}
};
si.show();
si.show();
si.show();
}
}
对这个代码有一个地方一直在困扰我,虽然没怎么理解,但也只能勉强接受:Show si = new Show(){...};
Show不是一个接口吗?接口为什么能用new实例化呢?我找了许多资料,最终得出这样的结论:new Show() {}实际上并没有实例化Show接口,而是创建了一个实现了Show接口的匿名内部类,从而达到调用show()的目的。
. 总的来说就是:看似实例,实则没有实例。
关于匿名内部类
- 匿名内部类不能有构造器 由于构造器的名字必须与类名相同,而可怜巴巴🥺的匿名内部类连名字都没有,何来构造器呢?
- Lambda表达式 多年来,Java程序员习惯的做法是用匿名内部类实现事件监听器和回调。如今在Java8之后可以使用Lambda表达式简化繁琐的匿名内部类。