简介
内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在。内部类可以是静态的,可以使用 protected 和 private 来修饰,而外部类只能使用 public 和 默认的包访问权限。
Java 中内部类分为:成员内部类、局部内部类、静态内部类和匿名内部类。
成员内部类
作为外部类的一个成员存在,与外部类的属性、方法并列。
内部类的表现形式
// 定义一个外部类
class Outter{
String info; // 定义一个成员
// 定义一个内部类
class Inner{
String innerInfo; // 定义内部类的成员
public void print(){
System.out.println("内部类的方法");
}
}
}
通过外部类访问内部类
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。初始化内部类的方式:Outter.Inner inner = new Outter().new Inner();
,因为内部类是依托于外部类,所以需要先实例化外部类,然后在实例化内部类。
class Outter{
String info = "外部类信息";
private String msg = "外部类消息";
public static int count = 1;
class Inner{
String innerInfo = "内部类信息"; // 定义内部类的成员
// 内部类的方法
public void print(){
// 可以直接访问外部类定义的成员变量,不能使用 this,使用this指的是当前的 Inner
System.out.println(info); // 访问外部类的普通变量 输出结果:外部类信息
System.out.println(msg); // 访问外部类的私有变量 输出结果:外部类消息
System.out.println(count); // 访问外部类的静态变量 输出结果:1
}
}
}
public class TestDemo {
public static void main(String[] args) {
// 初始化 Inner 对象
Outter.Inner inner = new Outter().new Inner();
inner.print();
}
}
内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。
比如上面的例子:
- 如果成员内部类Inner用private修饰,则只能在外部类的内部访问。
- 如果用public修饰,则任何地方都能访问。
- 如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问。
- 如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类。它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。因为它们所在的作用域不同,访问的方式也不一样。
class Animal {
public Animal () {
}
}
class Cat {
public Cat (){
}
public Animal getMouse (){
class Mouse extends Animal { //局部内部类
int count =0;
}
return new Mouse();
}
}
局部内部类传递参数使用 final 关键字
在 JDK1.8 之前,方法中定义的内部类,访问方法的参数以及变量的时,需要在参数或者变量前,加上 final
标记。
class Outter {
private String msg = "外部类";
// 在 JDK 1.8 以后,可以不用加上 final 关键字
public void fun(final int num){
// 在 JDK 1.8 以后,可以不用加上 final 关键字
final double score = 99.9; // 方法变量
// 定义一个局部内部类
class Inner{
public void print(){
// 访问外部类的属性
System.out.println("属性:"+ Outter.this.msg); // 打印输出:属性:外部类
System.out.println("方法参数:" + num); // 打印输出:方法参数:1000
System.out.println("方法变量:" + score); // 打印输出:方法变量:99.9
}
}
// 调用 内部类的方法
new Inner().print();
}
}
public class TestDemo {
public static void main(String[] args) {
new Outter().fun(1000);
}
}
静态内部类
如果一个内部类使用了 static 定义,那么这个内部类就被称为静态内部类,并且只能访问外部类中定义的 static 操作。相当于定义了一个外部类。
静态内部类的初始化方式:Outter.Inner inner = new Outter.Inner();
这里和普通内部类是不一样的。
class Outter {
public String str = "外部消息"; // 外部类的普通变量
public static int count = 1; // 外部类的静态变量
public void printOutter() {
System.out.println("外部类中的普通方法");
}
static class Inner {
public void print() {
// System.out.println(str); // 无法直接访问 str 变量,此处会报错
System.out.println(count); // 只能访问外部类的静态变量
}
}
}
public class TestDemo {
public static void main(String[] args) {
// 初始化内部类
Outter.Inner inner = new Outter.Inner();
inner.print(); // 1
}
}
匿名内部类
匿名内部类使用时有一个前提:必须要基于接口或者抽象类的应用。
- 匿名内部类继承自接口,必须实现指定接口的方法,且无参数
- 匿名内部类继承自类,参数必须按父类的构造函数的参数传递
匿名内部类的特点
- 一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。
- 只是为了获得一个对象实例,不需要知道其实际类型。
- 类名没有意义,也就是不需要使用到。
接口中使用匿名内部类
下面介绍出正常的接口使用方式,以及使用匿名内部类实现。
// 定义一个接口
interface Message{
public void print();
}
// 接口的实现
class MessageIpml implements Message{
@Override
public void print(){
System.out.println("实现的消息");
}
}
public class TestDemo {
public static void main(String[] args) {
Message message = new MessageIpml();
message.print(); // 正常的接访问
// 使用匿名内部类实现
Message msg = new Message(){
@Override
public void print() {
System.out.println("匿名内部类实现的消息");
}
};
msg.print(); // 匿名内部类实现的消息
}
}
抽象类中使用匿名内部类
abstract class Message {
public void execute(double d) {
System.out.println("抽象类的普通方法");
print(); // 调用 抽象 print 方法
calc(d); // 调用有参的方法
}
public abstract void print(); // 无参方法
public abstract void calc(double d); // 有参方法
}
public class TestDemo {
public static void main(String[] args) {
double d = 22.02;
Message msg = new Message(){
@Override
public void print() {
System.out.println("匿名内部类的方法");
}
@Override
public void calc(double d) {
System.out.println("传入有参方法的值为:"+ d);
}
};
msg.execute(d);
}
}