七、面向对象(高级)

一、类变量和类方法

1. 类变量

类变量(静态变量/静态属性):是该类所有对象共享的变量,该类所有的对象都可以对齐进行修改或引用。

语法:static : 表示静态

1
2
3
访问修饰符 static 数据类型 变量名;(推荐该写法)

static 访问修饰符 数据类型 变量名;

引用语法:

1
2
3
类名.类变量名;(推荐使用)

对象名.类变量名;

:::note

  1. 类变量是随着类的加载而创建的,即使没有创建对象,也可以访问;
  2. 类变量的访问,也要遵守访问修饰符的访问权限;
  3. 没有加 static 则表示为实例变量,不共享,加上则表示为 类变量,是共享的;
  4. 类变量的生命周期时随着类的加载而加载,随着类的消亡而消亡;
    :::

2.类方法

类方法,也叫静态方法;

语法:

1
访问修饰符 static 返回数据类型 方法名(){};(推荐写法)

调用:

1
类名.类方法名();

::: warning

  1. 非静态方法不能通过类调用,只能通过对象调用;
  2. 静态方法既可以通过类调用,也可以通过类调用;
  3. 类方法中不允许使用和对象有关的关键字
    1. 如: this,super
  4. 静态方法中,只能访问静态变量或静态方法
    1. 普通成员方法 都可以访问;
      :::

静态方法,只能访问静态的成员;
普通方法,静态与非静态的成员都可以访问;

使用场景:
::: tip

  1. 用来编写不涉及对象的方法,比如:工具类
    :::

二、代码块

代码块(初始化块):属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过{}包围起来;
与方法不同,没有方法名,没有返回,没有参数,只有方法体,不能通过对象或类显式调用,在加载类或创建对象时隐式调用

语法:

1
[修饰符]{代码};

:::warning

  1. 修饰符 可选,要写只能写 static
  2. 没有修饰符的叫普通代码块,有修饰符的叫静态代码块
  3. “;” 可以省略
  4. 代码块的调用顺序优先于构造器
    :::

:::note
类什么时候加载:

  1. 创建实例对象时
  2. 创建子类对象实例时,父类也会加载(父类先加载,子类后加载);
  3. 使用类的静态成员时
    :::

:::tip
细节:

  1. 静态代码块只会执行一次,普通代码块 每创建一个对象,就会执行一次
    1. 如果只使用静态成员时,普通成员不会执行
  2. 创建对象时,类 调用顺序:
    1. 调用静态代码块和静态属性初始化(优先级一样,多个时按定义顺序调用)
    2. 调用普通代码块和普通属性的初始化(同上)
    3. 调用构造器方法
  3. 构造器的前面隐含了 super()和 调用普通代码块,静态相关的代码块和属性初始化在类加载时就执行完成了,因此是优先于 构造器和普通代码块执行的。
  4. 有继承关系的子类对象在创建时的调用顺序:
    1. 父类静态代码块、静态属性(优先级一样,按定义顺序执行)
    2. 子类静态代码块、静态属性(优先级一样,按定义顺序执行)
    3. 父类普通代码块、普通属性(优先级一样,按定义顺序执行)
    4. 父类的构造方法
    5. 子类普通代码块、普通属性(优先级一样,按定义顺序执行)
    6. 子类的构造方法
  5. 静态代码块只能调用静态成员,普通代码块可以调用任意成员
    :::
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 StaticDemo01 {
public static void main(String[] args) {
StaticDemo01.demo1();
System.out.println("======================");
new StaticDemo01().demo2();
}

private static String name1 = getName1();
private String name2 = getName2();

public static String getName1() {
System.out.println("静态属性 被执行~~~");
return name1;
}

public String getName2() {
System.out.println("普通属性 被执行~~~");
return name2;
}

{
System.out.println("普通代码块 被执行~~~");
}
static {
System.out.println("静态代码块 被执行~~~");
}
public static void demo1(){
System.out.println("静态方法 被执行~~~");
}
public void demo2(){
System.out.println("普通方法 被执行~~~");
}

public StaticDemo01() {
System.out.println("构造函数 被执行~~~");
}
}

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
public class StaticDemo02 {
public static void main(String[] args) {
Test a = new Test();
}
}

class Sample{
Sample(String s){
System.out.println(s);
}
Sample(){
System.out.println("Sample 默认构造器函数被调用");
}
}
class Test{
Sample sam1 = new Sample("sam1 成员初始化");
static Sample sam = new Sample("静态成员 sam 初始化");
static {
System.out.println("static 快执行");
if (sam == null){
System.out.println("sam is null");
}
}
Test(){
System.out.println("Test 默认构造器函数被调用");
}
}

三、单例设计模式

单例模式: 采取一定的方法,使某个类只存在一个对象实例,并且该类只提供一个获取对象实例的方法。
单例模式:
①。饿汉式: 类在加载时直接创建一个对象,不管后续有没有使用;
②。懒汉式: 只有当使用时,类才会加载一个对象;

:::note
饿汉式 和 懒汉式 设计模式的实现:

  1. 构造器私有化(防止直接 new 对象)
  2. 类的内部创建对象
  3. 向外暴露一个静态的公共方法
    :::
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
// 单例模式 - 饿汉式 案例
public class SingleTon01 {
public static void main(String[] args) {
GirlFriend friend = GirlFriend.getInstance();
System.out.println(friend);
}
}

class GirlFriend{
private String name;
// 构造方法私有化
private GirlFriend(String name) {
this.name = name;
}
// 类的内部创建对象,因需要一个静态方法返回,所以创建对象也需要静态化
private static GirlFriend gf = new GirlFriend("小汪");
// 暴露给外部的方法
public static GirlFriend getInstance(){
return gf;
}

@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
'}';
}
}
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
// 单例模式 - 懒汉式
public class SingleTon02 {
public static void main(String[] args) {
Cat c = Cat.getInstance();
System.out.println(c);
}
}

class Cat{
private String name;
private static Cat cat;

private Cat(String name) {
this.name = name;
}
// 如果已经创建了一个对象,则不在创建,如果没有创建对象,则会创建一个对象
public static Cat getInstance(){
if (cat == null){
cat = new Cat("你老子");
}
return cat;
}

@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}

四、final 关键字

final : 表示最后的、最终的
final 可以用于修饰类、属性、方法、局部变量等

:::tip
使用场景:

  1. 当不希望类被继承时,可以使用 final 修饰
  2. 当不希望父类的某个方法被子类覆盖、重写时,可以使用 final 关键字修饰
  3. 当不希望某个属性的值被修改时,可以使用 final 修饰
  4. 当不希望某个是不变量被修改时,可以使用 final 修饰
    :::

:::note
注意事项:

  1. final 修饰的属性又叫常量,一般用 全大写字母 和 下划线 来命名
    1. NUM_TEST
  2. final 修饰的属性在定义时,必须赋初始值,并且以后不能再修改
    1. 定义时:如:public final double TAX_RATE = 0.08;
    2. 在构造器中赋值;
    3. 在代码块中赋值;
  3. 如果 final 修饰的是静态属性,则初始化的位置只能
    1. 在定义时
    2. 在静态代码块中
    3. 不能在构造器中赋值
  4. final 类不能继承,但是可以实例化对象
  5. 如果类不是 final 类,但是含有 final 方法,则该方法虽然不能重写,但是可以被继承
  6. 如果一个类 被 final 修饰了,那么他的方法就没有必要再用 final 修饰
  7. 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// final 关键字
public class Final01 {
public static void main(String[] args) {
System.out.println(new AA("小王"));
CC cc = new CC();
// 方法被 final 修饰后,子类可以继承但是不能重写
cc.prints();
}
}

class AA{
// 定义时赋值
public final double TAX_RATE = 0.08;
private final String name;
private final int age;

{ // 代码块中赋值
age = 18;
}
// 构造器中赋值
public AA(String name) {
this.name = name;
}

@Override
public String toString() {
return "AA{" +
"TAX_RATE=" + TAX_RATE +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}

class BB{
// 静态方法只能在 定义时 或 静态代码块中初始化
private static final String name;
private static final int age = 18;
static {
name = "小明";
}
public final void prints(){
System.out.printf("name=%s,age=%d",name,age);
}
}

class CC extends BB{ }

五、抽象类(abstract)

抽象类: 当类中的某些方法不确定时,就可以使用 abstract 关键字将方法修饰为抽象方法,用 abstract 修饰类成为抽象类,一般都会由子类继承,由子类来实现抽象方法。

语法:

1
2
3
4
// 抽象类及抽象方法
abstract class Demo{
public abstract String demo();
}

::: tip
注意事项:

  1. 抽象类和抽象方法必须使用 abstract 修饰;
  2. 抽象方法没有方法体;
  3. 抽象类一般都会被继承,由子类重写抽象方法;
  4. 抽象类不能实例化;
  5. 抽象类不一定有抽象方法,但是有抽象方法,则必须是抽象类;
  6. abstract 只能修饰 类 或 方法;
  7. 如果继承了抽象类,则必须实现抽象方法,或者自己也申明为抽象类
  8. 抽象方法不能用 final、static、private 来修饰,与抽象方法规则相违背;
    :::
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 抽象类
abstract public class Employee {
private String name;
private int age;
private double salary;

public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public double getSalary() {
return salary;
}

public void setSalary(double salary) {
this.salary = salary;
}

abstract public void work();
}

class CommonEmployee extends Employee{
public CommonEmployee(String name, int age, double salary) {
super(name, age, salary);
}


@Override
public void work() {
System.out.printf("普通员工 %s 工作中~~~\n",getName());
}
}

class Manager extends Employee{
private double bonus;

public Manager(String name, int age, double salary, double bonus) {
super(name, age, salary);
this.bonus = bonus;
}

public double getBonus() {
return bonus;
}

public void setBonus(double bonus) {
this.bonus = bonus;
}

@Override
public void work() {
System.out.printf("经理 %s 工作中……\n",getName());
}
}

class Test{
public static void main(String[] args) {
CommonEmployee ce = new CommonEmployee("小李", 25, 3000);
ce.work();
Manager mg = new Manager("老王", 40, 5000, 1000);
mg.work();
}
}
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
// 抽象 - 模板模式
public class AbstractTime {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime();
}
}

abstract class Template{
public abstract void job();
// 抽象类 计算任务执行所需的时间
public void calculateTime(){
long startTime = System.currentTimeMillis();
job();
long endTime = System.currentTimeMillis();
System.out.printf("执行时间为:%d",(endTime-startTime));
}
}

class AA extends Template{
// 重写父类的抽象方法
@Override
public void job() {
for (int i = 1; i <= 8000000 ; i++) {
i++;
}
}
}

六、接口

接口: 就是给出一些没有实现的方法封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
使用 interface 来定义接口
使用 implement 来实现接口

语法:

1
2
3
4
5
6
7
8
interface 接口名{
属性或方法;
}

class 类名 implement 接口名{
自己的属性或方法;
必须实现抽象方法;
}

::: warning
注意事项:

  1. 接口不能被实例化;
  2. 接口中所有的方法都是 public 方法,接口中的抽象方法 可以不用 abstract 修饰
  3. 一个普通类实现接口,就必须将该接口的所有方法都实现
  4. 抽象类实现接口,可以不用实现接口的方法
  5. 一个类同时可以实现多个接口
  6. 接口中的属性,只能是 final 的,而且是 public static final 修饰符
    1. 如: int a =1; 实际上是 public static final int a = 1;(必须初始化)
  7. 接口中属性的访问形式: 接口名.属性名
  8. 一个接口不能继承其他的类,但是可以继承多个接口
    1. 如: interface A extends B,C{}
  9. 接口的修饰符只能是 public 和 默认,这点和 类的修饰符一样
    :::

当子类继承类父类,就自动拥有父类的功能,如果子类需要扩展功能,则可以通过实现接口的方式扩展
实现接口 是对 java 单继承的一个补充

:::note
继承 与 接口实现的区别:

  1. 继承时,会自动拥有父类的所有功能;
    1. 接口是对 单继承的一种补充,用于扩展子类功能
  2. 继承主要解决代码的复用性和可维护性
    1. 接口主要用于设计各种规范,让其他类去实现这些方法
  3. 接口相较于继承更加灵活
    :::
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
// 接口与继承
public class ExtendsVsInterface {
public static void main(String[] args) {
LittleMonkey wk = new LittleMonkey("悟空");
wk.work();
wk.flying();
wk.swimming();
}
}

class Monkey{
private String name;

public Monkey(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public void work(){
System.out.println(String.format("%s 会爬树",name));
}
}

class LittleMonkey extends Monkey implements FishAble,BirdAble{
public LittleMonkey(String name) {
super(name);
}

@Override
public void swimming() {
System.out.printf("%s 通过学习,可以像鱼一样游泳~\n",getName());
}

@Override
public void flying() {
System.out.printf("%s 通过学习,可以像鸟一样飞翔~\n",getName());
}
}

interface FishAble{
void swimming();
}

interface BirdAble{
void flying();
}

:::tip
接口的多态特性:

  1. 多态参数(一个接口有多个方法实现时,通过参数判断实现对象)
  2. 多态数组
  3. 多态传递(一个接口继承了另一个接口)
    :::
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
// 接口 - 多态数组
public class InterfacePoly {
public static void main(String[] args) {
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camera_();
for (int i = 0; i < usbs.length; i++) {
if (usbs[i] instanceof Phone_){
((Phone_) usbs[i]).call();
}
usbs[i].work();
}
}
}

interface Usb{
void work();
}

class Phone_ implements Usb{
public void call(){
System.out.println("用手机打电话");
}
@Override
public void work() {
System.out.println("手机工作中");
}
}

class Camera_ implements Usb{
@Override
public void work() {
System.out.println("相机工作中");
}
}

七、内部类

内部类 : 一个类的内部又完整的嵌套了另一个类结构,

类的五大成员: 属性、代码块、构造器、方法、内部类
语法:

1
2
3
4
class Outer{	// 外部类
class Inner{ // 内部类
}
}

:::note
内部类的分类:

  1. 根据定义在外部类的位置:
    1. 局部内部类(有类名)
    2. 匿名内部类(没有类名)
  2. 根据定义在外部类的成员位置:
    1. 成员内部类(没有 static 修饰)
    2. 静态内部类(有 static 修饰)
      :::

1. 局部内部类

:::tip
说明:

  1. 通常定义在方法中;
  2. 可以直接访问外部类的所有成员,包括私有的属性或方法;
  3. 不能添加访问修饰符,但是可以使用 final 修饰符
  4. 作用域:只在定义他的方法或代码块中使用``
  5. 局部内部类访问外部类时,可以直接访问
  6. 外部类访问局部内部类时,需要先创建对象,在进行访问
  7. 外部其他类不能访问局部内部类
  8. 如果外部类和内部类的成员重名,则默认采取就近原则,
    1. 如果要访问外部类成员,可以使用 外部类.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
46
47
48
49
50
51
// 局部内部类
public class LocalClass {
public static void main(String[] args) {
AA aa = new AA("老王");
aa.method1();

}
}

class AA{
private String name;

public AA(String name) {
this.name = name;
}

public void method1(){
// 不能使用访问修饰符,但是可以使用 final,使用后不能被其他类继承
final class BB{
private String name;

public BB(String name) {
this.name = name;
}
public void method1(){
// 内部类属性与外部类属性同名时,默认访问的是内部类属性,可以通过 类名.this.属性 获取外部类
System.out.printf("局部内部类,内部类 name= %s,外部类 name= %s\n",name,AA.this.name);
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
// 外部类访问内部类时,需要先创建对象,然后在访问
BB bb = new BB("张三");
bb.method1();
System.out.println("访问类外部类方法");
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

2.匿名内部类

语法:

1
2
3
new 类或接口(形参){
类体;
}

:::danger
注意事项:

  1. 调用匿名内部类的方法:
    1. new A(){}.cry();
    2. A a = new A(){}; a.cry();
  2. 可以直接访问外部类的所有成员,包括私有属性
  3. 不能添加访问修饰符,因为它就是一个局部变量
  4. 作用域:仅定义在他的方法或代码块中
  5. 外部其他类,不能访问匿名内部类
  6. 外部类和内部类的成员重名时,默认遵守就近原则;
    :::
    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
    // 匿名内部类 - 案例 1
    public class LocalClass2 {
    public static void main(String[] args) {
    Cellphone cellphone = new Cellphone();
    cellphone.alarmclock(new Bell() {
    @Override
    public void ring() {
    System.out.println("懒猪起床了");
    }
    });
    cellphone.alarmclock(new Bell() {
    @Override
    public void ring() {
    System.out.println("小伙伴们上课了");
    }
    });
    }
    }

    interface Bell{
    void ring();
    }

    class Cellphone{
    public void alarmclock(Bell bell){
    bell.ring();
    }
    }
    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
    57
    58
    59
    // 匿名内部类 - 案例 2
    public class AnonymousInnerClass {
    public static void main(String[] args) {
    Other01 other01 = new Other01();
    other01.method1();
    }
    }

    class Other01{
    public void method1(){
    // 基于 接口 的匿名内部类
    // 匿名内部类 只能被调用一次,但是对象可以调用多次(tiger 为对象)
    IA tiger = new IA() {
    @Override
    public void cry() {
    System.out.println("老虎叫~~~");
    }
    };
    // 匿名内部类调用
    tiger.cry();

    // 基于 类 的匿名内部类
    // 不加 {},则为普通的创建对象,加上 {} 则表示匿名内部类
    Father father = new Father("张三"){
    @Override
    public void test() {
    System.out.println("匿名内部类重写类 test 方法");
    }
    };
    father.test();

    // 基于 抽象类 的匿名内部函数
    Animal animal = new Animal(){
    @Override
    void eat() {
    System.out.println("实现抽象类的抽象方法");
    }
    };
    animal.eat();
    }
    }

    interface IA{
    void cry();
    }

    class Father{
    String name;
    public Father(String name){
    this.name = name;
    };
    public void test(){
    System.out.println(name);
    };
    }

    abstract class Animal{
    abstract void eat();
    }

3.成员内部类

成员内部类定义在外部类的成员位置,并且没有 static 修饰

:::tip

  1. 可以直接访问外部类的所有成员,包括私有成员
  2. 可以添加任意访问修饰符(public、protected、默认、private),他的定位时成员;
  3. 作用域:和外部类的成员方法一样
  4. 成员内部类 可以直接访问 外部类
  5. 外部类 访问 成员内部类时,需要先创建内部类对象,再访问
  6. 外部其他类 可以访问 内部成员类
  7. 如果外部类和内部类的成员重名,则默认遵守就近原则
    1. 如果要访问外部类成员,则 通过(外部类名.this.成员名)访问
      :::
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      // 外部其他类访问 成员内部类的方法

      // 方法 1
      Outer1 outer1 = new Outer1();
      Innter1 innter1 = outer1.new Innter1();

      // 方式 2
      Innter2 innter2 = new Outer2().new Innter2();

      // 方式 3(使用一个方法来获取)
      Innter3 innter3d = new Outer3().getInnter3();
      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
      // 成员内部类 - 案例
      public class LocalClass3 {
      public static void main(String[] args) {
      Outer1 outer1 = new Outer1();
      outer1.t1();

      // 外部其他类 访问成员内部类
      // 通过外部类对象,创建成员内部类实例对象
      Outer1.Inner1 inner1 = outer1.new Inner1();
      inner1.say();
      // 通过 成员方法调用 成员内部类
      Outer1.Inner1 inner1 = outer1.getInner1();
      inner1.say();
      }
      }

      class Outer1 {
      private int n1 = 10;
      private String name = "张三";
      // 成员内部类
      // 成员内部类可以使用任何 访问修饰符
      public class Inner1{
      public void say(){
      // 内部类 可以直接访问外部类成员方法或属性,包括私有属性
      System.out.printf("n1= %d,name= %s",n1,name);
      }
      }

      public void t1(){
      // 外部类访问成员内部类时,需要先创建内部类对象,再进行访问
      Inner1 inner1 = new Inner1();
      inner1.say();
      }

      // 编写一个方法,返回 成员内部类的实例对象
      public Inner1 getInner1(){
      return new Inner1();
      }
      }

4.静态内部类

静态内部类定义在 外部类的成员位置, 并且有 static 修饰符

:::tip

  1. 可以直接访问外部类的所有静态成员,包括私有的,但不能直接访问非静态成员
  2. 可以添加任意访问修饰符,因为它定位为成员
  3. 作用域: 和其他成员相同
  4. 静态内部类可以直接访问外部类的静态成员
  5. 外部类访问静态内部类时,需要先创建对象,再进行访问
  6. 外部其他类 可以访问 静态内部类
  7. 如果外部类和静态内部类的成员重名,则默认遵守就近原则
    1. 如果要访问外部类成员,则 通过(外部类名.成员名)访问
      :::
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
// 静态内部类 - 案例
public class LocalClass3 {
public static void main(String[] args) {
Outer1 outer1 = new Outer1();
outer1.m1();

// 外部其他类 访问 静态内部类
// 1. 通过外部类的类名访问
Outer1.Inner1 inner1 = new Outer1.Inner1();
inner1.say();

// 2. 通过方法 返回一个内部类对象
Outer1.Inner1 inner11 = outer1.getInner1();
inner11.say();

// 通过静态方法返回
Outer1.Inner1 inner2 = Outer1.getInner2();
inner2.say();
}
}

class Outer1 {
private int n1 = 10;
private static String name = "张三";

public static void cry(){
System.out.println("静态方法");
};

public static class Inner1{
public void say(){
System.out.println(name);
cry();
}
}

public void m1(){
Inner1 inner1 = new Inner1();
inner1.say();
}

// 普通方法,返回静态内部类对象
public Inner1 getInner1(){
return new Inner1();
}

// 静态方法,返回静态内部类对象
public static Inner1 getInner2(){
return new Inner1();
}
}