内部类(Inner Class)
内部类的定义
一个.java文件中可以定义多个类吗?
答案是可以的。在一个Java文件中可以定义多个类,但是只能有一个public的类,而且public类的名字必须和文件名相同。例如,Java文件Outer.java中,下面这种写法是正确的。
public class Outer
{
public class Inner
{
}
}
class Other1
{
}
class Other2
{
}
有几点注意:
1、class前的修饰是非常有限的只能是:public、abstract或者final,别的都不行,否则会报错:Illegal modifier for the class XXX; only public, abstract & final are permitted。
2、可以没有public的class,但是如果有,那么public的类名必须和文件名相同,否则会报错:The public type XXX must be defined in its own file XXX.java。
3、只有public的类才可以被外部的类引用,这里的外部是指其他package中的类,非public的类也可以被同一个package中的其他类引用。但是,当其他package中的类引用非public类时,import语句编译时会报错:The type xxx.XXX is not visible。
4、编译时,一个.java文件中的多个类会编译成不同.class文件。
内部类
内部类不是在一个Java文件中定义的多个类,而是在一个类中,又定义了另外一个类。以下面的代码为例,Outer类被称为外部类,Inner类被称为内部类。在一个外部类中可以定义多个内部类。Outer.java文件在编译后将生成Outer.class和Outer$Inner.class两个文件。
public class Outer
{
public class Inner
{
}
}
内部类的分类
内部类可以分为四种:成员内部类、静态内部类、局部内部类和匿名内部类。其中,局部内部类并不常见,匿名内部类作为一种特殊的局部内部类,更为常见。
成员内部类
最常见的一种内部类的使用方法。内部类可以访问外部类中的成员变量,包括外部类私有的成员变量,内部类也可以访问。这也意味着:在内部类中含有对外部类对象的引用,Java编译器在创建内部类对象的时候,隐式的把外部类类对象的引用也传了进去并一直保存着。正因为内部类对象中包含了外部类对象的引用,所以在外部类之外想要创建内部类对象的话,必须先创建外部类对象,类似Outer.Inner inner2 = new Outer.Inner();的写法是错误的。
public class TestInnerClass
{
public static void main(String[] args)
{
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
}
}
在内部类中可以直接引用外部类的成员变量,如果内部类和外部类的成员变量相同,使用Outer.this.variable来引用。不仅在成员内部类中,在局部内部类和匿名内部类中也可以通过Outer.this获取外部类对象。注意:在成员内部类中,不能有静态数据,声明静态成员变量或者静态成员函数都会在编译时报错。
public class AppStart extends Activity
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Handler().postDelayed(new Runnable()
{
public void run()
{
Intent intent = new Intent(AppStart.this, PictureActivity.class);
startActivity(intent);
finish();
}
}, 2000);
}
}
静态内部类
静态内部类与成员内部类的区别就在于:静态内部类中不包含外部类对象的引用。而且,在静态内部类中可以含有静态数据。Android中的对话框就是静态内部类的一个例子。
AlertDialog.Builder builder = new AlertDialog.Builder(_context);
局部内部类
局部内部类和成员内部类的区别就在于:内部类放置的位置,不是直接放置在外部类中(和成员变量、成员函数平级),而是放置到一个方法之中。
注意:如果定义一个局部内部类,并且局部内部类使用了一个在外部定义的对象,那么要求其参数引用是final。
匿名内部类
顾名思义,匿名内部类就意味着创建一个没有名字的内部类,在处理一些按键事件时经常用到。
public class LActivity5 extends Activity
{
private Button button;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity5);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
}
});
}
}
有一点需要注意:匿名内部类因为没有名字,所以没有构造函数。