内部类的含义
定义:内部类我们从字面看是非常容易理解的,无非就是在一个类的内部再定义一个类。
作用:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
分类:在 java 中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类
成员内部类
成员内部类:内部类对象依赖外部类对象而存在,即在创建一个普通内部类对象时首先需要创建其外部类对象。
内部类对象可以访问外部类对象中所有访问权限的字段,同时,外部类对象也可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段
成员内部类可以使用任何访问权限修饰符进行修饰(一般类只能使用 public 权限或默认权限)
成员内部类格式如下:
public class OuterClass {
private String name;
public void run() {
}
public class InnerClass {
}
}
编译上述代码会产生两个文件:Outer.class
和Outer$Inner.class
。内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)
在没有创建外部类的对象前,不可以直接创建内部类的对象,所以以下的写法是错误的:
其实这个规则很好理解,因为内部类可以使用外部类的成员变量,所以如果外部类还没有创建,而内部类的使用外部类成员变量就没有意义。
但是在 OuterClass 内的 run 方法中是可以创建 InnerClass 的,因为 OutterClass 对象已经创建了才能执行run方法:
public class OuterClass {
private String name;
public void run() {
InnerClass ic = new InnerClass();
}
public class InnerClass {
}
}
非静态内部类
非静态内部类中不能定义静态成员,例如:
class A{
class B{
//在一个类内部定义一个类,这个类前面没有静态关键字
//static int i;错误的,不能定义静态成员变量
}
}
不能单独创建B实例,如果想创建B实例,首先应该创建A实例,例如:
A a = new A();
A.B b = a.new B();
静态内部类
在一个类内部定义一个静态内部类。静态内部类格式如下:
public class A {
static class B{
}
}
静态的含义是该内部类可以像其他静态成员一样,没有外部类对象时,也能够访问它。静态嵌套类仅能访问外部类的静态成员和方法。
A.B b = new A.B();
举例1:创建非静态内部类和静态内部类
我们在 A 类中创建静态内部类 B 和非静态内部类 C
public class A {
static class B {
//有静态关键字,属于A类
}
class C {
}
}
创建 B 和 C 时语法如下:
public class Main {
public static void main(String[] args) {
A.B b = new A.B();
System.out.println("已经创建静态内部类B实例");
A a = new A();
A.C c = a.new C();
System.out.println("已经创建非静态内部类C实例");
}
}
与普通静态成员相同,静态内部类也会优先加载到内存,所以在静态内部类中不可以访问外部类的非静态成员
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,例如:
class Outer {
public void doSomething() {
class Inner {
public void seeOuter() {
}
}
}
}
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public
、protected
、private
以及static
修饰符的,所以以下写法是错误的:
我们把前边的 private 删掉,也不代表它有默认的权限,因为没有权限这一说,就像Inner 中的 seeOuter 方法中不能写 private int x = 10; 一样。
匿名内部类
匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
举例2:创建局部内部类和匿名内部类
定义一个 Weapon 接口,有进攻(kill()
)方法
public interface Weapon {
void kill();
}
Main.java
public class Main {
public static void main(String[] args) {
Weapon weapon = f1();
weapon.kill();
Weapon weapon2 = f2("倚天剑");
weapon2.kill();
}
private static Weapon f1() {
class AK47 implements Weapon {
@Override
public void kill() {
System.out.println("使用AK47");
}
}
return new AK47();
}
private static Weapon f2(String name) {
//只有一对括号,匿名类{}
//直接创建一个匿名类,并赋给一个实例,让匿名类实现父接口
Weapon w = new Weapon() {
@Override
public void kill() {
System.out.println(name);
}
};//赋值运算,后边需要分号
return w;
}
}
运行结果: