javaSE学习-面向对象11-内部类

内部类

将一个类定义在另一个类的内部,这个类就是内部类

内部类在外部类中的位置不同,使用也有所不同

位置:

  1. 成员内部类:在外部类的成员位置处,与成员变量、方法位置并列
  2. 局部内部类:在外部类的成员方法中定义,类似局部变量

成员内部类

  • 成员内部类可以直接访问外部类的成员,包括私有成员
  • 外部类访问成员内部类成员,必须创建成员内部类对象
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Outer{
private int num=100;
class Inner{
public void show() {
System.out.println("num="+num);
}
}
}
public class ClassDemo {
public static void main(String[] args) {
Outer.Inner o = new Outer().new Inner();
o.show();
}
}

静态内部类

一般的类是不能用 static 修饰的,但是内部类可以用 static 修饰,因为内部类可以看成是外部类的一个成员,而类的成员可以是静态成员

静态内部类案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Outer{
private int num=10;
private static int numStatic=100;
static class Inner{
public void show() {
//错误,静态内部类不能调用外部非静态成员,只能调用静态成员
//System.out.println("show() - num="+num);
System.out.println("show() - numStatic="+numStatic);
}
public static void showStatic() {
System.out.println("showStatic() - numStatic="+numStatic);
}
}
}
public class ClassDemo {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
inner.show();
inner.showStatic();
//static 方法:showStatic() 的另一种调用方式,直接调用
Outer.Inner.showStatic();
}
}

调用方式

通过外部类调用成员内部类方法
  • 非静态内部类:外部类.内部类 对象名 = new 外部类().new 内部类();
  • 静态内部类
    • 调用静态方法:外部类.内部类.静态方法();
    • 调用非静态方法:外部类.内部类 对象名 = new 外部类.内部类(); 对象名.方法();
在内部类中访问变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ClassDemo {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}

class Outer{
private int num=10;
private static int numStatic=100;
class Inner{
public int num = 20;
public void show() {
int num = 30;
System.out.println("调用内部类方法的局部变量:"+num);
System.out.println("调用内部类的成员变量:"+this.num);
System.out.println("调用外部类的成员变量方式1:"+new Outer().num);
System.out.println("调用外部类的成员变量方式2:"+Outer.this.num);
}
}
}

注意,在这个例子中,访问外部类的成员变量方式2中,只有在内部类是非静态时才可以使用,如果是静态,则不能调用

局部内部类

  • 可以直接访问外部类的成员;
  • 在局部方法内,创建内部类对象,用对象调用内部类的方法
  • 局部内部类只能访问被 final 修饰的局部变量
    • 原因:因为局部变量是随着方法的调用而调用,调用完毕就销毁,而创建的内部类对象在堆内存中不会立即被销毁,此时还是要保留内部类的方法,所以方法调用的变量也要一直保存,所以需要使用关键字 final 使得变量成为常量,数值一直保留不被销毁

匿名内部类

匿名内部类,就是一个类的简化写法

前提:存在一个类或接口,这个类可以是具体类或抽象类

格式:new 类名/接口名(){重写方法}

本质:匿名内部类,就是继承了已经存在的一个类或实现了已经存在的一个接口的匿名对象(new了一个没有名字的对象),

匿名内部类调用

匿名方法实现的接口中单个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface Inter{
public abstract void show();
}
class Outer{
public void method() {
new Inter() {
public void show() {
System.out.println("show 匿名内部类...");
}
}.show();
}
}
public class ClassDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}

匿名方法实现的接口中有多个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Inter{
public abstract void show();
public abstract void show2();
}
class Outer{
public void method() {
Inter i = new Inter() {
public void show() {
System.out.println("show 匿名内部类...");
}
public void show2() {
System.out.println("show2 匿名内部类...");
}
};
i.show();
i.show2();
}
}
public class ClassDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}

匿名内部类注意事项

  • 匿名内部类不能有构造方法
  • 匿名内部类不能定义任何静态成员、方法和类
  • 只能创建匿名内部类的一个实例
  • 匿名内部类也属于局部内部类

考题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface Inter { void show(); }

class Outer{
public static Inter method() {
return new Inter() {
@Override
public void show() {
System.out.println("Hello World!!!");
}
};
}
}

public class ClassDemo {
public static void main(String[] args) {
Outer.method().show();
}
}