你可以像
private String data这样定义一个“平行的”成员内部类:
private class Inner
具体看下面的例子: Outter.java:
public class Outter {
// 成员变量data
private String data = "外部数据";
//定义一个内部类
private class Inner {
public void innerPrint () {
System.out.println(data);
}
}
// 外部类的方法, new一个内部类的实例并调用其innerPrint方法
public void outterPrint () {
Inner i = new Inner();
i.innerPrint();
}
}Test.java:
public class Test {
public static void main (String [] args) {
Outter o = new Outter();
o.outterPrint();
}
}结果输出:
外部数据看来这还是能达到我们预期的效果的:由于将Inner内部类设为private,它变得只对我们当前的外部类Outter类可见,我们成功地把它"隐藏"在了Outter类内部,与此同时,它还自由地访问到了Outter类的私有成员变量data
两个this
虽然上面的例子看起来挺简单的,但实际上内部类的作用机制还是比较复杂的。
让我们对上面成员内部类处理的场景做些思考:我们的Inner内部类仅仅只在outterPrint方法中使用了一次:
public void outterPrint () {
Inner i = new Inner();
i.innerPrint();
} 那么我们能不能把Inner内部类直接定义在outterPrint的内部呢?这样的话,它就能更好地隐藏起来,即使是类Outter中除outterPrint外的方法,也不能访问到它:
现在的Outter的类看起来像这样:
public class Outter {
public void outterPrint () {// 外部类方法
class LocalInner { // 局部内部类
public void innerPrint () { }
}
LocalInner i = new LocalInner(); // 实例化局部内部类
i.innerPrint();
}
}相比于成员内部类,局部内部类多了一项能访问的数据,那就是局部变量(由外部类方法提供)
成员内部类:外部类数据,内部类数据 局部内部类: 外部类数据,内部类数据, 局部数据
具体示例如下:
Outter.java
public class Outter {
private String data = "外部数据"; // 外部类数据
public void outterPrint (final String localData) { // 局部数据
class LocalInner {
private String data = "内部数据"; // 内部类数据
public void innerPrint () {
System.out.println(Outter.this.data); // 打印外部类数据
System.out.println(this.data); // 打印内部类数据
System.out.println(localData); // 打印局部数据
}
}
LocalInner i = new LocalInner();
i.innerPrint();
}
}Test.java:
public class Test {
public static void main (String [] args) {
Outter o = new Outter();
o.outterPrint("局部数据");
}
}结果输出:
外部数据
内部数据
局部数据局部类所使用的外部类方法的形参必须用final修饰
这里要注意一点, 局部类所使用的外部类方法的形参必须用final修饰,否则会编译不通过,也就是说传入后不许改变
例如对于下面outterPrint方法中的LocalInner
public void outterPrint (final String data) {
class LocalInner {
public void innerPrint () {
// 使用 data
}
}
}编译之后大概长这样:
public class Outter$LocalInner{
public LocalInner(String data){
this.LocalInner$data = data; // 对于使用的data做了一次拷贝
}
public void innerPrint (){ /* 使用 data */ }
}这里要注意的是:
public void outterPrint (String data) {// 没加上final
class LocalInner {
public void changeData () {
data = "我想修改data的值"; // 在这一行编译报错
}
}
}提示:
Cannot refer to a non-final variable data inside an inner class defined in a different method
Outter.java
public class Outter {
public void outterPrint (final String [] data) {
class LocalInner {
public void innerPrint () {
data[0] = "堂而皇之地修改它!!"; // 修改数据
System.out.print(data[0]); // 输出修改后的数据
}
}
LocalInner i = new LocalInner();
i.innerPrint();
}
} Test.java:
ulic class Test {
public static void main (String [] args) {
Outter o = new Outter();
String [] data = new String [1];
data[0] = "我是数据";
o.outterPrint(data); // 修改数据并且输出
}
}结果输出:
堂而皇之地修改它!!
【注意】局部类不能用public或private访问符进行声明!!
回到顶部
匿名内部类
倘若我们再把局部内部类再深化一下, 那就是匿名内部类
匿名内部类的使用方式
new [超类/接口] { /* 类体 */ }
让我们看看下面这个例子: Other.java:
public class Other { } Outter.java:
public class Outter {
public void outterPrint (String data) {
Other o = new Other() { }; // 匿名内部类
}
}何谓之匿名?
“诶,不是说好的匿名吗? 那么为什么还有个Other的类名呢?”
Other o = new Other() { /* 匿名内部类的类体 */ };
实际上,这里的Other并不是我们的匿名内部类,而是我们匿名内部类的超类,上面一行代码其实相当于(用成员内部类来表示的话)
// annoymous翻译为匿名
public class Outter {
private class annoymous extends Other{ }
public void outterPrint () {
Other a = new annoymous();
}
}
同时要注意,我们在使用匿名内部类的方式,是在定义一个内部类的同时实例化该内部类:
new Other() { /* 匿名内部类的类体 */ }; // new操作和定义类的代码是紧紧结合在一起的匿名函数的作用
用匿名函数的作用在于在一些特定的场景下写起来很简单,例如事件监听器:
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) { }
};
避免了再创建另外一个类文件