------- android培训、java培训、期待与您交流! ----------
概述:
将类定义在一个类的内部,这个定义在其他类内部的类称为内部类,包含内部类的类称为外部类。
Java从JDK1.1开始引入内部类。
格式举例:
public class Outer{
private class Inner{}
}
内部类的作用:
1、内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类
2、内部类成员可以直接访问外部类的成员,包括私有数据,因为内部类被当成其外部类成员,
同一个类的成员之间可以相互访问。但外部类不能访问内部类的实现细节
3、匿名内部类适合用于创建那些仅需一次使用的类
访问特点:
1、内部类可以直接访问外部类的成员,包括私有成员
2、外部类要访问内部类中的成员必须创建内部类对象
内部类的分类:
内部类又分为成员内部类和局部内部类。
成员内部类是一种和属性、方法、构造器和初始化块的类成员,局部内部类和匿名内部类不是类成员。
成员内部类又分为两种:静态内部类和非静态内部类,使用static修饰的成员内部类是静态内部类。
非静态内部类:
非静态内部类作为外部类,所以可以使用任意访问修饰符如public、private、protect等修饰。
因为此类型内部类的上一程序单元是外部类,它就具有4个作用域:同一个类,同一个包,父子类和
任何位置,因此可以使用4中访问修饰符。
非静态内部类里可以直接访问外部类的成员,包括私有成员,当在非静态内部类访问某个变量时,
优先级从内而外:内部类方法的局部变量>内部类的成员变量>外部类的成员变量。
因此,如果外部类的成员变量、内部类的成员变量、内部类方法里的局部变量同名,则可以通过
使用外部类类名.this.、this作为限定来区分。而如果在外部类想要访问内部类则必须在外部类中
创建非静态内部类对象,根据静态不能访问非静态成员的原则,不允许在外部类的静态成员中直接
使用非静态内部类。
演示:
public class OuterClass {
String str = "这是外部类中的属性";
private class InnerClass
{
String str = "这是内部类中的属性";
/**
* 打印外部类成员和内部类成员的方法
*/
public void showField()
{
String str = "这是局部变量";
System.out.println("访问外部类成员:"
+ OuterClass.this.str);
System.out.println("访问内部类成员:" + this.str);
System.out.println("访问内部类方法中的局部变量:"
+ str);
}
}
/**
* 创建访问内部类的方法
*/
public void visitInnerClass() //如果加上static修饰,编译不通过
{
//创建内部类对象
InnerClass in = new InnerClass();
//调用打印方法
in.showField();
}
public static void main(String[] args) {
//创建外部类对象
OuterClass oc = new OuterClass();
oc.visitInnerClass();
}
}
编译上面程序,看到在文件所在路径生成了两个class文件,一个是OuterClass.class,
另一个是OuterClass$InnerClass.class,前者是外部类的文件,后者是内部类文件,
即成员内部类(包括静态和非静态)的class文件形式:外部类名$内部类名.class。
Java不允许在非静态内部类里定义静态成员,否则编译出错。
演示说明:
public class Outer{
private class Inner{
//下面三个静态声明都将引发编译错误
static{}
private static int a;
private static void show(){}
}
}
在外部类以外使用非静态内部类,则非静态内部类不能使用private修饰。语法如下:
外部类名.内部类名 标识符 = new 外部类名().new 内部类名();
演示:
public class Outer {
public class Inner
{
public void show()
{
System.out.println("这是内部类");
}
}
}
public class Test{
public static void main(String[] args) {
//在外部类以外创建内部类对象
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
静态内部类:
使用static来修饰的成员内部类称为静态内部类。根据静态成员不能访问非静态的成员的规则,
静态内部类不能访问外部类的实例成员,只能访问外部类的类成员(static修饰)。
即使是在静态内部类的实例方法也不能访问外部类的实例成员。
演示:
public class Outer{
private int age = 0;
private static class Inner{
public void show()
{
System.out.println(age); //编译出错
}
}
}
静态内部类里也可以直接访问外部类的静态成员,当在静态内部类访问某个静态属性时,
优先级也是从内而外:内部类的静态成员变量>外部类的静态成员变量。
因此,如果外部类的静态成员变量、内部类的静态成员变量同名,则可以通过使用
外部类类名.变量名、内部类名.变量名作为限定来区分。
演示:
public class Outer {
static String str = "这是外部类中的属性";
private static class Inner
{
private static String str = "这是内部类中的属性";
/**
* 打印外部类成员和内部类成员的方法
*/
public void showField()
{
//System.out.println(age);
String str = "这是局部变量";
System.out.println("访问外部类成员:" + Outer.str);
System.out.println("访问内部类成员:" + Inner.str);
System.out.println("访问内部类方法中的局部变量:"
+ str);
}
}
/**
* 创建访问内部类的方法
*/
public static void visitInnerClass()
{
//创建内部类对象
Inner in = new Inner();
//调用打印方法
in.showField();
}
public static void main(String[] args) {
//创建外部类对象
Outer oc = new Outer();
oc.visitInnerClass();
}
}
在外部类以外使用静态内部类,内部类也不能用private修饰,语法如下:
外部类名.内部类名 标识符 = new 外部类名.内部类名();
演示:
public class Outer {
public static class Inner
{
public void show()
{
System.out.println("这是内部类");
}
}
}
public class Test{
public static void main(String[] args) {
Outer.Inner in = new Outer.Inner();
in.show();
}
}
局部内部类:
如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在该方法里有效。
因此局部内部类不能使用任何修饰符,如果需要使用局部内部类定义变量、创建实例或派生子类,
那么都只能在局部内部类所在的方法内进行。
演示:
Public class Outer{
public static void main(String[] args){
Class Inner{
Int a;
}
Class InnerSub extends Inner{
Int b;
}
Inner i = new InnerSub();
i.a = 8;
}
}
编译上面程序,生成了三个class文件:Outer.class、Outer$1Inner.class、Outer$1InnerSub.class。
局部内部类的class文件比成员内部类的class文件多了一个数字,这是因为同一个类里不可能有两个
同名的成员内部类,而同一个类里则可能有一个以上同名的局部内部类(处于不同的方法中),
所以java为局部内部类的class文件名中增加了一个数字,作为区分。
匿名内部类:
匿名内部类适合创建只需一次使用的类,定义匿名内部类的格式如下:
new 父类构造器(实参列表) 或者 实现接口()
{
//实体部分
}
从定义格式可以看出,匿名内部类必须继承一个父类,或实现一个接口,有且继承或实现一个。
关于内部类的两条规则:
1:匿名内部类不能是抽象类,因为在创建匿名内部类的同时,会立即创建匿名内部类的对象,
因此不允许将匿名内部类定义成抽象类
2:匿名内部类不能定义构造器。因为匿名内部类没有类名。但可以定义实例初始化块。
匿名内部类最常见的创建方式是定义在接口中,
演示:
public class FileTest {
public static void main(String[] args) {
File file = new File("h:");
String[] strArr = file.list(new FilenameFilter()
{
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() &&
name.endsWith(".java");
}
});
for(String item : strArr)
{
System.out.println(item);
}
}
}
注意事项:
当创建匿名内部类是,必须实现接口或抽象父类里的所有抽象方法。如果匿名内部类和
局部内部类里需要访问外部类的局部变量,则必须使用final修饰符来修饰外部类的局部变量。
演示:
public class OuterClass {
public static void main(String[] args)
{
final int a = 20;
class InnerClass
{
public void show()
{
//如果不加final,此处报错
System.out.println(a);
}
}
}
}