关于java的内部类这些有必要知道
面试的时候,这些问题看似简单,但是未必一下子就能回答出来,今天记录一下吧!
为什么使用内部类?
这个类仅供某个外部类的方法来调用,而不会被其他外部类调用,所以这个类没有必要定义在外部或者单独定义一个类。
- 内部类享有和内部成员同样的待遇,可以使用外部类的静态变量和实例成员变量,也可以使用它所在方法的局部变量。
为什么使用匿名内部类?
如果某个类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?这个时候就引入了匿名内部类,匿名内部类只能使用一次,它通常用来简化代码编写,匿名内部类就是重写父类或接口的方法。例如:
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
这里就在main方法里面建立了一个匿名内部类,它是Person类的子类。
内部类使用它所在方法的局部变量有什么要求?
这个变量必须被final 修饰。
为什么要加final?
- 首先,编译的时候,内部类和外部类一样,都会生成.class文件。
- 这就导致内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁,所以为了防止方法执行完毕,引用了一个不存在的变量,就copy一份局部变量作为内部类的成员变量,当局部变量没有之后,实际访问的是copy的复制品。这样问题就来了,如果你修改了局部变量,这个时候内部类是不知道的,一致性是没办法保证的。
- 因此,设置为final,就是为了保证数据的一致性,这样内部类和外部方法的局部变量就是同一个值了,因为它不可修改,传给内部类的时候,值就已经确定了。
静态内部类和普通内部类的区别?
- 静态内部类的属性和方法可以声明为静态的,普通内部类不可以。
static 不用实例化就能加载进内存,而内部类需要外部类实例化后才能加载进内存。这就间接造成static需要实例化了,与static不需要实例化语义矛盾。
- 实例化的方式不一样,静态内部类是属于类的,普通内部类是属于对象的,静态内部类实例化不需要依附在外部类上面。比如,B是A的静态内部类,A.B b = new A.B()就可以实例化了。
- 静态内部类只能引用外部类的静态属性和方法。
内部类为什么可以访问外部类的私有成员?
- 编译器自动为内部类添加了换一个成员变量,这个成员变量用来指向外部类对象的引用
- 编译器自动为内部类的构造方法中添加一个参数,通过这个参数为1中的成员变量赋值
- 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。
- 编译器会扫描内部类,查看是否调用了外部类的私有属性,自动为外部类生成对应的access$XXX方法,内部类通过外部类的引用调用该方法访问外部类的私有成员。