java内部类的定义及使用
一、内部类的概述
内部类(inner class): 定义在一个类中的另一个类,外层的类称外部类。
为什么要使用内部类?
- 内部类可以对同一个包中的其它类隐藏。
- 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据。
- 内部类可以解决java单继承的缺陷
二、内部类的几种类型
1.成员内部类
成员内部类: 即定义在外部类中,与外部类的成员属性以及成员方法同级别的类。
定义格式:
public class Outer{
private String name="外部类属性";
private int id = 1;
private String str ="outer";
class Inside{
private String name ="内部类属性";
private int id = 2;
public void fun() {
//打印外部类同名属性
System.out.println(Outer.this.name); //外部类属性
System.out.println(Outer.this.id); //1
//打印内部类同名属性
System.out.println(this.name); //内部类属性
System.out.println(this.id); //2
//直接调用外部类属性
System.out.println(str); //outer
outerFun(); //内部类中直接调用外部类方法
}
}
public void outerFun() {
System.out.println("外部类方法");
}
}
创建对象的格式:
class Test{
public static void main(String[] args) {
//创建外部对象
Outer outer = new Outer();
//创建内部类对象
Inside inside = outer.new Inside();
inside.fun();
// 直接创建
Outer.Inside i = new Outer().new Inside();
i.fun();
两种创建方式:
- 先创建外部类对象,再创建内部类对象
- 直接创建通过“外部类名称.内部类名称 变量名 = new 外部类名称().new 内部类名称”。
注意事项:
1.当内部类和外部类有【同名变量时】,内部类使用"外部类名称.this.属性名"的方式进行访问外部类属性,内部类则通过this关键字调用自身属性。而当外部类需要访问内部类成员属性时,则需要创建对象;
2. 成员内部类不能定义静态成员这是因为:
内部类要使用需要实例化,在那之前是需要外部类实例化后再去实例化内部类,所以要加载内部类必须在实例化外部类之后完成 ,但是java虚拟机要求所有的静态变量必须在对象创建之前完成, 这样便产生了矛盾。
2.局部内部类
局部内部类: 定义在外部类方法中的类,作用范围和创建对象范围仅限于当前方法。
定义格式:
public class Outer2 {
private String name = "张三";
public void fun() {
int num = 1; //局部变量,默认final修饰
class Inside2{ //局部内部类,
private String name ="李四";
// private Static int a =2; //不允许使用 static修饰符
public void insideFun() {
// num = 2; 不能修改
System.out.println(name); //李四
}
}
Inside2 in2 = new Inside2(); //实例化局部内部类
in2.insideFun();
}
}
测试:
public static void main(String[] args) {
Outer2 ou2 = new Outer2();
ou2.fun(); //调用fun方法
}
注意事项:
由于局部内部类不能在外部类的方法以外的地方使用,因此局部内部类也不能使用控制符合static修饰符修饰.
且局部变量必须使用final修饰,jdk1.8后默认使用final修饰;局部内部类只能使用abstract 或final修饰。
3.静态内部类
静态内部类: 使用static关键字修饰,不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
定义格式:
public class Outer1 {
private String name ="外部类属性";
static class Inside1{ //静态内部类
private static String name = "静态内部类属性";
public static void fun() {
//访问静态内部类属性
System.out.println(Inside1.name); //打印静态内部类
//访问外部类属性,必须先实例化外部类,再进行调用
Outer1 outer1 = new Outer1();
System.out.println(outer1.name); //打印外部类属性
}
public void show() {
System.out.println("静态内部类普通方法");
}
}
}
测试:
public static void main(String[] args) {
//如果静态内部类中为普通方法,则需创建静态内部类实例对象调用
Inside1 in1 = new Inside1();
in1.show();
//静态方法直接通过类名调用
Inside1.fun();
}
注意事项:
静态加载总是比非静态的快,即静态内部类中不能直接访问外部类属性,必须先实例化外部类进行调用;在main方法中,可直接通过静态内部类类名进行访问静态方法;如果访问非静态方法,则必须先实例化对象。
4.匿名内部类(常用)
匿名内部类: 即没有名字的内部类,其特征和局部类内部类相同。
使用前提:必须先继承一个父类或实现一个接口
定义格式:
例如实现一个USB接口运转功能
//定义一个接口
public interface InterUsb {
void run(); //读入功能
}
//定义一个电脑类插入接口功能
public class Comeper {
public void reed(InterUsb interUsb) { //实现usb接口具体读入功能
interUsb.run();
}
}
测试类:
public class TestUsb {
public static void main(String[] args) {
// 使用匿名内部类实现接口功能,从而省略接口的实现类定义
InterUsb inter = new InterUsb() {
@Override
public void run() {
System.out.println("接口开始运转");
}
};
inter.run();
}
}
格式:
new 接口名{
// 重写方法
}
当只实现某一接口功能,且只使用一次时,可以采用匿名内部类的方法进行实现,从而减少了,实现类的单独定义,减少了开发中的代码量。