**初识内部类
内部类就是一个类的声明不在顶层类(与Java文件名相同的类相同层级),而是被嵌套在其他类或者其他方法当中的类。相当于这个类被其他代码环绕。
一般来说,内部类就分四种:成员内部类、局部内部类、匿名内部类和静态内部类。
1、成员内部类
成员内部类:顾名思义,就是这个类(B)身处某一个类(A)的内部,且这个类(B)像其他成员(属性和方法)一样,可以自由调用外部类(A)的属性和方法。
这里涉及了两个类,两个类的属性和方法,身处外部的A类和身处内部的B类,那么A就是B的外部类,而B就是A的成员内部类。
示例:
public class Outer { //外部类
public String name = "老王";
private void print(){}
//成员内部类
class Inner11 {
}
}
}
- 类比类中的其他成员,成员内部类可以用任意访问权限修饰符修饰:(public, protected, default, private)。
成员内部类可以无条件访问外部类的属性和方法,包括私有域的属性和方法。
//外部类Outer public class Outer { public String name = "老王"; private double age = 99; static int id = 20210423; final String status = "loser"; private void print(){ System.out.println("外部类私有方法"); } //成员内部类 class Inner11 { public String name = "老王.11"; private double weight = 200.11; //内部类方法 public void getOuterFields(){ //内部类直接拿外部类属性与方法,不需要创建外部类对象 System.out.println("属性名相同,用`Outer.this.XX`拿到外部类属性:" + Outer.this.name); //Outer.this.XX 可以拿到外部类所有非static的属性 System.out.println("属性名相同时,默认输出内部类属性:"+ weight); System.out.println("内部类直接访问外部类的私有属性:"+ age); System.out.println("内部类直接访问外部类的静态属性:"+ id); System.out.println("内部类直接访问外部类的常量:"+ status); print(); } } } //测试类 class Test { public static void main(String[] args) { Outer.Inner11 inner11= new Outer().new Inner11(); inner11.getOuterFields(); // } } //输出: 属性名相同,用`Outer.this.XX`拿到外部类属性:老王 属性名相同时,默认输出内部类属性:200.11 内部类直接访问外部类的私有属性:99.0 内部类直接访问外部类的静态属性:20210423 内部类直接访问外部类的常量:loser 外部类私有方法
当内部类属性名或方法名与外部类重叠(相同)时,程序默认调用内部类的属性和方法,这时若想访问外部类的属性方法,要用以下语法格式访问:
Outer.this.成员变量 Outer.this.成员方法
成员内部类是依附在外部类里面的,因此想创建内部类就得先创建外部类。创建内部类的语法格式:
外部类.内部类 内部类名 = new 外部类().new 内部类() //必须先创建外部类 new Outer() Outer.Inner inner = new Outer().new Inner();
成功创建内部类后就可以正常的访问内部类的属性和方法了。
class Test { public static void main(String[] args) { Outer.Inner11 inner11= new Outer().new Inner11(); System.out.println(inner11.name); //inner的属性 inner11.getOuterFields(); //inner的方法 } }
外部类要访问内部类的属性和方法,必须先实例化内部类,再通过内内部类的引用间接访问其元素。
//外部类访问内部类成员, public void test(){ Inner11 in = new Inner11(); in.getOuterFields(); }
2、局部内部类
局部内部类,与方法相关,如果一个类定义在一个方法或者作用域里,那么这个类就是局部内部类。
局部内部类的格式如下:
class Outer{ //属性 //方法 public void method() { //局部内部类 class Innter{ //方法中再定义一个类 //内部类的方法 //内部类的属性 } } }
因为局部内部类是在方法里,可以理解为是跟方法的局部变量一样,不能有public、protected、private、static等修饰符。
- 与成员内部类不一样的是,局部内部类对外部类完全隐藏。除了包住这个类的方法或作用域外,其他地方都不能访问。
因为方法可以有返回值,所以外部类可以通过方法的返回值得到内部类的引用。但方法的声明就要先确定返回值的类型,而局部内部类不能被方法外部识别。所以要拿到方法里面的类,这个返回值的类型一定只能是内部类的父类引用,而内部类一定为某个类的子类或者接口。
class Outer{ public void method() { //局部内部类 class Innter{ //方法中再定义一个类 //内部类的方法 //内部类的属性 } } }
示例:
public class Outer02 { //演示方法内部类 //演示一: 没有返回值的局部内部类 public void runInnerMethod() { class Inner{ //定义局部内部类 int id = 10; public void prnt(){ System.out.println(id); } } //只能在该方法中创建并使用该类 new Inner().prnt(); } //演示二:有父类引用作为返回值的内部类 public Dog getSubClass(){ class subDog extends Dog{ public void shout() { //重写了父类的方法 System.out.println("小狗重新叫了一下"); } void eat(){ System.out.println("开吃"); } } return new subDog(); } } //定义一个父类 class Dog { void shout(){ System.out.println("狗叫了一声"); } } class Outer02Test { public static void main(String[] args) { Outer02 outer02= new Outer02(); outer02.runInnerMethod();; Dog dog = outer02.getSubClass(); //dog.eat();报错,父类无法调用子类 //(subDog)dog; 无法写强转,因为局部内部类只能被包裹它的方法访问,对外部隐藏 dog.shout(); //只有重写父类的方法,父类才能访问局部类被重写过的方法。 } } //输出: 10 小狗重新叫了一下
3、匿名内部类
匿名内部类,就是没有引用变量直接new出来的类的统称,说白了就是一种没有赋予名字的对实例化对象。匿名内部类没有构造方法,因为匿名内部类并没有声明(没有名字)。方法格式如下:
class Outer {
//属性
//方法
public void method(){
new Inner() {
//匿名内部类具体实现
}
}
}
匿名内部类可以看作是一种特殊的局部内部类。一般来说,因为匿名内部类没有构造方法,匿名内部类只用于对继承方法的实现或是重写,用于继承其他类或是实现接口。和局部内部类相似,并不需要增加额外的方法,因为只有方法本身内能调用。
示例:
public class Outer03 {
//匿名内部类演示
public void dogRun() {
new Animal() { //匿名内部类没方法名,必须继承一个抽象类或者实现一个接口
@Override
public void run() {
System.out.println("小狗在跑");
}
}.run();
}
}
interface Animal {
void run();
}
class Outer03Test {
public static void main(String[] args) {
new Outer03().dogRun();
}
}
4、静态内部类
静态内部类就是前面加上 static修饰的成员内部类,静态内部类并不依赖外部类,可以在没有外部类对象的时候直接就能创建静态内部类。与静态属性和方法类似,静态内部类也拿不到外部类的非静态属性和方法。
- 静态内部类不能取得外部类所有元素,只能获取外部类的静态部份。
静态内部类的创建不依赖外部类对象。语法格式如下:
//外部类.内部类 内部类名 = new 外部类.内部类(); Outer.Inner inner = new Outer.Inner();
示例:
public class Outer04 { int i = 1; static double d = 2.2; static class Inner { public void getOuterFields(){ System.out.println(d); //静态内部类,拿不到非静态属性 //System.out.println(i); //Non-static field 'i' cannot be referenced from a static context } } } class Outer04Test { public static void main(String[] args) { Outer04.Inner inner = new Outer04.Inner(); inner.getOuterFields(); } } //输出: 2.2