一.学习内容
1.内部类
2.局部内部类
3.匿名内部类
二.具体记录
1.内部类
定义:一个类的内部又完整的嵌套另一个类结构,被嵌套的类称为内部类,嵌套其他类的类称为外部类,内部类最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系
类的五大成员(属性,方法,构造器,代码块,内部类)
class Outer{//外部类 class Inner {//内部类 } }
class Other{ //外部其他类 }
分类:
定义在外部类局部位置上(比如方法内)
1.局部内部类(有类名)
2.匿名内部类(无类名)
定义在外部类的成员位置上
1.成员内部类(没用static修饰)
2.静态内部类(使用static修饰)
2.局部内部类
局部内部类:定义在外部类的局部位置上,比如方法中或者代码块中,并且有类名
class Outer02{//外部类
private int n1=100;
private void m2() {}//私有方法
public void m1(){//方法
//局部内部类是定义在外部类的局部位置,通常在方法
class inner02{//局部内部类
//可直接访问外部类的所有成员,包含私有的
public void f1(){
System.out.println("n1="+n1);
m2();
}
}
}
}
1.可以直接访问外部类的所有成员,包含私有的
2.局部内部类不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量不能使用
修饰符,但是可以使用final修饰,因为局部变量也可以使用final
3.作用域:局部内部类仅仅在,定义它的方法或代码块中
4.局部内部类要访问,外部类的成员:直接访问
5.外部类访问,局部内部类的成员:创建对象再访问(注意必须在作用域内)
6.外部其他类不能访问局部内部类(因为局部内部类地位是一个局部变量)
7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
则可以使用:外部类名.this.成员 去访问
外部类名.this的本质就是外部类的对象
3.匿名内部类
匿名内部类:本质是类; 内部类; 没有名字(系统分配,看不见);同时还是一个对象;
new 类或接口(参数列表){ 类体 }
class Outer04{//外部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类:1.需求——想使用IA接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
IA tiger = new Tiger();
tiger.cry();
}
}
interface IA {//接口
public voud cry();
}
class Tiger implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤。。。");
}
}
//3.需求是Tiger/Dog 类只使用一次,后面不再使用
//4.可以使用匿名内部类来简化开发
//5.tiger的编译类型是IA,运行类型就是匿名内部类 XXXX => Outer04$1
/*
我们看底层,系统会分配 类名 Outer04$1
class Outer04$1 implements IA{
@Override
public void cry(){
System.out.println("老虎叫唤。。。");
}
}
以后看到$就知道是匿名内部类
*/
//7.IA tiger = new IA(),这个new代表什么? jdk底层在创建匿名内部类Outer04$1后,
// 立即马上就创建了Outer04$1的实例,并且把地址返回给tiger
//8.匿名内部使用一次,就不能再使用了,就没了你找不到了,但是tiger对象你是可以反复使用的
class Outer04{//外部类
private int n1 = 10;//属性
public void method() {//方法
IA tiger = new IA(){//jdk在底层执行的时候,他看到你这个语法,
//他就知道要给你创建一个匿名内部类
@Override
public void cry(){
System.out.println("老虎叫唤。。。");
}
};
tiger.cry();
}
}
interface IA {//接口
public voud cry();
}
//1.基于类的匿名内部类
//2.father编译类型Father,运行类型 Outer04$2
//3.底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test(){
System.out.println("匿名内部类重写了test方法")
}
}
*/
//4.同时也直接返回了匿名内部类Outer04$2的对象
class Outer04{//外部类
private int n1 = 10;//属性
public void method() {//方法
Father father = new Father("jack"){
//注意("jack")参数列表会传递给构造器
@Override
//test方法可以不写,但是如果是基于抽象类的匿名内部类,其中的方法就必须实现
public void test(){
System.out.println("匿名内部类重写了test方法")
}
};
father.test();
}
}
class Father{//非抽象类
public Father (String name){//构造器 }
public void test(){//方法 }
}
使用细节:
1.因为匿名内部类既是一个类的定义,同时本身也是一个对象,因此从语法上看它既有定义类的特征,也有创建对象的特征,因此调用匿名内部类的方法有以下两种。
1.方法一
class Outer05{
private int n1=99;
public void f1(){
//创建一个基于类的匿名内部类
Person p = new Person(){
@Override
public void hi(){
System.out.println("匿名内部类重写了hi方法");
}
};
p.hi();//动态绑定,真实的运行类型是Outer05$1
}
}
class Person {//类
public void hi(){
System.out.println("Person hi()");
}
}
2.方法二:直接调用
class Outer05{
private int n1=99;
public void f1(){
//也可以直接调用,匿名内部类本身也是返回对象
//class 匿名内部类 extends Person{}
new Person(){
@Override
public void hi(){
System.out.println("匿名内部类重写了hi方法");
}
}.hi(); //就把.hi()前面的一堆看作对象理解
}
}
class Person {//类
public void hi(){
System.out.println("Person hi()");
}
}
2.可以直接访问外部类的所有成员,包含私有的
3.不能添加访问修饰符,因为他的地位就是一个局部变量
4.作用域:仅仅在定义他的方法或代码块中
5.匿名内部类访问外部类的成员:直接访问
6.外部其它类不能访问匿名内部类(匿名内部类的地位是一个局部变量)
7.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用:外部类名.this.成员
匿名内部类的最佳实践:
1.当做实参直接传递,简洁高效
//1.匿名内部类
public static void main(String[] args){
//当做实参直接传递,简洁高效
f1(new IL() {
@Override
public void show(){
System.out.println("这是一幅名画。。。");
}
});
}
//静态方法,形参是接口类型
piblic static void f1(IL il){
il.show();
}
//接口
interface IL{ void show(); }
//2.传统写法
public static void main(String[] args){
f1(new Picture());
}
//静态方法,形参是接口类型
piblic static void f1(IL il){
il.show();
}
//接口
interface IL{ void show(); }
//先写个类去实现IL----在编程里面成为硬编码
class Picture implements IL{
@Override
public void show(){
System.out.println("这是一幅名画。。。");
}
}