内部类

内部类是一类特殊的类,指的是定义在一个类的内部的类。实际开发中,为了方便的使
用外部类的相关属性和方法,这时候我们通常会定义一个内部类。

上图所示,内部类共分为:匿名内部类局部内部类成员内部类。而成员内部类又可以分成非静态内部类静态内部类


内部类的概念

一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内
部定义,称为内部类(innerclasses)。内部类可以使用public、default、protected 、private 以及static 修饰。而外部顶级类(我们以前接触的类)只能使用public 和default 修饰。

==注意!!==

内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer 的外部类和其内部定义的名为Inner 的内部类。编译完成后会出现==Outer.class== 和==Outer$Inner.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
27
28
/**内部类Outer*/
public class Outer {

private int age = 100;

private void show()
{
System.out.println("这是外部类!");
}


public static void main(String[] args) {
Outer.Inner newname = new Outer().new Inner();
newname.inner();
}

/**内部类Inner*/
public class Inner{
private int age = 110000;
//内部类中可以声明与外部类同名的属性与方法
//非静态方法可以调用静态成员或者方法
public void inner(){
System.out.println(age); //110000
System.out.println(Test000.this.age); //100
show(); //这是外部类!
}
}
}

内部类的作用:
内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。


非静态内部类

非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)

  • 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象

  • 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。

  • 非静态内部类不能有静态方法、静态属性和静态初始化块。

  • 成员变量访问要点:(例子同上面代码)

    1. 内部类里方法的局部变量:变量名。
    2. 内部类属性:this.变量名。
    3. 外部类属性:外部类名.this.变量名。

非静态内部类对象创建方式

非静态内部类对象新建方式一共有两种:(针对Outer类内嵌Inner类举例)

1
2
3
4
5
6
//第一种方式
Outer.Inner in01 = new Outer().new Inner(); //此时in01作为内部类的对象可以实现方法或者成员调用

//第二种方式
Outer out02 = new Outer();
Inner in02 = out02.new Inner(); //此时in02作为内部类的对象可以实现方法或者成员调用

静态内部类

与大多数静态方法相似,静态内部类只需要在类名前加上static即可

1
2
3
4
static class ClassName
{
//类体
}
  • 静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。
  • 静态内部类看做外部类的一个静态成员。
    (这点与静态方法不能调用非静态成员性质一致)

静态内部类对象创建方式

依旧针对Outer类内嵌Inner类举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//通过new 外部类名.内部类名() 来创建内部类对象
Outer.Inner in03 = new Outer.Inner();

-----------------------------------------------
//一些举例
Class Outer{
public static int a = 100;
public int b = 200;
static class Inner{
puiblic void print(){ //静态内部类方法即便前面没有加static修饰也会被定义为静态方法
System.out.println(a); //可以正常输出100
System.out.println(b); //静态方法不能调用非静态属性,这行代码会报错
}
}
}

匿名内部类

Java 中可以实现一个类中包含另外一个类,且不需要提供任何的类名直接实例化。主要是用于在我们需要的时候创建一个对象来执行特定的任务,可以使代码更加简洁。匿名类是不能有名字的类,它们不能被引用,只能在创建时用 new 语句来声明它们。

1
2
3
4
5
//语法体
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
//匿名类继承父类

//一个定义类
class Polygon {
public void display() {
System.out.println("在 Polygon 类内部。");
}
}

class AnonymousDemo {
public void createClass() {

// 创建的匿名类继承了 Polygon 类
Polygon p1 = new Polygon() {
public void display() {
System.out.println("在匿名类内部。");
}
};
p1.display();
}
}
//实例中,创建了 Polygon 类,该类只有一个方法 display(),AnonymousDemo 类继承了
//Polygon 类并重写Polygon 类的 display() 方法
class Main {
public static void main(String[] args) {
AnonymousDemo an = new AnonymousDemo();
an.createClass();
}
}

上述代码中,AnonymousDemo匿名类中的createClass()方法内部继承类新建了一个Polygon对象并改写Override了display()方法,这中间的p1对象调用并销毁次数与方法调用次数一致。

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
//匿名类实现接口
//首先定义一个接口
interface Inter{
void run(); //内部只有一个run()方法
}

//再定义一个实现,这是一个有名字的类,是可以反复调用新建对象的
class Imp implements Inter{

@override
public void run(){
System.out.println("我正在跑!");
}
}

//然后定义public主类
public class AnonymousInnerClass{
public void test(Inter a)
{
a.run(); //方法的定义
}
public static void main(String[] args)
{
AnonymousInnerClass b = new AnonymousInnerClass(); //创建对象
// b.test(); //!!括号内需要传参
//一般情况下,我们可以通过implements实现接口,这里我我们采用匿名类;
b.test(new Imp); //可以通过定义的实现完成接口,输出结果为 我正在跑!

//此外,可以通过定义匿名类来实现接口

b.test(new Inter(){ //没有实际名字的类
@Override
public void run(){
System.out.println("我正在慢跑五分钟!");
}
}); //定义和调用同时进行,调用结束,这个类直接被销毁
//每一次调用,这个方法只能调用一次,每一次都是新的
}
}

局部内部类

定义在方法内部的,作用域只限于本方法,称为局部内部类。

局部内部类的的使用主要是用来解决比较复杂的问题,想创建一个类来辅助我们的解决
方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员
内部类一样被编译,只是它的作用域发生了改变,它只能在该方法中被使用,出了该方法就
会失效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 测试局部内部类
*/
public class TestLocalInnerClass {
public void show() {
//作用域仅限于该方法
class Inner {
public void test() {
System.out.println("Hello World");
}
}
new Inner().test(); //调用结束就销毁
}
public static void main(String[ ] args) {
new TestLocalInnerClass().show();
}
}