概述
最近学习python,发现python是支持多继承的,这让我想起Java是通过内部类实现的这套机制。这篇文章不是讲如何通过内部类实现多继承,而是总结一下内部类的类型和使用方法。
Java内部类分为:
- 非静态内部类
- 静态内部类
- 局部内部类
- 匿名内部类
内部类在Android源码中被大量的使用,先介绍一下这四种内部类的共同点:
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因为内部类可以*的访问外部类的成员,包括private成员。
- 内部类声明为静态的,就不能随意的访问外部类的成员变量了,此时内部类只能访问到外部类的静态成员变量。
接下来,分别介绍一下这几种内部类。
非静态内部类
当一个类作为另一个类的非静态成员时,则这个类就是一个非静态内部类。
创建非静态内部类的示例代码如下:
1
2
3
|
class OutClass {
class InnerClass {}
}
|
当我们用javac去编译的时候,发现生成了两个.class文件:OutClass.class和OutClass$InnerClass.class。如下图所示:
从外部类的非静态方法中实例化内部类
在外部类中访问内部类是很容易的,直接创建内部类对象,然后通过对象实例调用类内的方法即可。示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class OutClass {
private static int a = 0 ;
public void makeInner() {
InnerClass inClass = new InnerClass();
inClass.seeOuter();
}
public static void main(String[] args) {
OutClass oClass = new OutClass();
oClass.makeInner();
}
class InnerClass {
public void seeOuter() {
System.out.println(a);
a++;
}
}
}
|
1
|
0
|
从外部类的静态方法中实例化内部类
在外部类中访问内部类是比较简单的,可以直接new出内部类对象,但是如果想在外部类的外部使用内部类,接不能直接new内部类名的方式了,而是需要如下方式:
1
|
OutClass.InnerClass innerClass = new OutClass(). new InnerClass();
|
也就是说,在外部调用非静态内部类,需要先实例化外部类,然后通过外部类对象再去实例化内部类。示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class OutClass {
private static int a = 0 ;
public void makeInner() {
InnerClass inClass = new InnerClass();
inClass.seeOuter();
}
public static void main(String[] args) {
OutClass oClass = new OutClass();
oClass.makeInner();
OutClass.InnerClass innerClass = new OutClass(). new InnerClass();
innerClass.seeOuter();
}
class InnerClass {
public void seeOuter() {
System.out.println(a);
a++;
}
}
}
|
运行结果:
1
2
|
0
1
|
内部类的this引用
普通的类可以使用this引用当前的对象,内部类也是如此。但是假若内部类想引用外部类当前的对象呢?可以使用如下方式:
外部类名.this
示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class OutClass {
private static int a = 0 ;
public void makeInner() {
InnerClass inClass = new InnerClass();
inClass.seeOuter();
}
public static void main(String[] args) {
OutClass oClass = new OutClass();
oClass.makeInner();
OutClass.InnerClass innerClass = new OutClass(). new InnerClass();
innerClass.seeOuter();
}
class InnerClass {
public void seeOuter() {
System.out.println( this );
System.out.println(OutClass. this );
}
}
}
|
静态内部类
上面介绍了非静态内部类,接下来我们学习神马是静态内部类。
静态内部类就是在外部类中扮演一个静态成员的角色,创建静态内部类和创建非静态内部类的形式很相似,只是class前面多了一个static修饰符。
注意,外部类是不可能使用static修饰符进行修饰的。
示例代码如下:
1
2
3
4
|
class OutClass {
static class InnerClass {
}
}
|
用javac命令编译一下,可以看到一样都是有两个.class文件,如下图所示:
从外部类的非静态方法中实例化静态内部类
从外部类中访问静态内部类,和在外部类中访问非静态内部类是一样的。但是,需要注意一点,此时静态内部类只能访问外部类的静态成员,无法访问非静态成员了。
示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class OutClass {
private static int a = 0 ;
private int b = 1 ;
public void makeInner() {
InnerClass inClass = new InnerClass();
inClass.seeOuter();
}
public static void main(String[] args) {
OutClass oClass = new OutClass();
oClass.makeInner();
}
static class InnerClass {
public void seeOuter() {
System.out.println( this );
System.out.println(a);
// System.out.println(b);
}
}
}
|
执行结果如下:
1
2
|
OutClass$InnerClass@79a340
0
|
从外部类静态方法中实例化静态内部类
注意:
因为静态内部类是外部类的静态成员,而静态成员是跟类绑定,而不是跟类实例化的对象绑定。所以,在外部类的静态方法中实例化内部类,是不需要先实例化外部类的。
示例代码如下:
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
|
public class OutClass {
private static int a = 0 ;
private int b = 1 ;
public void makeInner() {
InnerClass inClass = new InnerClass();
inClass.seeOuter();
}
public static void main(String[] args) {
OutClass oClass = new OutClass();
oClass.makeInner();
OutClass.InnerClass inClass = new OutClass.InnerClass();
inClass.seeOuter();
}
static class InnerClass {
public void seeOuter() {
System.out.println( this );
System.out.println(a);
// System.out.println(b);
}
}
}
|
匿名内部类
匿名内部类在Android应用开发中简直是泛滥,各种listener对象的实现很多都是通过匿名内部类。
匿名内部类从名字上就可以知道这是代表没有类名的内部类,通常用来简化代码。
相信写Java的同学都使用过线程,那Thread的时候我们可以传一个Runnable对象,也可以传一个匿名内部类。示例代码如下:
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 class OutClass {
public void testAnonymousClass() {
Thread t = new Thread( new Runnable() {
@Override
public void run() {
for ( int i = 0 ; i < 10 ; i ++) {
System.out.println(i);
try {
Thread.sleep( 500 );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
System.out.println( "another thread is running..." );
}
public static void main(String[] args) {
OutClass oClass = new OutClass();
oClass.testAnonymousClass();
}
}
|
执行结果如下:
1
|
another thread is running...
|