程序员常说万物皆对象,能够较好的理解对象的含义是编程修炼中的基本功,初接触可能会较难理解,但是基本的概念是一定要有的,首先需要清楚类和对象的关系。
总结来说,类是对象的蓝图。
类可以看作对现实生活中一类具有共同属性和行为的事物的抽象,而对象则是具体的事物。根据一个类可以创建多个对象,每个对象的实例变量都可以不同。一个很简单例子,如果将狗看作一个类,那么哈士奇、吉娃娃都是该类的对象。
一个类可以有多个对象。
下图显示了如何由一个类创建一个对象,类只是一个蓝图,通俗来说就是一个框架概念是无实体的,当通过类建立对应对象的时候,对象会存在于JVM的堆空间上,是实际存在并占有一定内存空间的。
对象有实例变量和方法两个属性:
同一个类创建的对象的具有相同的方法和变量,但是变量值存在差异。
类的组成是由属性和行为两部分组成
下面给出一般类的定义:
public class 类名 {
// 成员变量
变量1的数据类型 变量1;
变量2的数据类型 变量2;
…
// 成员方法
方法1;
方法2;
}
除了成员方法外,我们在定义类的时候还会给出构造方法,构造方法又分为无参构造和带参构造。
例如:
public class Student {
//成员变量(私有)
private int age;
private String name;
//无参构造方法
public Student() {
}
//带参构造方法
public Student(int age, String name) {
this.age = age;
this.name = name;
}
}
根据定义的类来创建对象的格式为:
类名 对象名 = new 类名();
例如:
//无参构造方法创建对象
Student s1 = new Student();
s1.setAge(10);
s1.setName("mary");
//带参构造方法创建对象
Student s2 = new Student(10,"ma");
创建对象时,对象名和地址是存储在栈内存中的,对象的属性内容存储在堆内存中,Java会根据对象的大小来分配内存空间,同时也会主动管理内存。当JVM发现某个对象不会再被使用时,该对象就会被标记为可回收,当内存不足时,垃圾收集器会启动来清理垃圾,回收空间。
多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自的内存区域中,成员方法多个对象共用的一份
当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)
只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据
在上面提到了类的构造方法分为带参构造和无参构造,通过构造函数可以初始化一个对象,而构造函数的实际意义是什么呢?
可以解释如下:构造函数会在对象能够被赋值给引用变量之前执行,能够让我们介入到new的过程中去。
需要注意的是,编译器在调用构造函数时会调用无参构造,同时构造函数不会有返回值
在创建子类对象时,会发生“构造函数链”的过程,也就是会创建一部分父类:
由上图可以看到,在调用构造函数的时候是从子类到父类一层层的调用,但是最终**父类的构造函数一定会在子类构造函数之前结束。**对supper()的调用是子类构造函数的第一个语句。
在使用构造函数时,除了使用supper()调用父类函数以外,还可以使用this()调用对象的本身,但是需要注意的是,supper()和this()不能同时出现在同一个构造函数中。
对象的堆内存中,会有专门是一块supper()区域来存放父类数据
局部变量只存活在方法中,实例变量和对象的生命周期一致。
对象的生命周期取决于其“引用变量”只要一个对象存在引用变量,那么它就不会被垃圾收集器(Garbage Collection, GC)回收
释放对象的引用有三种方法:
引用永久性的离开对象范围
例如在下面这个例子中:
public class StackRef{
public void foor(){
barf();
}
public void barf(){
Duck d = new Duck();
}
}
在上面这个代码实例中,先将foor()方法放到栈上,然后push一个barf()方法,barf()方法中有一个引用变量d指向对象Duck(),在barf()执行完毕后,引用d消失,Duck()对象将会被GC释放
引用被赋值到其他对象上
public class ReRef{
Duck d = new Duck();
public void go(){
d = new Duck();
}
}
在上面这个代码实例中,引用变量d先指向一个Duck对象,在调用go方法后,又指向了另一个Duck对象,那么最开始的那个Duck对象没有对应的引用,不久会被GC释放
引用指向了NULL指针
public class ReRef{
Duck d = new Duck();
public void go(){
d = null;
}
}
在上面这个代码实例中,引用变量d先指向一个Duck对象,在调用go方法后,又指向了null,那么最开始的那个Duck对象没有对应的引用,不久会被GC释放