通过类创建对象、对象内存管理(学习堆和方法区)
类是现实世界当中具有共同特征的事物进行抽象形成的模板或概念。而对象是实际存在的个体。
例如:“汽车”就是一个类(所有的汽车都有方向盘、发动机、都能形式,这是它们的共同特征),“你家的那个汽车”就是一个真实存在的对象。或者说“明星”是一个类,“刘德华”就是一个对象。“鹿晗”、“吴亦凡”、“蔡徐坤”都是实际存在的对象。
那么“明星”类都有哪些共同特征呢?明星类都有姓名、性别、年龄等状态信息(属性),他们还有一个共同的行为就是“演出”(方法)。
通过类可以创建对象,对象又被称为实例(instance),这个过程也可以称为实例化。对象1、2、3 具有共同特征,进行抽象形成了类,所以从对象到类称为抽象。如下图所示:
我们得知:类 = 属性 + 方法,而属性描述的是状态,方法描述的是行为动作。
其中id、name、age 都是属性,它们都是类中的成员变量(深入说是成员变量中的实例变量),所谓实例变量就是对象级别的变量,这些属性要想访问,必须先创建对象才能访问,不能直接通过类去访问。
其中study()是一个方法,但是这个方法是不加static关键字的,这个方法是实例方法,必须先创建对象才能访问,不能直接通过类去访问。
-----------------------------------------------------
//创建一个模板类Person
public class Person {
String sex;
double height;
int age;
String name;
public void call(){
System.out.println("打电话------");
}
public void sendMessage(){
System.out.println("发信息------");
}
}
public class TestPerson {
public static void main(String[] args) {
//创建一个Person对象
Person p1 = new Person();
//再创建一个Person对象
Person p2 = new Person();
//以上代码其实跟这行代码差不多
int i = 10;
}
}
代码解读:
对于int i = 10 来说,int 是一种基本数据类型,i 是变量名,10 是int 类型的字面量。
对于Student s1 = new Student()来说,Student 是一种引用数据类型,s1 是变量名,new Student()执行之后是一个Student 类型的对象。
---------------------------------------------------
在java 语言当中,当实例变量没有手动赋值,在创建对象的时候,也就是说在 new 的时候,系统会对实例变量默认赋值,它们的默认值请参考下表:
-------------------------------------------------------
对象内存管理--学习堆和方法区
(1)java 堆:
概念:是被所有线程共享的一块区域,在虚拟机启动时创建。
特点:线程共享,存放的是对象实例(所有的对象实例和数组),GC 管理的主要区域。可以处于物理上不连续的内存空间。
(2)方法区:
概念:存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代码等数据。
//方法区中存储类的信息(即代码片段)。所有程序的执行,必须入栈执行!
特点:线程共享的区域,当方法区无法满足内存分配需求的时候,会抛出异常OutOfMemory 异常。
大概了解了java 虚拟机内存分配之后,来看看以下代码在执行过程中,内存是如何变化的,例如有如下代码:
以上代码在执行过程中内存的变化如下图所示:
第一步执行类加载
第二步main 方法调用,给main 方法分配栈帧(压栈)
第三步执行int i = 10,局部变量
第四步执行new Student(),在堆中创建对象,同时初始化实例变量
第五步将堆区中学生对象的内存地址赋值给局部变量s1
上图堆区中“对象”创建完成之后,该对象在堆区当中的内存地址是:0x1111,程序中的“=”将0x1111 这个堆内存地址赋值给s1 变量,也就是说s1 变量保存了堆内存对象的内存地址,我们对于这种变量有一种特殊的称呼,叫做“引用”。也就是说对于Student s1 = new Student()代码来说,s1 不是对象,是一个引用,对象实际上是在堆区当中,s1 变量持有这个对象的内存地址。
如果是创建多个对象,例如有如下代码:
内存分配如图所示:
值得大家注意的是,java 中没有指针的概念(指针是C 语言当中的机制),所以java 程序员没有权利直接操作堆内存,只能通过“引用”去访问堆内存中的对象,例如:s1.no、s1.name、s1.sex、s1.age。
访问一个对象的内存,其实就是访问该对象的实例变量,而访问实例变量通常包括两种形式,要么就是读取数据,要么就是修改数据,例如:System.out.println(s1.no)这就是读取数据,s1.no = 100 这就是修改数据。