tags:

  • 内部类
  • Java编程思想
    categories:
  • Java
    author: Jang
    title: 内部类
    date: 2019-01-06 11:26:00

什么是内部类

把一个类的定义放在另一个类的定义内部,这个类就是内部类。

内部类可以访问外围类的所有成员。

在创建内部类实例对象时,首先要获得一个外部类的引用,然后通过.new的方式来创建:Out.Inner in = out.new Inner();

成员内部类

在一个类中以成员的形式定义一个内部类,就是最基础的内部类

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
public class Outer{
private String a = "a";
public int i = 1;

//内部类
class Inner{
private String b = "b";
public String c = "c";

public int getInt(){
return i; //内部类可以访问外部类的成员变量
}

private String getString(){
return a + b + c;
}
}

public String getParam(){
Inner inner = new Inner();
inner.b = "bb";
inner.c = "cc";
return inner.getInt() + inner.getString();
}
}
//测试类
class Test {
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.getParam()); // 输出:1abbcc

Outer.Inner oi = outer.new Inner();
oi.c = "ccc";
//oi.b = "bbb"; 编译失败
System.out.println(oi.getInt()); // 输出:1
//System.out.println(oi.getString()); 编译失败
}
}

上面的代码就是一个最简单的内部类的使用。总接一下内部类的使用要点:

  • 内部类可以访问外部内的所有变量
  • 在外部类中使用内部类,需要通过 new 关键字创建一个实例对象。并且外部类可以访问到内部类所有的变量和方法。
  • 在其他类中创建内部类对象需要使用这样的形式:OuterClass.InnerClass inner = new OuterClass.new InnerClass()。并且在其他类是不能访问内部类的四私有方法和对象的。
  • 内部类通过 .this 的方式可以获得外部类的引用。

静态内部类

在定义内部类的时候,用 static 关键字修饰

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
46
47
48
49
50
51
52
53
54
55
56
public class Outer {
private int i = 1;
public static String str = "str";

static class StaClass implements inter{
private String s = "s";
static int j = 2;

static int getInt(){
//return i + j;
return j;
}

private String getString(){
return str + s;
}

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

static class InStaClass{
int x = 4;
static int y = 5;
static int getInt(){
//return x; // x是非静态变量 不可以在静态方法中使用
return y;
}
}
}

public inter getInter(){
return new StaClass();
}
}

interface inter{
void inter();
}

class Test{
public static void main(String[] args) {
int a = Outer.StaClass.getInt();

//Outer.StaClass.getString(); // getString()为非静态方法,不能这样调用

int b = Outer.StaClass.InStaClass.getInt();

System.out.println(a + "----" + b); // 输出 2----5

//new Outer().new StaClass(); 编译失败 StaClass是静态的

new Outer().getInter().inter(); // 输出 inter
}
}

通过上面的代码,可以看出来静态内部类有以下特点:

  • 静态内部类中可以定义静态的成员变量,也可以定义非静态的成员变量。
  • 在静态内部类中只能访问外部类的静态变量和方法,不能访问非静态的变量和方法。
  • 静态内部类的静态方法可以在其他类中通过,OuterClass.InnerClass.StaticMethod 这样的方式调用。
  • 在其他类中,静态内部类是不能通过 new OuterClass.new InnerClass() 这样的方式获得。但是在外部类中可以通过 new 获得一个静态内部类的实例对象。
  • 静态内部类中不能使用 .this 来获得外部类的引用。

局部内部类

局部内部类是在一个方法或者任意作用域中定义的内部类。在有些情况下,需要一个类来辅助解决问题,但是又不希望这个类是公共可用的,这个时候可以用局部内部类来解决问题。

在方法中定义的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Animal {
public Run howToRun(){
class RunWithLeg implements Run{
@Override
public void runWith() {
System.out.println("Run with leg");
}
}
return new RunWithLeg(); //向上转型
}

public static void main(String[] args) {
Run animal = new Animal().howToRun();
animal.runWith();
}
}


interface Run{
void runWith();
}

这样在 Run 方法执行的时候,内部类才会存在,当 Run 方法执行结束。内部类就无法使用了。

在任意作用域中嵌入内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Add {
public static void main(String[] args) {
System.out.println(new Add().add(8));
}

public int add(int num){
if (num > 5){
class Other{
private int i = 10;
public int getNum() {
return i + num;
}
}
return num + new Other().getNum();
}else {
// new Other().getNum; 超过作用域
return 0;
}
}
}

这样的内部类只能在 (num > 5) 这个作用域范围内生效。

匿名内部类

匿名内部类主要适用于对于一个接口的隐式实现。

JDK1.8 以前如果在匿名内部类中引用外部的定义的对象,这对象必须是final的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
};//注意:分号不能省
}

public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chengfan");
System.out.println(inner.getNumber());
}
}

interface InnerClass {
int getNumber();
}

匿名内部类的使用要点:

  • 匿名内部类是没有访问修饰符的,且其中不能存在任何静态成员变量或者是静态方法
  • 匿名内部是不能包含构造器的,可以通过构造代码来模拟构造器。

Java8 中使用 lambda表达式 来代替大部分的内部类,可以让代码看上去更为简洁。