什么是内部类
内部类是指在一个外部类内定义的类。如图:
public class Body{//外部类
class Heart{//内部类:定义在外部类中的类
public void work(){
System.out.println("正在跳动");
}
}
}
在非外部类中定义的内部类和局部变量一样,其作用范围从其定义的位置开始至其语句块结束。
内部类的分类
可以分为静态内部类和非静态内部类
用static修饰的内部类为静态内部类,没有static修饰的内部类则为非静态内部类。
静态内部类
- 静态内部类只能直接定义在外部类中,不能定义在方法和作用域中
- 静态内部类仅能直接访问外部类的静态成员变量和方法,可以通过创建外部类的对象间接使用非静态的成员变量和方法
public class OutClass{
private double weight = 72;
public static void print(String name){
System.out.println(name);
}
static class InClass{
{
//由于weight变量是非静态的,所以必须创建外部类对象间接调用weight
double weight = new OutClass().weight
//由于print方法是静态的,所以可以直接使用
print("Tom");
}
}
}
- 只有有名的静态内部类中才允许有静态成员(静态成员变量、静态方法和静态代码块)
下面我们通过创建内部类对象来具体看一下静态内部类和非静态内部类的区别。
如何创建内部类对象
public class Body{
class Heart{//非静态内部类 class前加上static就是静态内部类
public void work(){
System.out.println("正在跳动");
}
}
public static void main(String[] args){
//创建非静态内部类对象
Body body = new Body();
Heart heart = body.new Heart();
//创建静态内部类对象
//Body body = new Body();
//Heart heart = new Body.Heart();
}
}
可以分为有名内部类和匿名内部类
上文写的全部是有名内部类,下面我们具体写一下匿名内部类
匿名内部类
匿名内部类由于没有类名而不能单独存在,定义匿名内部类的同时则须直接实例化该类,语法格式如下:
new 父类构造器([参数列表])/接口(){
匿名内部类类体;
}
举例:
public class Mammal{
public void move(){
System.out.println("正在移动");
}
}
___________________________________________________________________
public class Ocean(){
//匿名内部类
Mammal mammal = new Mammal(){//调用Mammal中的无参构造方法
public void move(){
System.out.println("用鳍移动");
}
};
}
匿名内部类特点
- 匿名内部类一定是接口的实现类(该类仅能实现一个接口)或类(普通类或抽象类)的子类,其中new关键字后面的类名或接口名就是该匿名内部类继承的类或实现的接口。
- 匿名内部类不能自定义构造方法(没有名字怎么定义构造方法),但是可以通过非静态代码块初始化成员变量
- 匿名内部类一定不能是抽象类
- 可以在匿名内部类里添加新的属性和方法,但是这些属性和方法不能被上转型对象所调用,只能被非上转型对象方式创建的匿名内部类对象所调用
public class Test{
public static void main(String[] args){
IMammal whale = new Mammal(){
public void breath(){
System.out.println("正在呼吸");
}
@Override
public void move(){
System.out.pringtln("用鳍移动");
}
};//此时匿名内部类对象为上转型对象
whale.breath();//这里会报错,上转型对象无法调用新增的breath方法
}
}
interface IMammal{
void move();
}
_______________________________________________________________________________
//调用breath方法
new IMammal(){
public void breath(){
System.out.println("正在呼吸");
}
public void move(){
System.out.println("用鳍移动");
}
}.breath();//调用新增breath方法
内部类特点
- 内部类是一个独立的类:编译之后内部类会被编译成独立的.class文件,如果该内部类为有名内部类,则有名内部类字节码文件名为外部类的类名+$+内部类类名;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+$+数字。
- 普通外部类、抽象类和接口都可以有内部类(匿名的或者有名的)
- 内部类可以直接定义在类中,也可以定义在方法或者代码块中;其中直接定义在外部类(普通外部类、抽象类和接口只能使用public和default修饰)中的内部类可以用所有四种的访问权限控制符来修饰,也可以使用static修饰(这时static不能修饰普通外部类、接口和抽象类);但是定义在方法和代码块中的内部类则不可以有访问控制修饰符,也不能有static修饰。
- 内部类可以访问外部类中所有访问权限级别的成员变量。
- 在局部变量的作用范围内,如果定义的内部类需要使用该局部变量,则该变量必须使用final修饰。