内部类
介绍
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类,嵌套其他类的类称为外部类。内部类最大的特点是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。
1.基本语法
class Outer{//外部类
class Inner{//内部类
}
}
class Other{//外部其他类
}
2.内部类的分类
1.定义在外部类局部位置上(比如方法内)
- 局部内部类(有类名);
- 匿名内部类(没有类名,重点!!!)
2.定义在外部类的成员位置上
- 成员内部类(没用static修饰);
- 静态内部类(使用static修饰)。
3.局部内部类
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
- 可以直接访问外部类的所有成员,包含私有的;
- 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰符,因为局部变量也可以使用final;
- 作用域:仅仅在定义它的方法或代码块中;
- 局部内部类–访问—》外包类的成员【访问方式:直接访问】;
- 外部类–访问—》局部内部类的成员【访问方式:创建对象,在访问(必须在作用域内)】;
- 外部其他类—不能访问-----》局部内部类(因为局部内部类地位是一个局部变量);
- 如果外部类和局部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。
class Outer {
private int n1 = 100;
private void m2(){
System.out.println("m2");
}//私有方法
public void m1(){//方法
String name = "小红";
//1.局部内部类是定义在外部类的局部位置,通常在方法里
//3.不能添加访问修饰符,但是可以使用final修饰
//4.作用域:仅仅在定义它的方法或代码块中
final class Inner{//局部内部类(本质仍然是一个类)
//2.可以直接访问外部类的所有成员,包含私有的
private int n1 = 200;
public void f1(){
//5.局部内部类可以直接访问外部类的成员,比如下面的变量和方法
System.out.println("n1= " + n1);
//如何访问外部类的n1?
//语法--->外部类名.this.成员
//Outer.this.n1 本质就是外部类的对象,那个对象调用了m1方法,Outer.this就是那个对象
System.out.println("n1= " + Outer.this.n1);
m2();
}
}
//6.外部类在方法中,可以创建Inner对象,然后调用方法即可
Inner inner = new Inner();
inner.f1();
}
}
注意:
- 局部内部类定义在方法或代码块中
- 作用域在方法体或者代码块中
- 本质还是一个类
4.匿名局部内部类
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名。
- 本质是类;
- 还是内部类;
- 该类没有名字(系统会自动生成名字);
- 同时还是一个对象。
//基本语法
new 类或接口(参数列表){
类体
};
//class 匿名内部类 extends 类或接口(参数列表){
//类体
//};
1)需求:想要用动物接口,并创建猫对象。
2)传统方式,是写一个猫类,在实现动物接口,最后创建对象;
3)要求:猫类只能使用一次,后面再不使用;
4)可以使用匿名内部类来实现该需求;
5)动物接口是编译类型,匿名内部类是运行类型;
6)底层会帮我们实现接口的操作,并且会分配一个类名,类名就是[类名$1];
7)jdk底层在创建匿名内部类,立马就创建了[类名$1]实例,并且把地址返回给动物接口;
8)匿名内部类使用一次,就不能使用了。
1.匿名内部类的使用
1.匿名内部类的语法比较奇特,请大家一定要注意,因为匿名内部类即使一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码的分析可以看出这个特点,因此可以调用匿名内部类方法。
new A(){
public void cry(){
System.out.println("hello~~");
}
}.cary();
A a = new A(){
public void cry(){
System.out.println("hello~~");
}
};
a.cry();//动态绑定,运行类型是匿名内部类
- 可以直接访问外部类的所有成员,包括私有的;
- 不能添加访问修饰符,因为它的地位就是一个局部变量;
- 作用域:仅仅在定义它的方法或代码块中;
- 匿名内部类–访问—>外部类成员【访问方法:直接访问】;
- 外部其他类–不能访问—>匿名内部类(因为匿名内部类地位是一个局部变量);
- 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问。
2.匿名内部类的使用场景
- 把匿名内部类当做实参直接传递。
只使用一次的话,写匿名内部类会简洁很多
public class Test2 {
public static void main(String[] args) {
//使用匿名内部类,当做实参直接传递,简洁高效
f1(new ISS(){
@Override
public void show() {
System.out.println("调用到我了");
}
});
//传统写法
f1(new XXX());
}
//静态方法,形参是接口类型
public static void f1(ISS iss){
iss.show();
}
}
//接口
interface ISS{
void show();
}
//传统写法--->编程领域 硬编码
class XXX implements ISS{
@Override
public void show() {
System.out.println("也调用到我了,我是传统写法");
}
}
5.成员内部类
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
- 可以直接访问外部类的所有成员,包含私有的;
- 可以添加任意访问修饰符,因为它的地位就是一个成员;
- 作用域和外部类的其他成员一样;
- 成员内部类—访问----》外部类成员【访问方式:直接访问】;
- 外部类—访问—》成员内部类【创建对象,再访问】;
- 外部其他类----访问----》成员内部类。
1)外部类.内部类 类名称 = 外部类名称.new 内部类();
2)在外部类中写一个方法,返回内部类; - 如果外部类和内部类的成员重名时 ,内部类访问的话,默认遵循就近原则,如果想访问,则可以使用【外部类名.this.成员】去访问
class Outer {//外部类
private int n1 = 10;
public String name = "小红";
class Innter {//这是一个成员内部类
public void say(){
}
}
//写方法
public void t1(){
使用了成员内部类
Innter aa = new Innter();
aa.say();
}
}
6.静态内部类
说明:静态内部类是定义在外部类的成员位置,并且有static修饰。
- 可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员;
- 可以添加任意访问修饰符,因为它的地址就是一个成员;
- 作用域:同其他的成员,为了整个类体;
- 静态内部类–访问—》外部类(比如,静态属性)【访问方式:直接访问所有静态成员】;
- 外部类—访问-----》静态内部类【访问方式,创建对象,再访问】;
- 外部其他类—访问----》静态内部类
1)外部类对象.静态内部类(除了私有的,需要满足访问权限);
2)写一个方法,返回一个静态内部类对象; - 如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则,如果想访问外部类的成员,则可以使用【外部类名.成员】 去访问。(不用加this,因为这是静态内部类);