一:局部内部类
1.局部内部类是定义在外部类的局部位置,通常在方法中
(1)局部内部类可以直接访问局部外部类的所有成员,包括私有的,如下所示
(2)局部内部类不能用访问修饰符修饰{ 因为他是一个局部变量 },但是可以用final修饰
(3)作用域:仅仅在定义它的方法或代码块中,如下面这个类只能在m1方法中使用,相当于一个局部变量
(4)如果外部类和内部类的成员重名,默认遵循就近原则
(5)如果要访问外部类的成员则只要使用(外部类名.this.成员)去访问
*外部类名.this实际上是外部类的一个对象,谁在调用内部类所在的方法/代码块, 谁就是这个对象
二:匿名内部类:
1.定义位置:方法体或代码块中
为什么需要匿名内部类?
A:为了简化开发
比如有一个接口要去使用那么需要创建很多类去实现这个接口而且用完了这些类还留着
于是有了
1.基于接口的匿名内部类
外部类Outer{
Interface A{
pulic void cry();
}
语法:
A(接口名) tiger(对象名) = new A(接口名) { 需要实现的方法 }
}
tiger 的编译类型 ? A
tiger 的运行类型 ? 就是匿名内部类 Outer$1(外部类名加 $1 )
我们看底层 系统会分配 类名 Outer$1
class Outer$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
jdk 底层在创建匿名内部类 Outer$1 , 立即马上就创建了 Outer04$1 实例,并且把地址返回给tiger
匿名内部类使用一次,就不能再使用
但是内部类创建的实例对象实例tiger可以一直使用
2.基于类的匿名内部类
外部类Outer{
class Father {
public Father(String name) { //构造器
}
public void test() { }//方法
语法
A(父类名) son (对象名) = new Father(构造器参数) { 需要重写的方法 /可以不重写 } ;
}
1. father 编译类型 Father
2. father 运行类型 Outer$2 (在已经有一个匿名内部类的前提下)
假如没有花括号的话,那么运行类型就是Father
3. 底层会创建匿名内部类
class Outer$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}
4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
};
System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
father.test();
为什么匿名内部类不能调用自己的特有方法?
因为匿名内部类实际上继承了父类Father,如果要调用特殊方法那么需要向下转型
又因为子类类名不存在或者说无法使用所以匿名内部类不能使用自己的特殊方法
2.5基于(抽象)类的匿名内部类
和基于类的匿名内部类差不多,但是花括号中必须重写方法
三:成员内部类
成员内部类也可以直接访问外部类的所有成员包括私有的
成员内部类作用域在Outer03中,外部类的成员方法可以访问
因为是成员,所以可以加访问修饰符
其他外部类访问内部类的两种方式
(1):Outer(外部类名) . Inner(内部类名) inner01(内部对象名) = outer(外部类对象名) . new Inner();(内部类构造器)
或者直接 外部类对象名 . new 内部类构造器
相当于把new出来的东西当做outer的一个成员,不用特别纠结
(2)通过外部类的方法返回一个内部类实例
Outer(外部类名) . Inner(内部类名) inner02(内部对象名)= outer(外部类对象名) . getInner();
public Inner getInner (){
return new Inner;
}
四:静态内部类
1.定位在成员位置
2.有static修饰
3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
5. 作用域 :同其他的成员,为整个类体
6.如果外部类和静态内部类的成员重名时,静态内部类访问的时候
默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
因为只能访问静态成员所以只需要外部类名不需要外部类名.this这样的对象实例来调用