25.匿名内部类的本质和使用
(1)本质上类(2)是一个内部类(3)该类没有名字(4)同时还是一个对象
基本语法:
new 类或接口(参数列表){ 类体 };
public class HelloJava { //外部其他类 public static void main(String[] args) { Outer outer = new Outer(); outer.method(); } } class Outer{ //外部类 private int n1 = 10;//属性 public void method(){//方法 //基于接口的匿名内部类 //1.需求:想使用接口A,并创建对象 //2.传统方式,写一个类,实现该接口,并创建对象 //3.现需求:Tiger类只使用一次,后面不再使用 //4.可以使用匿名内部类来简化开发 //5.tiger的编译类型 ? A(看等号左边) //6.tiger的运行类型 ? 匿名内部类 XXXX => Outer$1 /* 看底层 系统会分配类名 Outer$1 class XXXX implements A { @Override public void cry() { System.out.println("老虎叫唤...") } } */ //7.jdk底层在创建匿名内部类Outer$1,立即马上就创建了Outer$1实例,并把地址返回给tiger //8.匿名内部类使用一次,就不能再使用 A tiger = new A(){ @Override public void cry() { System.out.println("老虎叫唤..."); } }; System.out.println("tiger的运行类型=" + tiger.getClass()); tiger.cry(); //基于类的匿名内部类 //1.father编译类型 Father //2.father运行类型 Outer$2 //3.底层创建匿名内部类 /* class Outer$2 extends Father{ } */ //4.同时也直接返回了 匿名内部类 Outer$2的对象 //5.注意("jack") 参数列表会传递给 构造器 Father father = new Father("jack"){ @Override public void test() { System.out.println("匿名内部类重写了test方法"); } }; System.out.println("father对象的运行类型=" + father.getClass()); father.test(); //基于抽象类的匿名内部类 Animal animal = new Animal(){ @Override void eat() { System.out.println("小狗吃骨头..."); } }; } } interface A{//接口 public void cry(); } class Father{//类 public Father(String name){//构造器 System.out.println("接收到name=" + name); } public void test(){//方法 } } abstract class Animal{//抽象类 abstract void eat(); }
26.匿名内部类的细节
-
匿名内部类的语法比较奇特,注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类法
public class HelloJava { //外部其他类 public static void main(String[] args) { Outer outer = new Outer(); outer.f1(); } } class Outer{ private int n1 = 99; public void f1(){ //创建一个基于类的匿名内部类 Person p = new Person(){ @Override public void hi() { System.out.println("匿名内部类重写了 hi()方法"); } }; p.hi();//动态绑定,运行类是 Outer$1 //也可以直接调用,匿名内部类本质也是返回对象 new Person(){ @Override public void hi() { System.out.println("匿名内部类重写了 hi()方法"); } }.hi(); } } class Person{ public void hi(){//类 System.out.println("Person hi()"); } }
-
可以直接访问外部类的所有成员,包含私有的
-
不能添加访问修饰符,因为它的地位就是一个局部变量
-
作用域:仅仅在定义它的方法或代码块中
-
匿名内部类---访问--->外部类成员[访问方式:直接访问]
-
外部其他类---不能访问--->匿名内部类(因为 匿名内部类地位是一个局部变量)
-
如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
27.匿名内部类的最佳实践
把匿名内部类当作实参直接传递,简洁高效
public class HelloJava { public static void main(String[] args) { //当作实参直接传递,简洁高效 f1(new IL() { @Override public void show() { System.out.println("这是一副名画"); } }); } //静态方法,形参是接口类型 public static void f1(IL il){ il.show(); } } //接口 interface IL { void show(); }
28.成员内部类
成员内部类是定义在外部类的成员位置,并且没有static修饰
1.可以直接访问外部类所有成员,包括私有的
2.可以添加任意访问修饰符,因为它的地位就是一个成员
public class HelloJava { public static void main(String[] args) { Outer outer = new Outer(); outer.t1(); } } class Outer{//外部类 private int n1 = 10; public String name = "张三"; //成员内部类是定义在外部类的成员位置上 class Inner{//成员内部类 public void say(){ //可以直接访问外部类的所有成员,包含私有的 System.out.println("n1 = " + n1 + "name = " + name); } } //写方法 public void t1(){ //使用成员内部类 Inner inner = new Inner(); inner.say(); } }
3.作用域:和外部类的其他成员一样,为整个类体
4.成员内部类---访问--->外部类成员[访问方式:直接访问]
5.外部类---访问--->成员内部类[访问方式:创建对象,在访问]
6.外部其他类---访问--->成员内部类[访问方式:直接访问]
//三种方式 //方式1 Innter01 innter01 = outer01.new Inner01(); //方式2 Innter01 innter01 = new Outer01().new Innter01(); //方式3 Innter01 innter01Instance = new Outer01().getInnter01Instance();
29.静态内部类
-
可以直接访问外部类的所有静态成员,包括私有的,但不能直接访问非静态成员
-
可以添加任意访问修饰符,因为它的地位就是一个成员
-
作用域:同其他的成员,为整个类体
-
静态内部类---访问--->外部类[访问方法:直接访问所有静态类成员]
-
外部类---访问--->静态内部类[访问方式:创建对象,再访问]