在类中,我们有两个成员,一个是 属性,另一个是 方法;
class Person {// 定义属性String name;int age;char gender;// 定义方法public void eat() {String food = "宫保鸡丁"; // 定义局部变量System.out.println("我喜欢吃" + food);}public void sleep(int hour) { // 形参:属于局部变量System.out.println("人至少睡眠" + hour + "小时");}
}
属性中, 变量的定义可以分为:基本数据类型、引用数据类型;
方法中, 变量的定义可以分为:局部变量、形参;
即:
因为本文主要围绕的是 属性 部分,所以下文将首先介绍 方法 部分,然后详细介绍属性部分的 基本数据类型 与 引用数据类型。
// 定义方法
public void eat() {String food = "宫保鸡丁"; // 定义局部变量System.out.println("我喜欢吃" + food);
}
public void sleep(int hour) { // 形参:属于局部变量System.out.println("人至少睡眠" + hour + "小时");
}
在定义方法部分,我们一共对 Person
类定义了两个方法:eat
与 sleep
;而在方法 eat
中,我们通过定义局部变量 food
并赋值,最后通过 sout 打印;
public void eat() {String food = "宫保鸡丁"; // 定义局部变量System.out.println("我喜欢吃" + food);
}
需要注意的是,在定义局部变量时,我们必须对其进行赋值,而不是仅仅初始化;
在方法 sleep
中,我们通过定义形参 hour
,并且通过传参的方式将其值传入,最终通过 sout 打印;
public void sleep(int hour) { // 形参:属于局部变量System.out.println("人至少睡眠" + hour + "小时");
}
需要注意的是,与局部变量对比,形参因为可以在被调用时候传入值,所以我们可以仅执行初始化操作,而不赋值;
我们定义一个类 Employee
,并定义属性如下:
public class Employee {// 定义属性int id; // 编号String name; // 姓名int age; // 年龄double salary; // 薪资
}
其实通过观察不难发现,好像 String
与另外三个属性不太相同;仔细思考,其实是因为 String
不属于 基本数据类型,而是属于 引用数据类型。
Java 的基本数据类型包括以下几种:整型:byte、short、int、long
浮点型:float、double
字符型:char
布尔型:boolean这些数据类型分别代表不同的数据类型,可以用于声明变量、函数参数、函数返回值等。
其中,整型用来表示整数,浮点型用来表示小数,字符型用来表示单个字符,布尔型用来表示真或假。
Java 的引用数据类型可以被理解为指向对象的指针
它们不存储实际的数据值,而是存储指向对象的内存地址。Java 中常见的引用数据类型包括以下几种:类类型(Class Type):包括所有的类、接口和数组类型。
接口类型(Interface Type):指的是所有的接口类型。
数组类型(Array Type):指的是所有的数组类型,无论是基本数据类型的数组还是对象类型的数组。这些引用数据类型都需要在使用前进行实例化,即通过 new 关键字创建对象并分配内存空间。
在实例化后,引用数据类型变量会存储对象的内存地址,从而允许程序通过引用来访问对象的属性和方法。
上述两段初学不会完全理解,结合下述的代码去理解就好;
public class Employee {// 定义属性int id; // 编号String name; // 姓名int age; // 年龄double salary; // 薪资MyDate birthday; // 生日
}
我们在上述代码的基础上再加上一行 引用数据类型 变量,即 MyDate
;
MyDate
与 String
不同的在于,其是我们自己定义的 引用数据类型:
public class MyDate {int year;int month;int day;
}
创建一个名为 MyDate
的类;在类中,定义三个成员变量:year
,month
,day
,分别代表年月日;
然后我们将其实例化:
我们另创建一个名为 EmployeeTest
的类,在类中,我们创建两个实例:emp1
以及 emp2
public class EmployeeTest {public static void main(String[] args) {// 创建类的实例,类的实例化Employee emp1 = new Employee();System.out.println(emp1); // 类型@地址// 创建实例变量emp1.id = 1001;emp1.name = "Tom";emp1.age = 21;emp1.salary = 7800;emp1.birthday = new MyDate();emp1.birthday.year = 1999;emp1.birthday.month = 1;emp1.birthday.day = 15;System.out.println("id = " + emp1.id + ",name = " + emp1.name + ",age = " + emp1.age + ",salary = " + emp1.salary + ",birthday = " + emp1.birthday.year + "年 " + emp1.birthday.month + "月" + emp1.birthday.day + "日");// 创建第二个对象Employee emp2 = new Employee(); // 开辟空间给第二个对象System.out.println(emp2);// emp2.id = ;
// emp2.name = ;
// emp2.age = ;
// emp2.salary = ;System.out.println("id = " + emp2.id + ",name = " + emp2.name + ",age = " + emp2.age + ",salary = " + emp2.salary);}
}
观察第一个实例化部分:emp1
Employee emp1 = new Employee();// System.out.println(emp1); // 类型@地址// 实例变量赋值
emp1.id = 1001;
emp1.name = "Tom";
emp1.age = 21;
emp1.salary = 7800;
emp1.birthday = new MyDate();
emp1.birthday.year = 1999;
emp1.birthday.month = 1;
emp1.birthday.day = 15;System.out.println("id = " + emp1.id + ",name = " + emp1.name + ",age = " + emp1.age + ",salary = " + emp1.salary + ",birthday = " + emp1.birthday.year + "年 " + emp1.birthday.month + "月" + emp1.birthday.day + "日");
首先我们通过 new
方法给实例 emp1
开辟 堆空间;
Employee emp1 = new Employee();
然后我们对实例变量进行赋值:
emp1.id = 1001;
emp1.name = "Tom";
emp1.age = 21;
emp1.salary = 7800;
emp1.birthday = new MyDate();
emp1.birthday.year = 1999;
emp1.birthday.month = 1;
emp1.birthday.day = 15;
需要注意的是,在 emp1.birthday
开始,我们首先又一次执行了 new
,即:
emp1.birthday = new MyDate();
即,我们给 emp1.birthday
开辟 堆空间 ;并且把地址信息给 emp1.birthday
属性;然后给属性赋值:
emp1.birthday.year = 1999;
emp1.birthday.month = 1;
emp1.birthday.day = 15;
在这里读者应该产生困惑有两点,第一点是 堆空间,第二点是 地址信息;下一个部分的内容将阐述这两个点;
我们在赋值给引用数据类型 emp1.birthday
赋值后,可以打印内容如下:
System.out.println("id = " + emp1.id + ",name = " + emp1.name + ",age = " + emp1.age + ",salary = " + emp1.salary + ",birthday = " + emp1.birthday.year + "年 " + emp1.birthday.month + "月" + emp1.birthday.day + "日");
在 Java 中,堆空间和栈空间都是用来存储程序中的数据的内存区域,但是它们有着不同的特点和用途。
堆空间(Heap Space): 堆空间是用于存储对象的内存区域。所有通过 new 关键字创建的对象都存储在堆空间中,而且这些对象的生命周期由垃圾收集器来管理。堆空间的大小一般由 JVM 参数进行设置,可以动态扩展,因此它可以存储任意数量的对象。
栈空间(Stack Space): 栈空间是用于存储方法调用的内存区域。每个线程都有自己的栈空间,用于存储方法调用的参数、局部变量和方法返回值等数据。栈空间的大小是由 JVM 预设的,不能动态扩展,因此它的空间较小,只能存储相对较小的数据。
需要注意的是,基本数据类型的变量也可以存储在栈空间中,但是它们和对象的引用不同,基本数据类型的变量存储的是数据本身而不是内存地址。此外,在方法调用结束后,方法的栈帧会被弹出并释放相应的内存空间,因此栈空间中的数据只有在方法执行期间才是有效的。
在该程序中,我们有两次 new
,第一次开辟 堆空间给 emp1
实例,第二次开辟 堆空间 给 emp1.birthday
引用数据类型属性;而如果我们将 emp1
以及 emp1.birthday
打印可以发现,其存储的都是 类型@地址
的地址信息:
System.out.println(emp1); // 类型@地址
System.out.println(emp1.birthday); // 类型@地址
MyDate.java
package com.athongduo.idea;/*** ClassName: MyDate* Description:** @Author: XU Hongduo* @Create 2023/3/17 14:28* @Version 1.0*/
public class MyDate {int year;int month;int day;
}
Employee.java
package com.athongduo.idea;/*** ClassName: Employee* Description:** @Author: XU Hongduo* @Create 2023/3/17 14:16* @Version 1.0*/
public class Employee {// 定义属性int id; // 编号String name; // 姓名int age; // 年龄double salary; // 薪资MyDate birthday; // 生日
}
EmployeeTest.java
package com.athongduo.idea;/*** ClassName: EmployeeTest* Description:** @Author: XU Hongduo* @Create 2023/3/17 14:18* @Version 1.0*/
public class EmployeeTest {public static void main(String[] args) {// 创建类的实例,类的实例化Employee emp1 = new Employee();System.out.println(emp1); // 类型@地址// 创建实例变量emp1.id = 1001;emp1.name = "Tom";emp1.age = 21;emp1.salary = 7800;emp1.birthday = new MyDate();emp1.birthday.year = 1999;emp1.birthday.month = 1;emp1.birthday.day = 15;System.out.println("id = " + emp1.id + ",name = " + emp1.name + ",age = " + emp1.age + ",salary = " + emp1.salary + ",birthday = " +emp1.birthday.year + "年 " + emp1.birthday.month + "月" + emp1.birthday.day + "日");// 创建第二个对象Employee emp2 = new Employee(); // 开辟空间给第二个对象System.out.println(emp2);// emp2.id = ;
// emp2.name = ;
// emp2.age = ;
// emp2.salary = ;System.out.println("id = " + emp2.id + ",name = " + emp2.name + ",age = " + emp2.age + ",salary = " + emp2.salary);}
}