java使用内部变量_Java 类中变量的初始化,类内部变量/代码块的加载顺序

@

1. 变量的初始化方法

先不考虑继承父类和实现接口的情形,设想对一个Pet类的成员变量和静态变量进行初始化,有下列方法。

1.1 直接定义字段时赋值 or 显示字段初始化

private String name = "Lina";

private static String MasterName = "John";

1.2 调用方法进行初始化

1.2.1 调用方法赋值给变量

可以使用任何静态方法给静态变量/非静态变量赋值,也同样可以使用非静态方法给非静态变量赋值,只要方法返回的数据类型和变量的类型一致即可。

private int age = setAge();

public int setAge() {

int num = 2;

return num;

}

private static String id = setId();

public static String setId() {

String id = "X0012";

return id;

}

以上方式进行初始化本质上等同于直接赋值,只不过使用了方法的返回值代替了原本的值。

1.2.2 在非构造器的普通方法内进行初始化

变量在可以非构造器的普通方法内进行初始化,但是只有在创建对象,调用了方法之后才能真正完成初始化,而不是发生在类加载字段时。

(通常static变量不采用这种方式进行初始化,但只要使用该变量前完成了初始化,并不会影响实际使用)

private static String FatherName;

private String MotherName;

public static void setFatherName() {

FatherName = "Dog A";

}

public void setMotherName() {

FatherName = "Dog B";

}

1.3 成员变量-初始化代码块中初始化

成员变量可以在初始化代码块中初始化,初始化代码块可以定义多个。

private double height;

private double weight;

// initialization block 1

{

height = 0.5;

}

// initialization block 2

{

weight = 20;

}

注:静态变量是属于整个类的变量而不是属于某个对象的,因此不能把任何方法体内 (包括静态方法和静态代码块) 的局部变量声明为静态的。

1.4 静态变量-静态化代码块中初始化

类似地,静态变量可以在静态化代码块中初始化,静态代码块同样可以定义多个。

private static String color;

private static String sex;

// static block 1

static {

color = "Dotted";

}

// static block 2

static {

sex = "Female";

}

1.5 构造器中初始化

静态代码块和初始化代码块可以完成初始化任务,但通常情况下初始化变量的任务由构造器完成。下面初始化一下三个变量:

private String type;

private boolean healthy;

private static double price;

1.5.1 默认构造器初始化

在没有定义任何构造器时,Java会给我们自动提供一个默认的无参数构造器。

该构造器会将基本数据类型初始化为默认值,引用对象类型设置为null。

public Pet() {

this.type = null;

this.healthy = false;

this.price = 0.0;

}

但是当自主定义了一个构造器时,就不会自动提供默认构造器。没有被自定义的构造器初始化的变量将不会被初始化,除非再次定义一个无参数的构造器。如果自定义无参数的构造器,若构建对象时存在没有初始化的变量,也将自动初始化变量为默认值。

1.5.2 自定义构造器初始化

Java允许自定义多个构造器,也即重载构造器。

一个构造器可以通过this(...)调用其他的构造器,但是该语句必须位于构造器首行

public Pet(String type) {

this.type = type;

}

public Pet(String type, boolean healthy, double price) {

this(type);

this.healthy = healthy;

this.price = price;

}

引用对象类型的变量的初始化:

有时候,会经常碰到一个类中含有引用对象类型的变量,与基本数据类型变量相似,引用对象类型变量也同样可通过上述方法进行初始化。

现在假设有一个Toy类,而Pet类中列出了几种宠物爱玩的玩具,分别用1-6数字来代替玩具名

class Toy {

private int toolNum;

// Tool class 无参数构造器

public Toy() {

}

// Tool class 含参数构造器

public Toy(int toolNum) {

this.toolNum = toolNum;

}

}

/* 实际情况下,很少会创造静态对象,因为静态修饰的字段被类共享。此处引入静态对象仅仅是为了演示初始化方法及变量加载顺序,无其他实际意义。*/

初始化对象类变量:

private static Toy toy1;

private Toy toy2;

private Toy toy3 = generateToy();

private static Tool toy4 = new Toy();

private Toy toy5

static {

Pet.toy1 = new Toy(1);

}

public Toy generateToy() {

return new Toy();

}

{

tool3 = new Toy(3);

}

public Pet(){

this.toy5 = new Toy(5);

}

注:1. 虽然这里介绍了很多种初始化变量的方式,但是绝大部分情形仍然是直接在构造器中完成初始化,其他方式若使用不当易在实际开发过程中产生bug,应该尽量避免使用。

2. 对于静态常量 (例如: private static final int age = 20) 则通常在直接定义时赋值。

2. 类的加载顺序(无继承类和接口实现情形)

在不考虑继承父类、实现接口的情况下。类中变量和方法加载顺序:

在第一次调用类时,类进入加载阶段,会首先加载所有static修饰的内容: 静态变量 / 静态代码块 / 静态方法,其中静态方法只会被加载但并不会被执行。静态修饰的内容没有优先执行次序之分,在前的部分将先被执行。

加载完static修饰的内容后,若使用new关键字创建了对象则不再重新加载static修饰的内容了,因为静态内容在第一次调用类时已经被加载过了,后续可以直接调用静态内容。JVM会继续加载非静态内容: 成员变量/初始化代码块/成员方法,其中成员方法只会被加载但并不会被执行。这些除构造器外的非静态内容也无优先执行次序之分,在前的部分将先被执行。

第2步完成后,调用相应的构造器开始创建对象。若后续又使用new关键字新创建了对象,则重复2~3步。

对于静态方法和非静态方法都是被动调用,即系统不会自动调用执行。只有在主动调用后才会执行这些方法。

下面对于类的变量/代码块等加载顺序用一个完整的程序进行演示:

class Pet {

// 直接定义字段时赋值or显示字段初始化

private String name = "Lina";

private static String MasterName = "John";

// 初始化代码块中初始化

private double height;

private double weight;

// 静态初始化代码块中初始化

private static String color;

private static String sex;

// 构造器中初始化

private String type;

private boolean healthy;

private static double price;

// 引用数据类型初始化

private static Toy toy1 = new Toy(1);

// static block 1

static {

System.out.println("-- 静态初始化块 1 --");

color = "Dotted";

System.out.println("Color: " + color);

}

private static Toy toy2;

// 调用方法进行初始化

private static String id = setId();

// static block 2

static {

System.out.println("-- 静态初始化块 2 --");

sex = "Female";

System.out.println("Sex: " + sex);

Pet.toy2 = new Toy(2);

}

private Toy toy3 = new Toy(3);

// initialization block 1

{

System.out.println("-- 初始化块 1 --");

height = 0.5;

System.out.println("Height: " + this.height);

}

private int age = setAge();

private Toy toy4;

// initialization block 2

{

System.out.println("-- 初始化块 2 --");

weight = 20;

System.out.println("Weight: " + this.weight);

toy4 = new Toy(4);

}

private Toy toy5 = generateToy();

private Toy toy6;

public Toy generateToy() {

System.out.println("-- 调用 generateTool()方法初始化 --");

return new Toy();

}

// 引用返回值来初始化变量

public int setAge() {

System.out.println("-— 调用非静态方法初始化非静态变量 --");

int num = 2;

System.out.println("Age: " + num);

return num;

}

// 引用返回值来初始化变量

public static String setId() {

System.out.println("-— 调用静态方法初始化静态变量 --");

String id = "X0012";

System.out.println("Id: " + id);

return id;

}

// 方法内赋值

private static String FatherName;

private String MotherName;

public static void setFatherName() {

System.out.println("-- setFatherName() 方法内初始化 --");

FatherName = "Dog A";

System.out.println(FatherName);

}

public void setMotherName() {

System.out.println("-- setMotherName() 方法内初始化 --");

this.MotherName = "Dog B";

System.out.println(this.MotherName);

}

// 无参数构造器

public Pet() {

System.out.println("-- Pet Class 无参构造器 --");

}

// 含参构造器 1

public Pet(String type) {

System.out.println("-- Pet Class 含参构造器 1 --");

this.type = type;

this.toy6 = new Toy();

System.out.println("Type: " + type);

}

// 含参构造器 2

public Pet(String type, boolean healthy, double price) {

this(type);

System.out.println("-- Pet Class 含参构造器 2 --");

this.healthy = healthy;

Pet.price = price;

System.out.println("Healthy: " + this.healthy);

System.out.println("Price: " + Pet.price);

}

// 普通静态方法

public static void print() {

System.out.println();

for (int i = 10; i <= 50; i += 10)

System.out.println(i);

System.out.println();

}

// 辅助打印变量信息

public void toPetString() {

System.out.println();

System.out.println("|-----------打印 Pet 对象信息----------|");

System.out.println("Pet [Name = " + name + ", MasterName = "

+ MasterName + ", Age = " + age + ", Id = " + id + ", Height = "

+ height + ", Weight = " + weight + ", Type = " + type

+ ", Healthy = " + healthy + ", Price =" + price + "]");

System.out.println("Pet [FatherName = " + FatherName + ", MotherName = "

+ MotherName + "]");

System.out.println("Pet's Tools [ " + toy1 + ", " + toy2 + ", " + toy3

+ ", " + toy4 + ", " + toy5 + ", " + toy6 + "]");

System.out.println("|-----------------End----------------|");

}

}

class Toy {

private int toolNum;

// Tool class 无参数构造器

public Toy() {

System.out.println("-* Toy Class 无参构造器 *-");

System.out.println(this);

}

// Tool class 含参数构造器

public Toy(int toolNum) {

System.out.println("-* Toy Class 含参构造器 *-");

this.toolNum = toolNum;

System.out.println("Tool # " + this.toolNum);

}

// 辅助打印变量信息

@Override

public String toString() {

return "Tool # " + this.toolNum;

}

}

public class Run {

public static void main(String[] args) {

System.out.println("创建第 1 个Pet对象:\n");

Pet p1 = new Pet();

p1.toPetString();

Pet.print();

System.out.println("创建第 2 个Pet对象:\n");

Pet p2 = new Pet("Retriever", true, 100.0);

p2.setMotherName();

Pet.setFatherName();

p2.toPetString();

}

}

最终结果以两部分呈现,以便对比输出顺序。

Part 1

创建第 1 个Pet对象:

-* Toy Class 含参构造器 *-

Tool # 1

-- 静态初始化块 1 --

Color: Dotted

-— 调用静态方法初始化静态变量 --

Id: X0012

-- 静态初始化块 2 --

Sex: Female

-* Toy Class 含参构造器 *-

Tool # 2

-* Toy Class 含参构造器 *-

Tool # 3

-- 初始化块 1 --

Height: 0.5

-— 调用非静态方法初始化非静态变量 --

Age: 2

-- 初始化块 2 --

Weight: 20.0

-* Toy Class 含参构造器 *-

Tool # 4

-- 调用 generateToy()方法初始化 --

-* Toy Class 无参构造器 *-

Tool # 0

-- Pet Class 无参构造器 --

|-----------打印 Pet 对象信息----------|

Pet [Name = Lina, MasterName = John, Age = 2, Id = X0012, Height = 0.5, Weight = 20.0, Type = null, Healthy = false, Price =0.0]

Pet [FatherName = null, MotherName = null]

Pet's Tools [ Tool # 1, Tool # 2, Tool # 3, Tool # 4, Tool # 0, null]

|-----------------End----------------|

10

20

30

40

50

Part 2

创建第 2 个Pet对象:

-* Toy Class 含参构造器 *-

Tool # 3

-- 初始化块 1 --

Height: 0.5

-— 调用非静态方法初始化非静态变量 --

Age: 2

-- 初始化块 2 --

Weight: 20.0

-* Toy Class 含参构造器 *-

Tool # 4

-- 调用 generateTool()方法初始化 --

-* Toy Class 无参构造器 *-

Tool # 0

-- Pet Class 含参构造器 1 --

-* Toy Class 无参构造器 *-

Tool # 0

Type: Retriever

-- Pet Class 含参构造器 2 --

Healthy: true

Price: 100.0

-- setMotherName() 方法内初始化 --

Dog B

-- setFatherName() 方法内初始化 --

Dog A

|-----------打印 Pet 对象信息----------|

Pet [Name = Lina, MasterName = John, Age = 2, Id = X0012, Height = 0.5, Weight = 20.0, Type = Retriever, Healthy = true, Price =100.0]

Pet [FatherName = Dog A, MotherName = Dog B]

Pet's Tools [ Tool # 1, Tool # 2, Tool # 3, Tool # 4, Tool # 0, Tool # 0]

|-----------------End----------------|

3. 类的加载顺序(继承类+接口实现情形)

3待更新

参考内容:

If you have any question, please let me know, your words are always welcome.

新人入坑,如有错误/不妥之处,欢迎指出,共同学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值