1、介绍
package level2.interClass; /** * 1、介绍: 一个类的内部类 又完整的嵌套了另一个类结构,被嵌套的类称为内部类(inner class) * 嵌套其他类的类称为外部类,是我们类的第五大成员(属性、方法、构造器、代码块、内部类), * 内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系 * 2、语法: * class outer{ // 外部类 * class inner{ // 内部类 * } * } * class other{ // 外部其他类 * } * 4、内部类的分类: * 1) 定义在外部类的局部位置上(比如方法内): * a. 局部内部类(有类名) * b. 匿名内部类(没有类名,是重点) * 2) 定义在外部类的成员位置上: * a. 成员内部类(没有static修饰) * b. 静态内部类(使用static修饰) */ public class MyInterClass { public static void main(String[] args) { } } class Outer{ private int n1 = 100; public Outer(int n1){ this.n1 = n1; } public void m1(){ System.out.println("m1()"); } { System.out.println("代码块..."); } class Inner{ //内部类 } }
2、局部内部类
package level2.interClass; /** * 1、局部内部类:是定义在外部类的局部位置,比如方法中(通常),且有类名 * 1) 可以直接访问外部类所有成员,包含私有的 * 2) 不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的。 * 但是可以使用final修饰,因为局部变量也能使用final * 3) 作用域:仅仅在定义它的方法或代码块中 (本质仍然是个类) * 4) 局部内部类--访问-->外部类的成员-->[直接访问] * 5) 外部类--访问-->局部内部类的成员-->[创建对象再访问,必须在作用域内] * 6) 外部其他类--不能访问-->局部内部类 * 7) 如果外部类和局部内部类重名,默认遵循就近原则,如果想访问外部类的成员,则可以使用 * (外部类名.this.成员)去访问 * */ public class LocalInnerClass { public static void main(String[] args) { MyOuter myOuter = new MyOuter(); myOuter.m1(); } } class MyOuter{ private int n1=210; public void m2(){ System.out.println("MyOuter m2()..."); } public void m1(){ // 不能添加访问修饰符,但是可以使用final修饰 // 作用域仅仅在m1方法体内 final class MyInner{ // 本质仍是一个类 private int n1 = 900; // 内部类中含有同名的n1 public void f1(){ // 可以直接访问外部类的成员,包括私有属性 // 若内部类中含有同名成员,一般遵循就近原则,若指定访问外部类成员,需要 外部类名.this.成员: // MyOuter.this 本质是外部类的对象,谁调用f1(),MyOuter.this就是谁 System.out.println("MyOuter n1=" + MyOuter.this.n1); // 如无显式指定,则遵循就近原则 System.out.println("MyInner n1="+n1); m2(); } } // 外部类访问内部类的成员,需要创建对象再访问 MyInner myInner = new MyInner(); myInner.f1(); // 若MyInner是public,则可以继承 // class MyInner01 extends MyInner{} } { // 也可以在代码块中 class MyInner02{} } }
3、匿名内部类
package level2.interClass; /** * 1、介绍:匿名内部类(重要)是定义在外部类的局部位置(方法/代码块),且没有类名 * (1)本质还是一个类 (2)内部类 (3)该类没有名字 (4)同时还是一个对象 * 2、基本语法: * class 类或接口(参数列表){ * 类体 * }; * 3、说明: * 1) 可以使用对象调用,也可以直接调用 * 3) 作用域:仅仅在定义它的方法或代码块中 (本质仍然是个类) * 4) 匿名内部类--访问-->外部类的成员-->[直接访问] * 5) 外部类--访问-->匿名内部类的成员-->[创建对象再访问,必须在作用域内] * 6) 外部其他类--不能访问-->匿名内部类 * 7) 如果外部类和匿名内部类重名,默认遵循就近原则,如果想访问外部类的成员,则可以使用 * (外部类名.this.成员)去访问 */ public class AnoymousInnerClass { public static void main(String[] args) { } } class Outer01{ //外部类 private int n1 = 10; public void method() { // 基于接口的匿名内部类 // 想使用IA接口中的方法,但是不想定义类和实例化对象 // 1)tiger的编译类型是 IA,运行类型是 匿名内部类 // 2)匿名内部类,代码在底层运行时,实际上会创建一个类去实现接口,且会分配一个类名: Outer01$1 (外部类+$i) // 3)jdk底层在创建了匿名内部类Outer01$1,立即就创建了对象实例,并且返回地址 // 4)匿名内部类使用一次,就不能再使用,但是实例化出来的对象仍可以继续使用 // 5)匿名内部类是Outer01$1,tiger是对象 /* 6) 等价于 class Outer01$1 implement tiger {} */ IA tiger = new IA() { public void cry() { System.out.println("老虎叫..."); } }; System.out.println("tiger的运行类型 = " + tiger.getClass()); tiger.cry(); // 调用 // 基于类的匿名内部类 // 1) tiger的编译类型是 Father,运行类型是 Outer01$2 /* 2) 等价于: class Outer01$2 extends Father {} */ // 3) 同时返回一个对象 // 注意:参数列表也会传递给构造器 Father father = new Father("tom") { @Override public void test() { System.out.println("匿名内部类重写了test方法"); } }; System.out.println("father的运行类型 = " + father.getClass()); father.test(); // 注意: 以下形式 不带{} 是实例化对象 Father fa = new Father("tom"); } } class Outer02{ private int n1=100; public void f1(){ // 第一种调用方式:对象调用 Person p = new Person(){ @Override public void hi() { System.out.println(" Outer02 中的 第1个hi"); } }; p.hi(); // 第二种调用方式: 直接调用(可传参) new Person(){ @Override public void hi() { System.out.println(" Outer02 中的 第2个hi"); } }.hi(); } } class Person{ public void hi(){ System.out.println(" Person hi() "); } } interface IA{ // 接口 public void cry(); } class Father { public Father(String name) { // 构造器 } public void test() { } } abstract class Animal{ abstract public void eat(); }
3.1、匿名内部类练习01
package level2.interClass; /** * 使用场景 * 1、将匿名内部类 作为实参传递 * */ public class InnerClassExercise { public static void main(String[] args) { // 将匿名内部类 作为参数传递 f1(new AA() { @Override public void show() { System.out.println("f1() 中的show"); } }); } // 静态方法 形参是接口类型 public static void f1(AA aa){ aa.show(); } } interface AA{ void show(); }
3.1、匿名内部类练习02
package level2.interClass; public class InnerClassExercise01 { public static void main(String[] args) { // new CellPhone().alarmclock(new Bell() { @Override public void ring() { System.out.println("懒猪起床了..."); } }); CellPhone cellPhone = new CellPhone(); cellPhone.alarmclock(new Bell(){ @Override public void ring() { System.out.println("开始上课了..."); } }); cellPhone.alarmclock(new Bell(){ @Override public void ring() { System.out.println("已经下课了..."); } }); } } interface Bell{ public void ring(); } class CellPhone{ public void alarmclock(Bell bell){ bell.ring(); } }