java基础(八)

本次记录内部类,内部类我感觉挺特别的,既有类的感觉,又有方法和变量的感觉。内部类是定义在类里的,所以我们通常把内部类之外的类,称为外部类。

成员内部类

我们都知道,在类定义的变量称为成员变量,内部类也一样,定义在类里的类,就是成员内部类。

1
2
3
4
5
6
7
8
class A
{

class b
{

}
}

上面就是成员内部类的表示,那怎么使用呢。先想想,类,我们一开始使用时,如果它使用的都是普通方法,要先new对不对。如果是静态方法,则可以引入这个类,直接调用。是不是有感觉了。是类,要先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
27
28
29
30
31
32
33
public class innerClass {
public static void main(String[] args) {

A.B b = new A().new B();
b.print();

// 也可以这样new一个内部类B的对象
// A a = new A();
// A.B b1 = a.new B();
// b1.print();
A.C c = new A.C();
c.print();
}
}
class A
{

class B //是一个普通的内部类
{
public void print()
{
System.out.println("我是B");
}
}

static class C //static修饰,是个静态内部类
{
public void print()
{
System.out.println("我是C");
}
}
}

都如期打印相应的print()方法,我们也看得出来,我们在使用内部类的时候,都要先new父类的对象,如果内部类是静态,直接 . 使用,否则还要new内部类的对象。


当然,这里如图补充一句,平时我们写java代码,编译器都会给我们的代码编译成.class的字节码,方便虚拟机在任何平台运行,而上图也看得出来,我们的代码虽然在同一个java文件,但是编译器会把它以类的形式分开,而且,如果是内部类,则会有一个$符号,表示它是谁的内部类。

还有,你也可以不停的写内部类里写内部类,内部类里的内部类写内部类里的内部类的内部类……有点像递归啦。下面则是一个例子。而它的.class也就生成了 A$C$D.class 这样,会一直延伸下去。

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 innerClass {
public static void main(String[] args) {

A.C.D d = new A.C().new D();
d.print();

}
}
class A
{
static class C
{
class D
{
public void print()
{
System.out.println("我是D");
C.this.print();
}
}
public void print()
{
System.out.println("我是C");
}
}
}

上面的代码里有个this,this指向当前对象。谁的当前对象,是C的。当前C的print()方法。所以这里先后打印了我是D和我是C。等下就讲外部类使用内部类的属性方法,内部类如何使用外部类的属性方法。

局部内部类

局部内部类就像局部变量一样,出了相应的范围就不能使用。所以我们只能在方法里使用局部内部类,它的外部类是不能调用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class innerClass {
public static void main(String[] args) {

A a = new A();
a.print();
}
}
class A
{
public static void print()
{
class B
{
void printB()
{
System.out.println("我是B");
}
}
B b = new B();
b.printB();
}
}

外部类和内部类的互相使用

先看一看外部类如何使用内部类的属性和方法吧。

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
public class innerClass {
public static void main(String[] args) {

A a = new A();
a.printA();
//A.B b = new A().new B(); 报错
}
}
class A
{
private int x;
private class B
{
int y;
private int z;
public void print()
{
System.out.println("我是B");
}
}

public void printA()
{
B b = new B();
b.print();
b.y = 1;
b.z = 2;
System.out.println("y:"+b.y);
System.out.println("z:"+b.z);
}
}

看到很多有意思的东西,我们把内部类B私有化,这样内部类B就是外部类A独享的moment,所以它不能被其他类所访问,我们可以在外部类中,使用方法去新建内部类,使用它的方法,属性。而我们也看到,内部类中的z是私有的,但是我们可以在外部类中使用,看到z被赋值啦。

注意啦,外部类使用内部类可以在方法里调用。外部类也可以使用内部类私有的属性和方法。

下面则是内部类使用外部类的方法和属性。

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
public class innerClass {
public static void main(String[] args) {

A.B b = new A().new B();
b.print();

}
}
class A
{
private int x=1;
int z;
private int c = 2;
public void print()
{
System.out.println("这是A");
}

class B
{
int x = 3;

public void print()
{
z = 1;
x = 2;
c = 3;
System.out.println("内部类的x:"+x);
System.out.println("外部类的x:"+A.this.x);
System.out.println("外部类的z:"+z);
System.out.println("外部类的c:"+c);
A.this.print();
}
}
}

可以看得出来,内部类在使用外部类属性方法时,也同样在方法里使用,但可以直接使用。如果内部类和外部类有相同的变量名,可以用this来指向外部类的变量。而且,也同样,内部类也可以使用外部类的私有属性方法。

当然,这就有一点要注意的,上面两个代码,内部类都是非静态内部类。我们在前面的学习可以知道,在我们运行代码时,虚拟机会提前把静态的,常量,方法名加载到内存中,如果内部类为静态的呢,会怎么样。

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
38
39
40
41
42
43
44
45
public class innerClass {
public static void main(String[] args) {

A a = new A();
a.print();
A.B b = new A.B();
b.print();

}
}
class A
{
private int x=1;
int z;
private int c = 2;
public void print()
{

System.out.println("这是A");
B.x = 1;
B b = new B();
b.y = 2;
System.out.println(B.x);
System.out.println(b.y);
b.print();
}

static class B
{
static int x = 3;
int y = 3;

public void print()
{
// z = 1;
x = 2;
// c = 3;
System.out.println("内部类的x:"+x);
// System.out.println("外部类的x:"+A.this.x);
// System.out.println("外部类的z:"+z);
// System.out.println("外部类的c:"+c);
// A.this.print();
}
}
}

在上面的代码中,注释的都是报错的代码,而这些代码则是静态内部类使用外部类的属性方法。而外部类,则可以使用静态内部类的方法属性。为什么呢,还是和虚拟机运行机制有关。静态先加载出来,所以一开始静态内部类就比外部类先出现在内存上,而静态内部类要使用外部类的方法属性时。编译器找不到外部类,因为它没加载到内存上,所以报错。在外部类为什么能使用呢,也很简单,当我们使用外部类的时候,一定是把这个类先new出来了,虽然内部类提前加载到内存上,但new出了外部类,自然也就能使用静态内部类的方法属性。

以上是内部类像普通变量一样,有静态的,私有的,公共的,成员或局部。当然,内部类也可以定义为final修饰的,但,那就和私有差不多,只能外部类使用,而且比私有更恐怖的就是不能更改,毕竟final修饰。

抽象内部类

上面说完了内部类像变量一样的使用,而我们的类,除了普通的类,还是抽象类和接口对不对。所以内部类也有这样的特征,但也有不一样的地方。

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
public class innerClass {
public static void main(String[] args) {

A.B b = new A().new B() {

@Override
void print() {
System.out.println("主main");

}
};
b.print();

A.C c = new A().new C();
c.print();
}
}
class A
{
abstract class B
{
abstract void print();
}
class C extends B
{

@Override
void print() {
System.out.println("C实现抽象类B的方法");

}
}
}

上面就是抽象内部类的两种使用,当然,第一种肯定是不推荐使用的那种,方法全写在main方法里了,占空间,不好看。推荐下面的那种写法,和普通抽象类一样的继承使用。

内部接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class innerClass {
public static void main(String[] args) {

A.C c = new A().new C();
c.print();
}
}
class A
{
interface B
{
abstract void print();
}
class C implements B
{

@Override
public
void print() {
System.out.println("C实现内部接口B的方法");

}
}
}

和抽象内部类使用方法差不多,也没啥好说的,毕竟接口就是比抽象类更抽象的类。

匿名内部类

匿名类就是没有变量名的类,之间new一个类使用它的方法。比如下面的类,直接使用,当然,这种类就是一次性的,因为没有名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class innerClass {
public static void main(String[] args) {

new A().print();
}
}
class A
{
void print()
{
System.out.println("Hello");
}
}

那内部类的匿名怎么使用呢?

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
public class innerClass {
public static void main(String[] args) {
A.B b = new A().new B();
b.print();

}
}

class A
{
class B
{
void print()
{
new C() {

@Override
public void print() {
System.out.println("C");
}
}.print();
}
}
}

//abstract class C
//{
// abstract public void print();
//}

interface C
{
abstract void print();
}

如上使用,在内部类把抽象类或接口的方法实现,然后调用相应的方法,可以看到最后有个.print()。我调用了这个方法。匿名内部类的要点就是要实现抽象类或接口的方法,而这些方法可能只用一次。

谢谢您对我的支持
0%