内部类
- 在Java中,可以将一个类定义在另一个类或者方法里边,称之为内部类。
- 一般来讲分为四种,成员内部类,局部内部类,匿名内部类,静态内部类。
1.成员内部类
- 是最普通的内部类,它的定义位于另一个类的内部
- 成员内部类可以无条件访问外部类的所有成员属性和成员方法
- 而外部类访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过此对象的引用来访问
- 成员内部类是依附外部类存在的,若要创建成员内部类的对象,前提是必须存在一个外部类的对象
- 内部类可以拥有private,protected,public访问权限
- 内部类用private修饰,只能在外部类的内部访问
- 代码示例
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Measure { //内部类
public double calculate(double radius) {
return 3.14 * radius *radius ;
}
}
}
2.局部内部类
- 定义在方法或作用域中,与成员内部类的区别在于局部内部类的访问权限仅限于方法内或该作用域内
- 局部内部类就像是方法中的一个局部变量一样,不能被修饰符修饰
- 举个栗子
class A {
public A getHer() {
class B {//局部内部类
//代码
}
}
}
3.匿名内部类
- 匿名内部类的使用频率较高,是唯一一种没有构造器的类,所以使用范围有限
- 类似于回调函数,在编译时由系统生成名字
- 一般用于继承其他类或是实现接口,不需要增加方法,只是堆继承方法的实现或重写
- 代码演示
A(new B() {
@Override
public void c(V v) {
//代码
}
});
4.静态内部类
- 使用static修饰,不需要依赖于外部类,与类的静态成员属性类似
- 不能使用外部的非静态成员变量或方法
- 外部类的非静态成员必须依附于具体的对象
- 代码示例
public class Test {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
}
}
class Outer {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
深入理解内部类
1.为什么成员内部类可以无条件访问外部类的成员?
事实上,编译器在进行编译时会将内部类单独编译成一个字节码文件,换言之,编译后会出现两个class文件。我们在定义内部类时使用无参构造,编译器会默认添加一个参数,该参数的类型为指向外部类对象的一个引用,
所以成员内部类中的指针便指向了外部类的对象,因此可以无条件访问外部类的成员。也说明内部类依附外部类,如果没有创建外部类的对象,则无法创建内部类的对象。
2.为什么局部内部类和匿名内部类只能访问局部final变量?
public class Test {
public static void main(String[] args) {
}
public void test(final int b) {
final int a = 10;
new Thread(){
public void run() {
System.out.println(a);
System.out.println(b);
};
}.start();
}
}
- 上述代码中同样,编译器编译后会生成两个class文件,当test方法执行完毕后,变量a的生命周期就结束了,而此时的Thread对象的生命周期可能没有结束,thread中的run方法就访问不了变量a,但是又要达到这样的效果,怎么办呢?
Java采用l复制方法来解决该问题。匿名内部类中有两个参数,一个是指向外部类对象的引用,一个是int型变量。局部变量的值在编译期间就可以确定,则直接在匿名内部类中创建一个拷贝;如果局部变量的值无法在编译期间确定,
则通过构造器传参进行初始化。也就是说我们所访问的变量根本就不是原方法中的局部变量,那既然不是同一个变量,改变值呢?会造成数据不一致,所以编译器限制局部变量必须为final类型。 - 静态内部类不依赖于外部类,也就是说创建内部类的对象与外部类对象无关,且静态内部类不持有外部类对象的引用。
- 成员内部类的引用方式必须为Outer.Inner
3.静态内部类有什么好处?
- 1.每个内部类都能够独立的继承一个接口的实现,完美的弥补了Java单继承的缺陷。
- 2.方便编写线程相关代码