1、四种内部类
一个类的内部又完整的嵌套另一个类结构。被嵌套的类称为内部类(inner class)
内类的分类:
定义在外部类局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点!!!)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
1.1 局部内部类
局部内部类是定义在外部类的局部位置中,比如方法中,并且有类名
外部类调用局部内部类:
只能使用 外部类对象 调用 局部内部类所处方法,并且在方法中创建局部内部类的实例
public class OuterMain{
public static void main(String[] args) {
Outer outer = new Outer("李四");
//局部内部类所处的成员方法
outer.m2();
}
}
class Outer {//外部类
private String name; //属性
public Outer(String name){//构造器
this.name = name;
}
public void m1(){
System.out.println("外部类的成员方法m1()");
}
public void m2(){
class Inner {//局部内部类
private String name = "张三";
public void f1(){
//可直接访问外部类成员
m1();
//外部类和内部类的成员重名时,默认遵循就近原则
//访问外部类成员 使用 外部类名.this.成员名
System.out.println("内部类的name:"+ name);
System.out.println("外部类的name:"+ Outer.this.name);
}
}
//只能在方法中创建内部类的对象,然后调用方法
Inner inner = new Inner();
inner.f1();
}
}
类似一个局部变量
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,但可以使用final修饰
- 作用域:仅仅在定义它的方法或代码块中,因为局部内部类的地位相当于一个局部变量
- 局部内部类可以直接访问外部类的成员
- 外部其它类不能访问局部内部类(局部内部类的地位相当于一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)去访问
1.2 匿名内部类
本质是类,内部类,该类没有名字,同时还是一个对象
基于接口、类、抽象类的匿名内部类:
package inner;
/**
* @Author 孑然
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
//基于接口的匿名内部类
//底层分配类名:AnonymousInnerClass + $1
//jdk底层在创建匿名内部类AnonymousInnerClass$1后,立即就创建了
//AnonymousInnerClass$1的实例,并且把地址返回给 ia
IA ia = new IA() {
@Override
public void cry() {
System.out.println("老虎叫唤");
}
};
ia.cry();
System.out.println(ia.getClass());
//基于类的匿名内部类
//编译类型 Father
//运行类型 AnonymousInnerClass$2
Father father = new Father("王二"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
father.test();
//AnonymousInnerClass$2
System.out.println("father的运行类型:"+father.getClass());
//基于抽象类的匿名内部类
//编译类型:Animal
//运行类型:AnonymousInnerClass$3
Animal animal = new Animal(){
@Override
void test() {
System.out.println("匿名内部类重写了test方法");
}
};
animal.test();
System.out.println("animal的运行类型:"+animal.getClass());
}
}
interface IA {
void cry();
}
class Father {
public Father(String name){
}
public void test(){
}
}
abstract class Animal {
abstract void test();
}
使用细节:
- 匿名内部类的地位也相当于外部类的一个局部变量
- 成员变量与外部类的成员变量重名时,也是默认遵循就近原则
- 若想访问同名的外部成员,可使用(外部类名.this.成员)去访问
1.3 匿名内部类的最佳实践
当做实参直接传递,简洁高效
public class InnerClassExercise01 {
public static void main(String[] args) {
//使用匿名内部类传参调用f1();
f1(new IL() {
@Override
public void show() {
System.out.println("这是一幅名画...");
}
});
//传统方法,1.实现IL ,重写show方法,调用f1传入实现类对象
}
public static void f1(IL il){
il.show();
}
}
interface IL {
void show();
}
1.4 成员内部类
定义在外部类的成员位置:
package inner;
/**
* @Author 孑然
*/
public class OuterMain02 {
public static void main(String[] args) {
//外部类使用成员内部类的三种方式
Outer02 outer02 = new Outer02();
//1.相当于把new Inner02()看做outer02的一个成员
Outer02.Inner02 inner02 = outer02.new Inner02();
//2.在外部类中编写一个返回成员内部类实例的方法
Outer02.Inner02 inner02_1 = outer02.getInner02();
//3.第3 种写法
Outer02.Inner02 inner02_2 = new Outer02().new Inner02();
}
}
class Outer02 {//外部类
private int n1 = 10;
public String name = "张三";
class Inner02 {//成员内部类
public void say(){
//可以直接访问外部类的所有成员,包含私有的
System.out.println("n1="+n1+",name="+name);
}
}
public Inner02 getInner02(){
return new Inner02();
}
}
外部类调用成员内部类的三种方式:
//外部类使用成员内部类的三种方式
Outer02 outer02 = new Outer02();
//1.相当于把new Inner02()看做outer02的一个成员
Outer02.Inner02 inner02 = outer02.new Inner02();
//2.在外部类中编写一个返回成员内部类实例的方法
Outer02.Inner02 inner02_1 = outer02.getInner02();
//3.第3 种写法
Outer02.Inner02 inner02_2 = new Outer02().new Inner02();
若想访问同名的外部成员,同样使用(外部类名.this.成员)去访问
1.5 静态内部类
带有static修饰符的成员内部类,可以将其看做一个静态的成员变量
内部访问外部:
- 可以访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
外部访问内部:
public class OuterMain03 {
public static void main(String[] args) {
//外部其他类访问内部类
Outer03.Inner03 inner03 = new Outer03.Inner03();
}
}
class Outer03 {
public static class Inner03{
void say(){
System.out.println("内部类的say方法");
}
}
//外部类访问内部类通过调用f1()方法
public void f1(){
Inner03 inner03 = new Inner03();
inner03.say();
}
}
若想访问同名的外部成员,使用(外部类名.成员)即可