内部类的主要作用:
1、内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。例如:有一个Cow这个类,Cow类需要组合一个CowLeg的属性,CowLeg属性只有在Cow类里才有效,离开了Cow类之后没有任何意义。这种情况下,就可把CowLeg定义成Cow的内部类,不允许其他类访问CowLeg。
2、内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。但是外部类不能访问内部类的实现细节,例如内部类的属性。
3、匿名内部类适用于创建哪些仅需要一次使用的类。
注意:外部类的上一级程序单元是包,所以它的两个作用域:同一个包和任何位置,因此其只需两个访问权限:包访问权限(省略访问控制符)和公开访问权限(public)。因此一个外部类不适用任何访问控制符修饰,则只能被同一个包中其他类访问。而内部类的上一级程序单元时外部类,它就具有四个作用域:同一个类、同一个包,父子类和任何位置,因此可以有四种访问控制权限:public、private、protected、省略访问控制符。
根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例等。
例如:public class TestStatic{
private class In{} //定义一个非静态的内部类,是一个空类
public static void main(String[] args){//外部类的静态方法
new In();//这行代码发生贬义异常,因为静态成员无法访问非静态成员
}
}
Java不允许在非静态内部类里定义静态成员。
例如:public class InnerNoStatic{
private class InnerClass{
/*
下面三个静态声明都将引发编译错误:非静态内部类不能有静态声明
*/
static{
System.out.println("======");
}
private static int inProp;
private static void test(){}
}
}
注意:静态内部类里不可以有静态初始化块,但可以包含普通初始化块。非静态内部类普通初始化块的作用与顶层类初始化块的作用完全相同。
静态内部类属于整个外部类,而不是单独属于外部类的某个对象。
注意:static不可修饰外部类,可以修饰内部类。原因:使用static修饰的成员属于类而不属于对象,而外部类的上一级程序单元是包,所以不能用static修饰。
静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,所以静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
静态内部类时外部类的一个静态成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类的对象作为调用者来访问静态内部类的实例成员。
Java允许接口里定义内部类,接口里定义内部类默认使用public static 修饰,也就是说接口内部类只能是静态内部类。
接口里也可以定义内部接口,接口里的内部接口时接口的成员,因此系统默认添加public static 两个修饰。当然,定义接口内部接口的意义不大,因为接口的作用是定义一个公共规范(暴露出来供大家使用),如果把这个接口定义成一个内部接口,就没意义了。
如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类尽在该方法里面有效。因此,局部内部类不能再外部类以外的地方使用,那么局部内部类也无需使用访问控制符和static修饰符修饰。
匿名内部类适合创建那种只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。
匿名内部类必须集成一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。
匿名内部类的两条规则:
1、匿名内部类不能使抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。
2、匿名内部类不能定义构造器,因为没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化块,通过实例初始化块来完成构造器需要完成的事情。
定义匿名内部类的格式:
new 父类构造器(实参列表)|实现接口()
{
//匿名内部类的类体部分
}
匿名内部类不能使抽象类,所以匿名内部类必须实现它的父类或者接口里所包含的所有抽象方法。
通过接口创建匿名内部类时,匿名内部类不能显式创建构造器,因此匿名内部类只有一个隐式的无参构造器,所以new接口后的括号里不能传入参数值。
通过继承父类来创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指的是拥有相同的形参列表。
如果匿名内部类需要访问外部类的局部变量,则必须使用final修饰符来修饰外部类的局部变量,否则系统将报错。
例如:interface A{
void test();
}
public class TestA {
public static void main(String[] args){
int age=0;
A a=new A()
{
public void test(){
System.out.println(age);//此句将提示错误:匿名内部类访问局部变量必须使用final修饰
}
};
}
}
解析:由于age变量没有使用final修饰,所以编译异常。