!!! note 目录

一、类的定义

在计算机编程中,类(Class)是一种抽象数据类型(ADT),它是面向对象编程(OOP)的基本概念之一。类是对现实世界中对象的抽象,它定义了对象的属性(成员变量)和行为(成员方法)。

类的定义通常包括以下几个要素:

  1. 类名(Class Name):类的名称用于标识该类,在代码中可以通过类名来引用该类。类名通常使用大驼峰命名法(Pascal Case)。

  2. 成员变量(Member Variables):也称为属性或字段(Fields),用于描述类的状态或特征。成员变量可以是各种数据类型(如整数、浮点数、字符串等),它们代表了对象的各种属性。在类的定义中,成员变量通常以变量名和数据类型的形式列出。

  3. 成员方法(Member Methods):也称为函数或操作(Methods),用于描述类的行为或功能。成员方法定义了对象可以执行的操作,它们可以操作对象的状态,并且可以被外部代码调用以执行特定的任务。在类的定义中,成员方法通常以方法名、参数列表和返回类型的形式列出。

  4. 构造方法(Constructor):是一种特殊类型的成员方法,用于在创建对象时初始化对象的状态。构造方法的名称与类名相同,并且通常没有返回类型。在Java等编程语言中,通过调用构造方法可以创建类的实例。

  5. 访问修饰符(Access Modifiers):用于控制类的成员对外部代码的可见性和访问权限。常见的访问修饰符包括public、protected、private等。

一个简单的类定义示例(使用Java语言)如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyClass {
// 成员变量
private int myNumber;
private String myString;

// 构造方法
public MyClass(int number, String str) {
this.myNumber = number;
this.myString = str;
}

// 成员方法
public void printDetails() {
System.out.println("Number: " + myNumber);
System.out.println("String: " + myString);
}
}
/*
在这个示例中,类名为MyClass,包含了两个成员变量(myNumber和myString)、一个构造方法(MyClass)和一个成员方法(printDetails)。
这个类定义了一个简单的数据结构,表示了一个具有整数和字符串属性的对象,并且提供了一个方法用于打印对象的属性。
*/

二、类对象的创建和使用

创建和使用类对象是面向对象编程中的基本操作,它们使我们能够使用类定义的属性和方法来操作对象。

以下是创建和使用类对象的一般步骤:

  1. 类定义:首先,我们需要定义一个类,其中包括类的属性(成员变量)和方法(成员方法)。
  2. 对象实例化:在程序中,通过使用类的构造方法来创建类的实例(对象)。构造方法会初始化对象的状态,并返回一个指向该对象的引用。
  3. 访问成员变量:一旦对象被创建,我们可以使用点操作符(.)来访问对象的成员变量,并为其赋值或获取值。
  4. 调用成员方法:同样,我们也可以使用点操作符来调用对象的成员方法,并向方法传递参数(如果需要)。

以下是一个简单的示例,演示了如何创建类对象并使用它:

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 MyClass {
// 成员变量
private int myNumber;
private String myString;

// 构造方法
public MyClass(int number, String str) {
this.myNumber = number;
this.myString = str;
}

// 成员方法
public void printDetails() {
System.out.println("Number: " + myNumber);
System.out.println("String: " + myString);
}
}

public class Main {
public static void main(String[] args) {
// 创建类对象
MyClass obj = new MyClass(10, "Hello");

// 访问成员变量
int number = obj.myNumber;
String str = obj.myString;
System.out.println("Number: " + number);
System.out.println("String: " + str);

// 调用成员方法
obj.printDetails();
}
}
/*
在这个示例中,我们首先定义了一个名为MyClass的类,其中包含了一个构造方法(用于初始化对象的状态)和一个成员方法(用于打印对象的属性)。
然后,在Main类中,我们通过调用MyClass的构造方法创建了一个名为obj的对象。
接着,我们通过点操作符访问对象的成员变量,并调用对象的成员方法来操作对象。
*/

三、JVM内存分析

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
package com.camellia.oop01;
/*实例变量属于成员变量,成员变量如果没有手动赋值,系统会赋默认值
数据类型 默认值
----------------------
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
boolean false
char \u0000
引用数据类型 null
*/
public class Student {

// 属性:姓名,年龄,性别,他们都是实例变量

// 姓名
String name;

// 年龄
int age;

// 性别
boolean gender;
}
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
package com.camellia.oop01;

public class StudentTest01 {
public static void main(String[] args) {
// 局部变量
int i = 10;

// 通过学生类Student实例化学生对象

(通过类创造对象)
// Student s1; 是什么?s1是变量名。Student是一种数据类型名。属于引用数据类型。
// s1也是局部变量。和i一样。
// s1变量中保存的是:堆内存中Student对象的内存地址。
// s1有一个特殊的称呼:引用
// 什么是引用?引用的本质上是一个变量,这个变量中保存了java对象的内存地址。
// 引用和对象要区分开。对象在JVM堆当中。引用是保存对象地址的变量。
Student s1 = new Student();

// 访问对象的属性(读变量的值)
// 访问实例变量的语法:引用.变量名
// 两种访问方式:第一种读取,第二种修改。
// 读取:引用.变量名 s1.name; s1.age; s1.gender;
// 修改:引用.变量名 = 值; s1.name = "jack"; s1.age = 20; s1.gender = true;
System.out.println("姓名:" + s1.name); // null
System.out.println("年龄:" + s1.age); // 0
System.out.println("性别:" + (s1.gender ? "男" : "女"));

// 修改对象的属性(修改变量的值,给变量重新赋值)
s1.name = "张三";
s1.age = 20;
s1.gender = true;

System.out.println("姓名:" + s1.name); // 张三
System.out.println("年龄:" + s1.age); // 20
System.out.println("性别:" + (s1.gender ? "男" : "女")); // 男

// 再创建一个新对象
Student s2 = new Student();

// 访问对象的属性
System.out.println("姓名=" + s2.name); // null
System.out.println("年龄=" + s2.age); // 0
System.out.println("性别=" + (s2.gender ? "男" : "女"));

// 修改对象的属性
s2.name = "李四";
s2.age = 20;
s2.gender = false;

System.out.println("姓名=" + s2.name); // 李四
System.out.println("年龄=" + s2.age); // 20
System.out.println("性别=" + (s2.gender ? "男" : "女")); // 女


}
}

JVM内存分析图

从此图可以看出,开始将所有类的字节码存储到元空间当中,当对象被创建时就在堆内存中开辟一个空间,用于存储对象和实例变量等。然后通过引用实现对对象的一系列操作。
其中对象属性等的改变都发生在堆内存中,引用只不过保存了它的地址(这和C++中的指针很像)。

四、实例变量和实例方法的访问

  1. 实例变量要想访问,必须先new对象。通过引用来访问实例变量。
  2. 实例变量是不能通过类名直接访问的。
  3. 我们通常描述一个对象的行为动作时,不加static。 没有添加static的方法,被叫做:实例方法。(对象方法)
  4. 空指针异常:一个空引用访问实例相关的,都会出现空指针异常。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Pet {

    String name; // 实例变量
    // 出生日期
    String birth;
    // 性别
    char sex;

    // 方法:行为动作
    // 吃
    public void eat(){ // 实例方法
    System.out.println("宠物在吃东西");
    }
    // 跑
    public void run(){
    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
    29
    30
    public class PetTest02 {
    public static void main(String[] args) {
    // 创建宠物对象
    Pet dog = new Pet();

    // 给属性赋值
    dog.name = "小黑";
    dog.birth = "2012-10-11";
    dog.sex = '雄';

    // 读取属性的值
    System.out.println("狗狗的名字:" + dog.name);
    System.out.println("狗狗的生日:" + dog.birth);
    System.out.println("狗狗的性别:" + dog.sex);

    dog = null;

    // 注意:引用一旦为null,表示引用不再指向对象了。但是通过引用访问name属性,编译可以通过。
    // 运行时会出现异常:空指针异常。NullPointerException。这是一个非常著名的异常。
    // 为什么会出现空指针异常?因为运行的时候会找真正的对象,如果对象不存在了,就会出现这个异常。
    //System.out.println("狗狗的名字:" + dog.name);

    // 会出现空指针异常。
    dog.eat();

    // 会出现空指针异常。
    //dog.run();
    }
    }
    //java.lang.NullPointerException

    如果没有任何引用指向对象,该对象最终会被当做垃圾被GC回收。

五、方法调用时传递参数

5.1、方法调用时传递基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.camellia.oop04;

/**
* 面试题:判断该程序的输出结果
*/
public class ArgsTest01 {
public static void main(String[] args) {
int i = 10;
// 调用add方法的时候,将i传进去,实际上是怎么传的?将i变量中保存值10复制了一份,传给了add方法。
add(i);
System.out.println("main--->" + i); // 10
}
public static void add(int i){ // 方法的形参是局部变量。
i++;
System.out.println("add--->" + i); // 11
}
}

在这里插入图片描述

5.2、方法调用时传递引用数据类型

1
2
3
4
package com.camellia.oop04;
public class User {
int age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.camellia.oop04;

/**
* 面试题:分析以下程序输出结果
*/
public class ArgsTest02 {
public static void main(String[] args) {
User u = new User();
u.age = 10;
// u是怎么传递过去的。实际上和i原理相同:都是将变量中保存的值传递过去。
// 只不过这里的u变量中保存的值比较特殊,是一个对象的内存地址。
add(u);
System.out.println("main-->" + u.age); // 11
}
public static void add(User u) { // u是一个引用。
u.age++;
System.out.println("add-->" + u.age); // 11
}
}

这个和基本数据类型原理相同。首先明确引用数据类型中应用存储的是User的地址,所以add(User u);实质上是将main中的引用u里存储的值(就是new User();的地址)复制一份给add方法。

* 六、封装

概念: 封装是面向对象编程中的一个重要概念,它指的是将数据和操作数据的方法捆绑在一起,并限制对数据的访问。
封装的目的是隐藏对象的内部细节,只向外界暴露必要的接口,以防止外部代码直接访问对象的内部状态,从而提高代码的安全性和可维护性。
如何实现封装:
数据隐藏(Data Hiding): 封装通过将对象的数据隐藏起来即属性私有化,只允许通过对象的方法来访问和修改数据,从而防止外部直接访问对象的内部状态。
访问控制(Access Control): 通常,封装会将对象的属性设置为私有(private),只允许通过公共(public)方法来访问和修改这些属性。

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
package com.camellia.oop07;
/**
* 为了保证User类型对象的age属性的安全,我们需要使用封装机制。实现封装的步骤是什么?
* 第一步:属性私有化。(什么是私有化?使用 private 进行修饰。)
* 属性私有化的作用是:禁止外部程序对该属性进行随意的访问。
* 所有被private修饰的,都是私有的,私有的只能在本类中访问。
*
* 第二步:对外提供setter和getter方法。
* 为了保证外部的程序仍然可以访问age属性,因此要对外提供公开的访问入口。
* 访问一般包括两种:
* 读:读取属性的值
* 改:修改属性的值
* 那么应该对外提供两个方法,一个负责读,一个负责修改。
* 读方法的格式:getter
* public int getAge(){}
* 改方法的格式:setter
* public void setAge(int age){}
*/
public class User {
private int age;

// 读取age属性的值
// getter方法是绝对安全的。因为这个方法是读取属性的值,不会涉及修改操作。
public int getAge(){
//return this.age;
return age;
}

// 修改age属性的值
// setter方法当中就需要编写拦截过滤代码,来保证属性的安全。
// java有就近原则,若不加this关键字都默认是形参age。
public void setAge(int age){
if(age < 0 || age > 100) {
System.out.println("对不起,您的年龄值不合法!");
return;
}
// this. 大部分情况下可以省略。
// this. 什么时候不能省略?用来区分局部变量和实例变量的时候。
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.camellia.oop07;

public class UserTest {
public static void main(String[] args) {
User u = new User();
// 读
System.out.println("年龄:" + u.getAge());

// 改
u.setAge(-100);

// 读
System.out.println("年龄:" + u.getAge());

//改
u.setAge(50);

//读
System.out.println("年龄:" + u.getAge()); // 50
}
}

* 七、构造方法

7.1、构造方法的基本知识点

1、构造方法的作用

对象的创建: 构造方法通过调用完成对象的创建。当使用 new 关键字实例化一个对象时,构造方法被调用,对象在内存中被创建并分配空间。
对象的初始化: 构造方法用于给对象的所有属性赋值,即对象的初始化。它确保对象在创建后处于一个合适的状态,属性被赋予初始值,以便对象可以正常运行。

2、定义构造方法的方式

1
2
3
[修饰符列表] 构造方法名(形参列表) {
构造方法体;
}

注意事项:

  • 构造方法名必须和类名一致,以便编译器能够识别并与类关联。
  • 构造方法不需要提供返回值类型,因为它的主要目的是创建对象,而不是返回值。
  • 如果提供了返回值类型,则该方法不再是构造方法,而是普通方法,不能用于对象的创建。

3、构造方法怎么调用呢?

  • 使用new运算符来调用。
  • 语法:new 构造方法名(实参);
  • 注意:构造方法最终执行结束之后,会自动将创建的对象的内存地址返回。但构造方法体中不需要提供“return 值;”这样的语句。

4、构造方法相关注意事项

  • 在Java语言中,如果一个类没有显式定义构造方法,系统会默认提供一个无参数的构造方法。这个构造方法通常称为缺省构造器。
  • 如果一个类显式定义了构造方法,系统则不再提供缺省构造器。因此,为了对象创建更加方便,建议手动编写一个无参数的构造方法。
  • 在Java中,一个类可以定义多个构造方法,并且这些构造方法自动构成了方法的重载。这意味着可以根据不同的参数列表调用不同的构造方法来创建对象。
  • 构造方法中给属性赋值是对象第一次创建时属性的初始值。然而,单独定义set方法给属性赋值的好处在于后期可以灵活地修改属性的值。这种方式允许在对象创建后,根据需要修改对象的属性,从而增加了对象的灵活性和可维护性。

*5、构造方法的执行原理

  • 构造方法的执行包括两个重要的阶段:

    • 第一阶段:对象的创建
    • 第二阶段:对象的初始化
  • 对象在什么时候创建的?

    • 当使用new关键字实例化一个对象时,在堆内存中直接开辟空间。这个过程中,会给对象的所有属性赋默认值,完成对象的创建。这一过程发生在构造方法体执行之前。
  • 对象初始化在什么时候完成的?

    • 构造方法体开始执行时,标志着对象的初始化过程开始。在构造方法体中,可以对对象的属性进行赋值等初始化操作。构造方法体执行完毕,表示对象初始化完毕。此时,对象处于可用状态,可以被程序进一步操作和调用。

6、构造代码块

  • 语法格式:

    • 构造代码块的语法格式为一对大括号{},没有参数列表。
  • 执行时机及次数:

    • 每次在使用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
      34
      35
      public class Example {
      private int x;
      private int y;

      // 构造代码块
      {
      System.out.println("构造代码块被执行");
      x = 5;
      y = 10;
      }

      // 构造方法
      public Example() {
      System.out.println("构造方法被调用");
      }

      // 获取x的值
      public int getX() {
      return x;
      }

      // 获取y的值
      public int getY() {
      return y;
      }

      public static void main(String[] args) {
      // 创建对象
      Example obj = new Example();
      // 输出属性值
      System.out.println("x 的值为:" + obj.getX());
      System.out.println("y 的值为:" + obj.getY());
      }
      }

[!NOTE]

注意:和静态代码块做区分。

7、构造代码块的作用

构造代码块可以用于将对象初始化时共享的代码抽取出来,实现代码的复用。具体而言:

  • 如果所有的构造方法在最开始的时候有相同的一部分代码,可以将这部分代码放入构造代码块中。
  • 构造代码块会在每次对象创建时都执行,确保共享的代码被执行,并且避免了代码重复。
    这样,通过构造代码块,可以提高代码的可维护性和可读性,减少代码冗余,提高代码复用性。

*八、this关键字

this 本质上是一个引用。this 中保存的是当前对象的内存地址。
在Java中,this 是一个关键字,用于引用当前对象的实例。它通常用于区分实例变量和方法参数之间的命名冲突,或者在一个类的方法内部调用同一个类的另一个方法。下面详细解释 this 的几个常见用途:

  1. 区分实例变量和方法参数:当方法参数的名称与实例变量的名称相同时,使用 this 来引用当前对象的实例变量。这样可以明确指示要访问的是实例变量而不是方法参数。

    1
    2
    3
    4
    5
    6
    7
    public class MyClass {
    private int value;

    public void setValue(int value) { //这个形参与属性value相同,若不加this则根据Java中的就近原则,方法中的value都是形参value。
    this.value = value; // 使用 this 引用实例变量
    }
    }

    这里 this.value 指的是当前对象的 value 实例变量,而 value 是方法的参数。

  2. 在构造器中调用另一个构造器可以使用 this 调用同一个类的另一个构造器,且只能出现在第一行。这种方法通常被称为构造器重载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class MyClass {
    private int value;
    private String name;

    public MyClass() {
    //new MyClass(10,"giaogiao"); 这么会创建一个新对象
    this(10,"giaogiao");// 调用另一个构造器

    /*这个的目的是什么?
    当要求类在初始化时,给它赋指定的默认值。
    EG:this.value=10;
    this.name="giaogiao";
    这段代码其实是重复的。而通过this(10,"giaogiao");获取当前对象,调用MyClass(int value,String name)构造器以简化开发。
    */

    }

    public MyClass(int value,String name) {
    this.value = value;
    this.name=name;
    }
    }

    在这个例子中,无参构造器调用了带参构造器,以避免重复代码。

  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
package com.camellia.oop6;

// 学生类
public class Student {
// 私有成员变量 name
private String name;

// 带参构造方法,用于初始化 name
public Student(String name) {
this.name = name;
}

// 无参构造方法
public Student() {
}

// 获取学生姓名的方法
public String getName() {
return name;
}

// 设置学生姓名的方法
public void setName(String name) {
this.name = name;
}

// 学习方法,打印当前对象的引用地址
public void study(){
System.out.println("study---->" + this); // 验证this是当前对象的引用。
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.camellia.oop6;

// 测试类
public class StudentTest {
public static void main(String[] args) {
// 创建学生对象s1,初始化姓名为"小吴"
Student s1 = new Student("小吴");
// 打印s1对象的引用地址
System.out.println("main---->" + s1);
// 调用s1对象的study()方法
s1.study();

// 创建学生对象s2,初始化姓名为"小花"
Student s2 = new Student("小花");
// 打印s2对象的引用地址
System.out.println("main---->" + s2);
// 调用s2对象的study()方法
s2.study();
}
}

在Java中,当对象调用自己的方法时,方法体内的 this 关键字会引用该对象的实例。
在方法被调用时,Java虚拟机会隐式地将当前对象的引用传递给方法,以便方法能够访问对象的成员变量和方法。
因此,在普通方法中通过 this 关键字引用的就是调用该方法的当前对象。

九、static关键字

在Java中,使用static关键字声明的成员(变量、方法、代码块)是类级别的,而不是与类的每个实例相关联的。
因此,它们可以通过类名直接访问,而无需创建类的实例。

9.1、静态变量存储图

1、没使用静态变量时的存储图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.camellia.oop7;

public class User {
//用户id
private String id;
//用户国籍
private String country="China";

public User() {
}

public User(String id) {
this.id = id;
}
public void PrintInfo(){
System.out.println("ID: " + id+"\tCountry: " + country);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
package com.camellia.oop7;

public class UserTest {
public static void main(String[] args) {
User user1 = new User("1001");
user1.PrintInfo();
User user2 = new User("1002");
user2.PrintInfo();
User user3 = new User("1003");
user3.PrintInfo();
}
}

2、使用静态变量时的存储图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.camellia.oop8;

public class User {
//用户id
private String id;
//用户国籍
//静态变量什么时候开劈空间(初始化)、存储在哪里?
//类加载时初始化
//JDK8之后:静态变量存储在堆内存之中

private static String country="China";

public User() {
}

public User(String id) {
this.id = id;
}
public void PrintInfo(){
System.out.println("ID: " + id+"\tCountry: " + country);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.camellia.oop8;

import com.camellia.oop7.User;

public class UserTest {
public static void main(String[] args) {
com.camellia.oop7.User user1 = new com.camellia.oop7.User("1001");
user1.PrintInfo();
com.camellia.oop7.User user2 = new com.camellia.oop7.User("1002");
user2.PrintInfo();
com.camellia.oop7.User user3 = new User("1003");
user3.PrintInfo();
}
}

9.2、Java中静态变量和方法的访问,以及静态变量不能使用this关键字

  1. 静态变量和方法建议使用类名.调用。虽然用引用.也可以,但是实质还是通过类来调用,而且这样容易和实例变量和方法的访问相混淆。
  2. 静态方法不能使用 this 关键字是因为 this 关键字代表当前对象的实例,而静态方法是与类相关联的,不依赖于任何特定的实例。所以无法直接访问实例变量和方法。

9.3、静态代码块

静态代码块是使用 static 关键字声明的代码块,**它在类被加载时执行,并且只执行一次。**
静态代码块通常用于在类加载时进行初始化操作,例如初始化静态变量或执行静态方法。它们的执行顺序是在类加载时按照代码顺序执行。

[!NOTE]

注意:和构造代码块做区分。

静态代码块的特点包括:

  1. 使用 static 关键字声明:静态代码块使用 static 关键字进行声明,以标识它们是与类相关联的,而不是与类的实例相关联的。

  2. 在类加载时执行:静态代码块在类被加载时执行,并且只执行一次。类的加载是指当 JVM 第一次加载类时发生的操作,通常在首次创建类的实例之前。

  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
public class StaticTest01 { 

// 实例方法
public void doSome(){
System.out.println(name);
}

// 实例变量
String name = "zhangsan";

// 静态变量
static int i = 100;

// 静态代码块
static {
// 报错原因:在静态上下文中无法直接访问实例相关的数据。
//System.out.println(name);
// 这个i可以访问,是因为i变量是静态变量,正好也是在类加载时初始化。
System.out.println(i);
System.out.println("静态代码块1执行了");
// j无法访问的原因是:程序执行到这里的时候,j变量不存在。
//System.out.println(j);

System.out.println("xxxx-xx-xx xx:xx:xx 000 -> StaticTest01.class完成了类加载!");
}

// 静态变量
static int j = 10000;

// 静态代码块
static {
System.out.println("静态代码块2执行了");
}

public static void main(String[] args) {
System.out.println("main execute!");
}

// 静态代码块
static {
System.out.println("静态代码块3执行了");
}
}
//静态代码的执行顺序只能靠编写顺序的来确定,编写时在前的也就先执行。

十、无参构造方法、构造代码块和静态代码块的执行顺序

  1. 静态代码块
  2. 构造代码块
  3. 无参构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

public class ClassTest {
public static void main(String[] args) {
Camellia camellia = new Camellia();
}
}

class Camellia{
{
System.out.println("构造代码块执行");
}

static {
System.out.println("静态代码块执行");
}

Camellia(){
System.out.println("无参构造方法执行");
}
}