目录
一、局部内部类
二、匿名内部类
基于接口的匿名内部类
基于类的匿名内部类
三、匿名内部类的实践
类的五大成员:属性、方法、构造器、代码块、内部类
内部类的分类
定义在外部类局部位置上(比如说方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
一、局部内部类
说明:局部内部类是定义在外部类的局部位置,比如方法种,并且有类名
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类---访问----》外部类的成员 【访问方式:直接访问】
- 外部类---访问---》局部内部类的成员
- 访问方式:创建对象,再访问(注意:必须再作用域内)
package com.hspedu.innerclass;
/*** 演示局部内部类的使用*/
public class LocalInnerClass {public static void main(String[] args) {//演示一遍Outer02 outer02 = new Outer02();outer02.m1();}
}class Outer02 {//外部类private int n1 = 100;private void m2() {System.out.println("Outer02 m2()");}//私有方法public void m1() {//方法//1.局部内部类是定义在外部类的局部位置,通常在方法//3.不能添加访问修饰符,但是可以使用final修饰//4.作用域:仅仅在定义它的方法或代码块中class Inner02 {//局部内部类(本质仍然是一个类)//2.可以直接访问外部类的所有成员,包含私有的public void f1() {//5.局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()System.out.println("n1=" + n1);m2();}}//6.外部类在方法中,可以创建Inner02对象,然后调用方法即可Inner02 inner02 = new Inner02();inner02.f1();}}
输出结果
- 外部其他类---》不能访问---》局部内部类(因为 局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
Outer02.this 本质就是外部类的对象,即哪个对象调用了m1,Outer02.this就是哪个对象
输出结果:
二、匿名内部类
本质是类 内部类 该类没有名字 同时还是一个对象
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
匿名内部类的基本语法
new类或接口(参数列表){
类体
};
基于接口的匿名内部类
未使用匿名内部类简化开发之前
package com.hspedu.innerclass;/*** 演示匿名内部类的使用*/
public class AnonymousInnerClass {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}class Outer04 {//外部类private int n1 = 10;//属性public void method() {//方法//基于接口的匿名内部类//1.需求:想使用IA接口,并创建对象//2.传统方式,是写一个类,实现该接口,并创建对象//3.需求是 Tiger/Dog 类只是使用一次,后面不使用//4.可以使用匿名内部类来简化开发IA tiger = new Tiger();tiger.cry();}
}interface IA {//接口public void cry();
}
class Tiger implements IA {@Overridepublic void cry() {System.out.println("老虎叫-----");}
}class Dog implements IA {@Overridepublic void cry() {System.out.println("小狗叫-----");}
}
class Father {//类public Father(String name) {//构造器}public void test() {//方法}
}
使用匿名内部类简化开发之后
package com.hspedu.innerclass;/*** 演示匿名内部类的使用*/
public class AnonymousInnerClass {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}class Outer04 {//外部类private int n1 = 10;//属性public void method() {//方法//基于接口的匿名内部类//1.需求:想使用IA接口,并创建对象//2.传统方式,是写一个类,实现该接口,并创建对象//3.需求是 Tiger/Dog 类只是使用一次,后面不使用//4.可以使用匿名内部类来简化开发//5.tiger的编译类型 ? IA//6.tiger的运行类型 ? 就是匿名内部类 XXXX => Outer04$1/*我们看底层 会分配 类名 Outer04$1class XXXX implements IA {@Overridepublic void cry() {System.out.println("老虎叫----");}};*///7.jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,并且把地址// 返回给 tiger//8.匿名内部类使用一次,就不能再使用IA tiger = new IA(){@Overridepublic void cry() {System.out.println("老虎叫----");}};tiger.cry();System.out.println("tiger的运行类型:" + tiger.getClass());// IA tiger = new Tiger();
// tiger.cry();}
}interface IA {//接口public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫-----");
// }
//}
//
//class Dog implements IA {
//
// @Override
// public void cry() {
// System.out.println("小狗叫-----");
// }
//}
class Father {//类public Father(String name) {//构造器}public void test() {//方法}
}
要注意这段代码并不是直接创建接口的实例,而是创建了一个实现类该接口的类的实例,
这个类的类名由jdk分配
匿名内部类的代码:
IA tiger = new IA(){@Overridepublic void cry() {System.out.println("老虎叫----");}};
实际上等价于下面的代码
// 显式定义一个类实现接口
class Outer04$1 implements IA {@Overridepublic void cry() {System.out.println("老虎叫----");}
}// 在主方法中创建 MyPrinter 的对象
IA tiger = new Outer04$1();
基于类的匿名内部类
class Father {//类public Father(String name) {//构造器}public void test() {//方法}
}
//演示基于类的匿名内部类//分析//1.father编译类型 Father//2.father运行类型 Outer04$2//3.底层会创建匿名内部类/*class Outer04$2 extends Father{@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}}*///4.同时也直接返回了 匿名内部类 Outer04$2//注意("jack") 参数列表会传递给构造器Father father = new Father("jack"){@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}};System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2father.test();
Father father = new Father("jack"){@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}};
等价于
class Outer04$2 extends Father{@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}}Father father = new Outer04$2("jack");
基于类的匿名内部类的第二种方式,这里我调用的是Person类
//直接调用,匿名内部类本身也是返回对象
//class 匿名内部类 extends Person {}
new Person(){@Overridepublic void hi() {System.out.println("匿名内部类重写了 hi方法,zzzzzz");}
}.hi();
package com.hspedu.innerclass;public class AnonymousInnerClassDetail {public static void main(String[] args) {Outer05 outer05 = new Outer05();outer05.f1();//外部其他类---不能访问----》匿名内部类System.out.println("main hashcode=" + outer05);}
}class Outer05 {private int n1 = 99;public void f1() {//创建一个基于类的匿名内部类//不能添加访问修饰符,因为它的地位就是一个局部变量//作用域:仅仅在定义它的方法或代码块中Person p = new Person(){private int n1 = 88;@Overridepublic void hi() {//可以直接访问外部类的所有成员,包含私有的//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员) 去访问System.out.println("匿名内部类重写了 hi方法 n1=" + n1 + " 外部内的n1=" + Outer05.this.n1);//Outer05.this 就是调用 f1的 对象System.out.println("Outer05.this hashcode=" + Outer05.this);}};p.hi();//动态绑定,运行类型是Outer05$1// //也可以直接调用,匿名内部类本身也是返回对象
// //class 匿名内部类 extends Person {}
// new Person(){
// @Override
// public void hi() {
// System.out.println("匿名内部类重写了 hi方法,zzzzzz");
// }
//
// @Override
// public void ok(String str) {
// super.ok(str);
// }
// }.ok("jack");}
}class Person {//类public void hi(){System.out.println("Person hi()");}public void ok(String str){System.out.println("Person ok()" + str);}
}
//抽象类/接口。。。
三、匿名内部类的实践
示例1
匿名内部类方式
public class InnerClassExercise01 {public static void main(String[] args) {//当作实参直接传递,简洁高效f1(new IL() {@Overridepublic void show() {System.out.println("这是一幅画。。。");}}); }//静态方法,形参是接口类型public static void f1(IL il){il.show();}
}
//接口
interface IL {void show();
}
传统方式
public class InnerClassExercise01 {public static void main(String[] args) {//传统写法f1(new Picture());}//静态方法,形参是接口类型public static void f1(IL il){il.show();}
}
//接口
interface IL {void show();
}//类->实现IL =》编程领域(硬编码)
class Picture implements IL {@Overridepublic void show() {System.out.println("这是一幅名画。。。。");}
}
示例2
package com.hspedu.innerclass;public class InnerClassExercise02 {public static void main(String[] args) {CellPhone cellPhone = new CellPhone();cellPhone.alarmClock(new Bell() {//匿名内部类@Overridepublic void ring() {System.out.println("懒猪起床了");}});}
}interface Bell{//接口void ring();//方法
}class CellPhone{//类public void alarmClock(Bell bell){//形参是Bell接口类型bell.ring();//动态绑定}
}