Java内部类

[TOC]

内部类可对同一包中其他类隐藏,内部类方法可以访问定义这个内部类的作用域中的数据,包括 private 数据。

内部类是一个编译器现象,与虚拟机无关。编译器会把内部类转换成常规的类文件,用 $ 分隔外部类名与内部类名,其中匿名内部类使用数字编号,虚拟机对此一无所知。

静态内部类: 属于外部类,只加载一次。作用域仅在包内,可通过 外部类名.内部类名 直接访问,类内只能访问外部类所有静态属性和方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class ClassOuter {
private int noStaticInt = 1;
private static int STATIC_INT = 2;

public void fun() {
System.out.println("外部类方法");
}

public class InnerClass {
//static int num = 1; 此时编辑器会报错 非静态内部类则不能有静态成员
public void fun(){
//非静态内部类的非静态成员可以访问外部类的非静态变量。
System.out.println(STATIC_INT);
System.out.println(noStaticInt);
}
}

public static class StaticInnerClass {
static int NUM = 1;//静态内部类可以有静态成员
public void fun(){
System.out.println(STATIC_INT);
//System.out.println(noStaticInt); 此时编辑器会报 不可访问外部类的非静态变量错
}
}
}

public class TestInnerClass {
public static void main(String[] args) {
//非静态内部类 创建方式1
ClassOuter.InnerClass innerClass = new ClassOuter().new InnerClass();
//非静态内部类 创建方式2
ClassOuter outer = new ClassOuter();
ClassOuter.InnerClass inner = outer.new InnerClass();
//静态内部类的创建方式
ClassOuter.StaticInnerClass staticInnerClass = new ClassOuter.StaticInnerClass();
}
}

成员内部类: 属于外部类的每个对象,随对象一起加载。不可以定义静态成员和方法,可访问外部类的所有内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}

class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
System.out.println(count); //外部类的静态成员
}
}
}

局部内部类: 定义在方法内,不能声明访问修饰符,只能定义实例成员变量和实例方法,作用范围仅在声明类的代码块中。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class test {
public void show(){
class Inner{
public void fun(){
System.out.println("HelloWorld");
}
}
new Inner().fun();
}
public static void main(String args[]){
new test().show();
}
}

匿名内部类: 只用一次的没有名字的类,可以简化代码,创建的对象类型相当于 new 的类的子类类型。用于实现事件监听和其他回调。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface Product {
public double getPrice();
public String getName();
}
public class test1 {
public void test (Product p)
{
System.out.println(p.getName()+"--------"+p.getPrice());
}
public static void main(String [ ] args )
{
test1 as= new test1 ();
as.test(new Product( )//此处实现接口并实现抽象方法
{
public double getPrice( )//实现方法
{
return 8888;
}
public String getName( )//实现方法
{
return "I can do it ";
}

});
}
}

匿名内部类在方法中声明,可以访问方法中的临时变量吗 为什么

  1. 原因是:因为局部变量和匿名内部类的生命周期不同。

    匿名内部类是创建后是存储在堆中的,而方法中的局部变量是存储在Java栈中,当方法执行完毕后,就进行退栈,同时局部变量也会消失。那么此时匿名内部类还有可能在堆中存储着,那么匿名内部类要到哪里去找这个局部变量呢?

    为了解决这个问题编译器为自动地帮我们在匿名内部类中创建了一个局部变量的备份,也就是说即使方法执结束,匿名内部类中还有一个备份,自然就不怕找不到了。

    但是问题又来了。如果局部变量中的a不停的在变化。那么岂不是也要让备份的a变量无时无刻的变化。为了保持局部变量与匿名内部类中备份域保持一致。编译器不得不规定死这些局部域必须是常量,一旦赋值不能再发生变化了。所以为什么匿名内部类应用外部方法的域必须是常量域的原因所在了。

    特别注意:在Java8中已经去掉要对final的修饰限制,但其实只要在匿名内部类使用了,该变量还是会自动变为final类型(只能使用,不能赋值)。