前几天去面试Android开发工程师,遇到一个笔试题,说写出java中四种内部类的区别,说实话当时有点难过,平时开发过程中经常在用,但是设计写一些概念的东西的时候,不知道怎么落笔了,有些后悔,今天有时间,从概念,区别,使用场景三个方面做个总结,也希望能帮助到其他童鞋~如果哪里写的不对或者不规范,希望大家能给指正,谢谢。
目录
内部类的基本概念
java的内部类其实说白了就是在一个类中在定义一个类,称之为内部类,内部类可以理解为是一种封装形式,会在下面的例子中有所体现;
四种内部类的介绍以及区别
-
成员内部类
- 有两种初始化内部类的写法;
- 通过非静态内部类的初始化方式可以看到,非静态内部类属于对象,所以必须依赖于对象创建;
- 非静态内部类对main()方法而言是不直接可见的,所以不能直接在main方法中初始化内部类;
- 成员内部类可以无条件的访问外部类的所有的成员属性和方法,不受例如 private 和 static或者其他约束影响;
- 通过下面的例子可以看出,外部类对象也可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段;
//成员内部类
public class Test {
//外部类构造方法
public Test() {
//外部类对象可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段和方法
InnerTest innerTest=new InnerTest();
System.out.println(innerTest.s2);
innerTest.showInner();
}
//外部类成员
private String s1="外部类私有成员变量";
public static void main(String[] args) {
Test test=new Test();
// InnerTest innerTest=test.new InnerTest();
// //外部类对象可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段和方法
// System.out.println(innerTest.s2);
// innerTest.showInner();
}
//外部类普通方法
public void showOut() {
System.out.println(s1);
}
//成员内部类
public class InnerTest{
//内部类私有成员
private String s2="内部类私有成员变量";
//内部类普通方法
private void showInner() {
//成员内部类可以无条件的访问外部类的所有的成员属性和方法
System.out.println(s1+" "+s2);
showOut();
}
}
}
//成员内部类
public class Test {
// //外部类构造方法
// public Test() {
//
// //外部类对象可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段和方法
// InnerTest innerTest=new InnerTest();
// System.out.println(innerTest.s2);
// innerTest.showInner();
// }
//外部类成员
private String s1="外部类私有成员变量";
public static void main(String[] args) {
Test test=new Test();
InnerTest innerTest=test.new InnerTest();
//外部类对象可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段和方法
System.out.println(innerTest.s2);
innerTest.showInner();
}
//外部类普通方法
public void showOut() {
System.out.println(s1);
}
//成员内部类
public class InnerTest{
//内部类私有成员
private String s2="内部类私有成员变量";
//内部类普通方法
private void showInner() {
//成员内部类可以无条件的访问外部类的所有的成员属性和方法
System.out.println(s1+" "+s2);
showOut();
}
}
}
-
静态内部类
- 静态成员的访问方式想必大家都知道,通过类名.静态成员的方式进行访问,同样的,静态类也是作为外部类的一个静态成员直接引用,静态内部类对象也不会依赖于外部类,它和普通内部类不一样,
- 创建内部类对象无需依赖外部类对象,所以可以直接在main()方法中初始化,这是和普通内部类的一个区别,可以理解为静态内部类是独立于外部类存在的;
- 由于静态内部类的独立性,静态内部类中无法访问外部类的非静态成员;
- 外部类可以访问静态内部类对象的所有访问权限的成员;
//静态内部类
public class StaticTest {
private String s1="静态外部类成员";
public static void main(String[] args) {
//可以在main方法中直接初始化,可以理解为静态内部类是独立于外部类存在的
InnerTest innerTest=new InnerTest();
innerTest.innerShow();
System.out.println(InnerTest.s3);
}
static class InnerTest{
private String s2="静态内部类成员";
private static String s3="静态内部类静态成员";
protected void innerShow() {
System.out.println(s2);
}
}
}
-
匿名内部类
- 匿名内部类中可以使用外部类的属性,但是外部类却不能使用匿名内部类中定义的属性;
- 因为是匿名内部类,因此在外部类中无法获取这个类的类名,也就无法得到属性信息;
- 匿名内部没有构造方法。通过new 生成一个对象引用;
- 匿名内部类不能使用 static 和权限修饰符;
- 匿名内部类通常以接口的形式出现,比如我们android开发过程中,添加按钮监听;
下面对以上属性进行验证:大家可以复制代码运行看下效果
//匿名内部类,通常以接口的形式出现
public class NoNameTest implements OnCLickListener{
//外部类成员
public String s1="外部类私有成员";
public static void main(String[] args) {
NoNameTest test=new NoNameTest();
System.out.println("回车模仿按钮监听");
new Scanner(System.in).nextLine();
test.onClick("回车调用");
}
@Override
public void onClick(Object s) {
System.out.println("接口可以访问外部类对象s1="+s1);
System.out.println("接口内部对象不能被外部调用s2="+s2);
}
}
//接口
interface OnCLickListener{
public String s2="匿名内部类公开属性";
void onClick(Object s);
// static void show2(String s);//定义静态会报错
}
-
局部内部类
- 定义在外部类的方法体中,作用域仅限于在方法体中;
- 局部内部类里面可以访问外部类对象的所有访问权限的字段,而外部类却不能访问局部内部类中定义的字段,因为局部内部类的定义只在其特定的方法中,一旦出了这个方法,那么其定义就失效了;
- 外部类不能获取局部内部类的对象;
public class MethodTest {
private String s1="外部类私有成员变量";
public static void main(String[] args) {
MethodTest methodTest=new MethodTest();
methodTest.inner();
}
public void inner() {
class InnerMethodTest{
//内部类私有成员
private String s2="内部类私有成员变量";
//内部类普通方法
private void showInner() {
System.out.println(s1);
System.out.println(s2);
}
}
}
}
内部类多重继承
-
我们可以在外部类中定义多个内部类,分别继承不同的类,这里比较简单,不在做重复测试;