顶级类,内部类
顶级累(top level class),就是一个文件中最外面的类。内部类(nested class),就是一个类中的类
例如我们在file.java 有如下代码
package design;
public class Out1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
class Out2 {
class In{
};
}
其中的 Out1和Out2就是我们的顶级类,In就是Out2的内部类。
顶级类的访问权限修饰符只能是public 和默认(什么也不写)两种情况,写private 和protected会报错。public 所有类可以访问。默认只有同一个包中的类才能访问
因为对于顶级类来说是没有父类的所以private 和protected没有意义的所以java 把他们设计为从错误。
java 中的内部类
我们先拿《java 核心技术1》中的例子说明一下内部类的两个作用
class LinkedList {
public :
class Iterator {
public:
void insert(int x);
int erase();
//...
};
//...
private:
class Link {
public :
int * next;
int data;
};
//...
};
上面是c++中嵌套类的应用,充分说明类两种情况,命名控制和访问控制。Iterator类,是在public下的所以 我们可以在任何类中访问它而不用怕和别的类命名冲突。但是java 中有包的概念所以这个作用就不太明显了。而Link类是在private 下的所以我们只能在LinkedList类中访问它。这就起到了访问控制的目的。
上面我们简单的说了一下内部类的两个作用,现在我们详细另一个作用。
访问外部类的变量
学过c++的同学知道,c++嵌套类是不能访问外部类的非static 变量的。但是java 在上面的基础上还增加了这个功能。包括private成员和静态成员
class OutClass{
int var_out;
public class InnerClass{
//包括private成员和静态成员
int a=OutClass.this.var_out;
int b=var_out;
}
}
我们可以直接在内部类中访问外部类的变量,也可以使用外部类的类名.this访问外部类。
当然你需要注意变量隐藏的问题。
class OutClass{
int var_out;
public class InnerClass{
int var_out;
public void print(){
System.out.print(var_out);//本地的var_out
System.out.print(OutClass.this.var_out);//全局的
}
}
}
反过来错外部类访问内部类就比较难了,你要先创建内部类对象才能访问。
1如果外部类中使用内部类
class OutClass{
int var_out;
public class InnerClass{
public void print(){
System.out.print("InnerClass");//本地的var_out
}
}
public void f(){
new InnerClass().print();
}
}
2在非外部类中访问内部类
class OutClass{
int var_out;
public class InnerClass{
public void print(){
System.out.print("InnerClass");//本地的var_out
}
}
public void f(){
new InnerClass().print();
}
}
public class Test {
public static void main(String[] args) {
//第一种方式:
OutClass outter = new OutClass();
OutClass.InnerClass inner = outter.new InnerClass(); //必须通过Outter对象来创建
//第二种方式:
OutClass.InnerClass inner1 = outter.new InnerClass();
}
}
局部内部类
局部类就是写在函数中的类。且局部类和局部变量一样是不能有访问修饰符的(private public protected static)
public void f(){
class InnerClass{
}
}
因为局部类是在栈中的,所以内部类的生存周期受{}影响的。当我们在内部类使用外部类的变量时,双方的生命周期可能不在同一个时间线上,所以为了避免这个问题,java会在内部类中创建一个和外部类变量内容一样的变量。然而外部类的变量内容可能会被更改,可是内部类变量不会被更改,所以java 要求我们引用外部类变量时加上final 修饰符,
public void f(int y){
final int x=10;
class InnerClass{
public void f(){
System.out.println(y);
}
}
}
好消息,java1.8官方改进了Bain一起我们可以不用写这个final 了,
匿名内部类
我们写一个类时可以不用写类的名字。向下面这样。
public class OutClass{
public void f(int y){
class InnerClass{
public void f(){
C c=new C(2){
};//把继承C类的类赋值给c
}
}
}
}
class C{
public C(int x){
}
}
匿名内部类的这样写法注定它会在传递类参数时用的很多。
注意上面的细节,因为我们的匿名类时是没有名字的所以是我们的匿名类是没有构造函数的。所有的参数都会传递给父类的构造函数,
在java 1.8中匿名内部类有更好的实现叫做lambda表达式
http://blog.csdn.net/ioriogami/article/details/12782141/
静态内部类
还记得我们一开始说的c++嵌套类吗。静态内部类就和他们很像,不能访问外部类的变量。
public class staticclass {
int a;
static int b;
static class InnerClass{
public void f(){
System.out.println(a);//error
System.out.println(b);//ok
}
}
}
内部类的实现细节
http://www.cnblogs.com/dolphin0520/p/3811445.html
上面链接有内部类的详细实现信息。