Java基础——内部类

内部类是什么?

内部类是定义在另一个类中的类,使用场景:

  • 内部类方法可以访问该类定义所在的作用域中的数据
  • 内部类可以对同一个包中的其他类隐藏起来
  • 使用匿名内部类可以减少代码的书写

访问外部数据

内部类Coat可访问外部类Person的age域,或通过Person.this显示调用

class Person {
    private int age;

    public class Coat {
        void printAge() {
            System.out.println(age);
            System.out.println(Person.this.age);
        }
    }
}

为什么?因为内部类存在外部类的隐式引用,其在内部类的构造方法中设置,利用反射还原内部类,可以看到有个指向Person的this$0和对其赋值的构造方法

public class com.example.demo0.Person$Coat {
	final com.example.demo0.Person this$0;
	public com.example.demo0.Person$Coat(com.example.demo0.Person);
	public void printAge();
 }

那内部类是如何调用外部类私有变量age的呢?利用反射还原外部类,可以看到多出一个access$000()静态方法,它将返回接收参数所对应的对象中的域

class com.example.demo0.Person {
	private int age;
	com.example.demo0.Person();
	static int access$000(com.example.demo0.Person);
 }

即System.out.println(age)会转为System.out.println(Person.access$000(this$0))

创建外部类和内部类

外部类创建和普通类一样,而内部类则需要通过outerObject.new InnerClass()创建

Person person = new Person();
Person.Coat coat = person.new Coat();

局部内部类

局部内部类将类定义在方法里,不能用访问修饰符修饰,其作用域在{}块中,除方法体外无任何地方可以访问

class Person {

    public void setCoat(int coat) {
        class Coat {
            public void printCoat() {
                System.out.println(coat);
            }
        }
    }
}

局部内部类可以访问final类型的局部变量(coat),在java 8之前必须显示声明为final,利用反射还原局部内部类,可以看到局部内部类会创建val$coat域用于存储方法的参数

public class com.example.demo0.Person$Coat {
	final int val$coat;
	final com.example.demo0.Person this$0;
	public com.example.demo0.Person$Coat(com.example.demo0.Person,int);
	public void printCoat();
 }

如果在要局部内部类中修改变量,可使用长度为1的数组间接修改

class Person {

    public static void change(int coat) {
        int[] num = new int[1];
        num[0] = 1;
        class Coat {
            public void printNum() {
                num[0] += 1;
            }
        }
    }
}

匿名内部类

对于继承类或实现接口的内部类,且该内部类只创建一次对象,可不用对其命名,转为匿名内部类

class ActionInterface {

    public ActionInterface(String para) {
        System.out.println(para);
    }

    void action() {

    }
}

class Person {

    public void printAction() {
        class ActionImpl extends ActionInterface {

            public ActionImpl(String para) {
                super(para);
            }

            public void action() {
                System.out.println("action");
            }
        }
        ActionImpl actionImpl = new ActionImpl();
        actionImpl.action();
    }
}

将上述代码转为下面的匿名内部类

  1. 因为构造方法同类名,匿名内部类没有类名,故也不能有构造方法,会将构造方法的参数para传给父类构造方法
  2. 对匿名内部类调用getClass()会得到class PackageName.OuterClassName$1(如下为class com.example.demo0.Person$1),再调用getEnclosingClass()可获取其外部类对象
class Person {

    public void printAction() {
        ActionInterface actionImpl = new ActionInterface("para") {
            @Override
            public void action() {
                System.out.println("action");
                System.out.println(this.getClass());
                System.out.println(this.getClass().getEnclosingClass());
            }
        };
        actionImpl.action();
    }
}

利用上面的第二点性质,可实现在静态方法中获取类对象,因为静态方法无this指针,故可创建内部类再间接获取其外部类对象

class Person {

    public static void printClass() {
        //System.out.println(this.getClass());
        System.out.println(new Person(){}.getClass().getEnclosingClass());
    }
}

利用匿名内部类,我们可以实现双括号初始化,如下先创建ArrayList匿名内部类,再使用构造代码块初始化

ArrayList<String> name = new ArrayList<>();
name.add("tom");
name.add("john");

new ArrayList<String>() {{
    add("tom");
    add("john");
}};

静态内部类

上面说到在内部类中存在对外部类的引用OuterClass this$0,如果不需要此引用,可将内部类置为静态内部类

class Person {
    static class Coat {

    }
}

利用反射还原类,只有默认生成的无参构造方法,静态内部类没有对外部类的this$0引用

static class com.example.demo0.Person$Coat {
	com.example.demo0.Person$Coat();
 }

Tips:接口中的内部类自动声明为static和public

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值