一、什么是内部类?
在我之前的博客中, 无论运行什么程序,代码示例中,类与类之间无非平行关系,继承关系,但在Java中类与类之间除了这两种关系还存在一个包裹关系,这就是内部类。
内部类的定义:内部类是指在一个外部类内定义的类。(内部类的定义类似于全局变量与局部变量,作用范围与定义位置有关,因此,内部类不仅可以定义在类中,还可以定义在方法中)
二、有名内部类与无名内部类
(1)有名内部类
有名,顾名思义,即在定义该类时要声明该类的名字,结构如下:
若有名内部类要创建对象与调用方法,格式如下:
(2)无名内部类
抽象类的特点:
1、匿名内部类是普通类的子类
因为匿名内部类没有类名,因此无法用类名创建对象,因此匿名内部类对象的创建与类名的声明是在同一条语句中进行的,这就引出了匿名内部类的第一个特点, 格式如下:
先定义一个父类:
public class Mammal {
void move() {
System.out.println("正在移动");
};
}
然后直接定义匿名内部类并创建对象:
public class Body {
public static void main(String[] args) {
Mammal mammal = new Mammal() { // 匿名内部类创建对象与类声明同时进行
};
mammal.move();
}
}
由此可知,这行代码: 实际上包含了一个对象上转型的过程,同时也是Java多态的体现。
既然这样,也就说明匿名抽象类能够重写父类的方法:
public class Body {
public static void main(String[] args) {
Mammal mammal = new Mammal() {// 匿名内部类创建对象与类声明同时进行
@Override
void move() {
System.out.println("用鳍游动......");
}
};
mammal.move();
}
}
运行结果:
那么,父类的move()方法就失去了意义,此时不妨把弗雷定义为一个抽象类,这就引出了匿名内部类的第二个特点:
2、匿名内部类是抽象类的子类((匿名内部类不能是抽象类,因为抽象类不能创建对象,而匿名内部类的类与对象的创建是同时的))
public abstract class Mammal {
abstract void move();
}
public class Body {
public static void main(String[] args) {
Mammal mammal = new Mammal() {// 匿名内部类创建对象与类声明同时进行
@Override
void move() {
System.out.println("用鳍游动......");
}
};
mammal.move();
}
}
而当匿名内部类的父类抽象类只含抽象方法时,则可以把它定义为一个接口,这就引出匿名抽象类的另一个特点:
3.匿名内部类是接口的实现类
public interface Mammal {
void move();
}
public class Body {
public static void main(String[] args) {
Mammal mammal = new Mammal() {// 匿名内部类创建对象与类声明同时进行
@Override
public void move() {
System.out.println("用鳍游动......");
}
};
mammal.move();
}
}
4.无论是匿名内部类还是有名内部类,编译之后内部类会被编译成独立的.class文件,如果该内部类为有名内部类,则有名内部类字节码文件名为外部类的类名+$+内部类类名;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+$+数字;
三、拓展
访问权限用于限制成员变量或方法能否在另一个类中被使用,但因为局部变量已经限定,所以局部变量不能使用访问权限
在局部变量作用的范围内,如果定义的内部类需要使用该局部变量,则该变量必须有final修饰,从 Java 8开始,如果定义的内部类需要使用该局部变量,则该变量可以不使用final修饰。