Java内部类分为 成员内部类 和 局部内部类
一、成员内部类也即实名内部类
又分为 非静态实名内部类 和 静态实名内部类
1、实名内部类可以看做外部类的成员 , 因而可以具有 private 、默认访问权限、
protected 、 public 四种封装性
2、对于非静态实名内部类,如果他的成员域具有静态属性,那么这个成员域必须同时具有
final属性 , 即 static final 同时存在 或者 同时不存在
3、对于非静态实名内部类,不能含有静态属性的成员方法
4、①非静态实名内部类
可以直接访问外部类的成员域和成员方法,如:
void Print()
{
System.out.println(Data_Outer) ;
}
其中 Print()是实名内部类的成员方法 , Data_Outer 是外部类的成员域
②静态实名内部类
可以直接访问外部类的静态成员,
对于外部类的非静态成员只能先建立外部类的实例对象,然后通过该对象来访问
5、当外部类与实名内部类中具有同名的成员域、局部变量时,可以用如下方式
区分
class Outer{
private int index = 100 ;
private class Innter {
private int index = 50 ;
void Print() {
int index = 30 ;
System.out.println(index) ; // 访问局部变量 index = 30 ;
System.out.println(this.index) ; // 访问内部类成员域 index = 50
System.out.println(Outer.this.index) ;
// 访问外部类成员域index=100;
}
}
}
6、不论是静态还是非静态的实例内部类,
①当在外部类的类体内部访问实例内部类的非静态成员时,格式都是:
Inner myInnner = new Inner(参数) ;
myInner.实名内部类成员域 ;
myInner.实名内部类成员方法 ;
②当在外部类的类体内部访问实例内部类的静态成员时,格式都是:
Inner.实名内部类静态成员域 ;
Inner.实名内部类静态成员方法 ; // Inner 是实名内部类类名
7、当在外部类的类体外定义该外部类的实名内部类的实例对象时分为两种:
①当为 静态实名内部类 时 , 格式如下 :
Outer.Inner myObject = new Outer.Inner(参数) ;
②当为 非静态实名内部类 时 , 格式如下:
Outer a = new Outer() ;
Outer.Inner my = a.new Inner() ;
8、当在外部类的类体外访问实名内部类的成员时,不论是静态内部类 还是 非静态内部类
①当访问 实名内部类 的 静态成员时,格式如下:
Outer.Inner.静态成员域 ;
Outer.Inner.静态成员方法 ;
②当访问 实名内部类 的 非静态成员时,格式如下 :
表达式.非静态成员 ;
//表达式指的是 7 中定义的实名内部类的实例对象的引用
9、这里有必要对静态实名内部类做一个详细的分析:
① 实际上通过上面的规则可知 , 静态实名内部类的使用方式与顶层类是一样的,
只是他定义在了外部类的内部,拥有了更多的封装属性而已
② 由 7 可知 静态实名内部类的实例化不像非静态实名内部类,静态实名内部类的实例化
不依赖于外部类是否已经实例化,这也就说明了①的正确性
同理 4 中的② 更加说明了 ① 的正确性
③ 所以静态实名内部类提供了一个非常好的机制,即只有外部类与内部类的访问控制
属性组合起来才能确定一个静态实名内部类内否被其他类访问,换句话说就是,
当外部类可以被访问的前提下 , 静态内部类才可能被访问 ;
这个特性在实际问题中是非常常见的
二、局部内部类
1、局部内部类就是定义在外部类的成员方法中的类,而且只能有默认的控制属性
2、局部内部类和成员内部类中的非静态实名内部类规则相似 ,
如果局部内部类中的成员域具有static属性,则必须同时具有final属性 ;
而且不能含有静态成员方法 ;
3、如果局部内部类和外部类没有继承关系,即局部内部类没有继承外部类,
那么 局部内部类访问外部类成员的权限 和 局部内部类所在的外部类的成员方法 对
外部类成员的访问权限是一致的
4、对于 3 要好好理解 , 局部内部类可以定义在外部类的非静态方法 和 静态方法
(如main)中,按照 3 的规则
① 当局部内部类(没有继承外部类)定义在外部类的非静态成员方法中时
局部内部类可以直接访问外部类的所有成员包括静态的和非静态的
② 当局部内部类(没有继承外部类)定义在外部类的静态成员方法中时
局部内部类只能直接访问外部类的静态成员;
如果要访问外部类的非静态成员,必须借助外部类的实例对象
5、局部内部类是可以 继承 和 实现接口 的
①局部内部类访问父类型的成员的权限和普通的继承关系没有分别
②按照① 值得注意的是, 如果局部内部类继承的正好是外部类的话 ,
那么不论局部内部类定义在外部类的静态还是非静态成员方法中
局部内部类都能直接访问继承过来的外部类的静态和非静态成员
6、还有一点是 ,局部内部类是定义在一个外部类的成员方法中的,Java规定
局部内部类只能访问所在方法中的final属性的局部变量
7、为什么会有6 的规定呢 , 实际上问题在于局部内部类的生命周期
由于局部内部类可以继承和实现接口,这样一个局部内部类的实例对象经向上
转型后,就可以作为一些方法的参数或返回值传出局部内部类当前所在的外部类的
成员方法,但是当前的外部类的方法中的那些非final局部变量的作用域不能
超过当前的方法体,所以传出去局部内部类对象是不能访问当前方法中的
非final局部变量的
三、匿名内部类
其实 匿名内部类 就是一种特殊的局部内部类 ,他也是定义在外部类的成员方法中的
,由于匿名内部类本身就是来继承和实现接口的,所以
要满足局部内部类关于继承的一些规则
1、匿名内部类的定义方式 :
父类型名 实例对象名 = new 父类名(参数)
{ 类体 } ; // 有分号
2、父类型可以是一个类、抽象类、接口 ,实际上定义的这个匿名类就是继承类父类型
3、常用的方式是,类体中重写或实现父类型中的相应方法 , 由于动态多态性,那么
上面的父类型的实例对象名这个父类的引用变量就可以调用这些重写的方法了
4、匿名内部类的规则和非静态的实名内部类的规则是相同的 ,
即 如果匿名内部类的成员域具有静态属性(static),那么必须同时具有final属性 并且不能有静态的成员函数