内部类
概念
在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。
内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。(非静态)内部类拥有外部类的所有元素的访问权限。
分类
内部类可以分为:实例内部类、静态内部类和局部内部类,关系为:一般把实例内部类就叫成成员内部类
内部类与外部类的关系
成员内部类的创建需要依赖于外部类对象-(成员方法必须通过对象调用),在没有外部类实例之前无法创建成员内部类对象
内部类与外部类相对独立,不是is a 的关系(发动机-汽车)
私有属性的互相访问,实例内部类可以直接访问外部类(所有元素),而静态内部类不能访问外部类的非静态元素,而外部类访问内部类需要内部类的对象来访问
public class Outer {
private String name = "CK";
class Inner {
private String name1 = "Ql";
public void innerTest() {
System.out.println(name);---->Ck
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
String name = inner.name1;---->Ql
}
}
在内部类内部使用隐藏(private)的外部类对象(隐藏的this)
public class Outer {
private String name = "CK";
class Inner {
private String name = "Ql";
public void innerTest() {
//如果不定义Ql,name=Ck;定义了Ql,name=Ql。
//System.out.println(name);
System.out.println(this.name);---->Ql
System.out.println(Outer.this.name);---->Ck
}
}
特点
内部类的特点如下:
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的
.class
文件,但是前面冠以外部类的类名和$
符号。 - 内部类不能用普通的方式访问,外部类访问内部类需要内部类的对象来访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
- 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。
访问修饰符
对于外部类来说,只有两种修饰,public和默认(default),因为外部类放在包中,只有两种可能,包可见和包不可见。
从作用范围的角度来说,对于顶级类(外部类)来说,有两种修饰符:public和默认(default)。因为外部类的上一单元是包,所以外部类只有两个作用域:同包,任何位置。因此,只需要两种控制权限:包控制权限和公开访问权限,也就对应两种控制修饰符:默认(default)和public。
对于内部类来说,可以有所有的修饰,因为内部类放在外部类中,与成员变量的地位一致,所以有四种可能。
实例内部类
成员内部类(上图的实例内部类):类比成员方法(其实指的就是实例方法),不能拥有静态域但是可以访问外部类的静态域
public class Outer {
private String name = "CK";
private static int a = 6;
class Inner {
//static String name = "Ql";//不能定义静态变量和方法
public void innerTest() {
System.out.println(name);//访问非静态成员
System.out.println(a);//访问静态成员
}
}
}
创建成员内部类对象
外部类内部,外部类外部
Outer.Inner inner = new Outer().new Inner();
静态内部类
定义在外部类的内部,使用static修饰,类比静态方法,静态内部类不需要外部类对象产生就能使用,不能访问外部类的成员域,但能访问静态域
public class Outer {
private String name = "CK";
private static int a = 6;
static class Inner {
private String name1 = "Ql";
public void innerTest() {
System.out.println(name);//这里会报错
System.out.println(a);
}
}
}
创建静态内部类对象
外部类内部
Inner inner1 = new Inner();
外部类外部
Outer.Inner inner = new Outer().new Inner();
普通内部类只能包含非静态变量、非静态方法、非嵌套类。
静态内部类可以包含静态和非静态变量、静态和非静态方法、静态和普通内部类。
静态内部类可以定义在接口中,并作为接口的一部分来使用。
局部内部类
在方法或某个作用域内的内部类,称为局部内部类。匿名内部类就是一种局部内部类。
public class Outer {
private String name = "CK";
private static int a = 6;
public void InnerClass() {
//解掉这行注释name就会报错,可以访问外围类的成员变量。如果是static方法,则只能访问static修饰的成员变量。
//public static void InnerClass() {
class Inner {
private double a = Math.random();
public void innerTest() {
System.out.println(a);
System.out.println(name);
}
}
Inner inner = new Inner();
inner.innerTest();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.InnerClass() ;
}
}
只能在方法内部,类(局部内部类)定义之后使用,不存在外部可见性问题,因此没有访问修饰符。
不能在局部内部类中使用可变的局部变量。
可以访问外围类的成员变量。如果是static方法,则只能访问static修饰的成员变量。
可以使用final 或 abstract修饰。
匿名内部类
由于匿名内部类不利于代码的重用,因此,一般在确定此内部类只会使用一次时,才会使用匿名内部类。
必须继承一个抽象类或者实现一个接口
没有构造方法
public class Outer {
public Runnable test(){
//匿名内部类
return new Runnable() {
@Override
public void run() {
System.out.println("Ck");
}
};
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.test().run();
}
}