类和对象

1. 类和对象

程序员常说万物皆对象,能够较好的理解对象的含义是编程修炼中的基本功,初接触可能会较难理解,但是基本的概念是一定要有的,首先需要清楚类和对象的关系。

总结来说,类是对象的蓝图

类可以看作对现实生活中一类具有共同属性和行为的事物的抽象,而对象则是具体的事物。根据一个类可以创建多个对象,每个对象的实例变量都可以不同。一个很简单例子,如果将狗看作一个类,那么哈士奇、吉娃娃都是该类的对象。

在这里插入图片描述

一个类可以有多个对象。

下图显示了如何由一个类创建一个对象,类只是一个蓝图,通俗来说就是一个框架概念是无实体的,当通过类建立对应对象的时候,对象会存在于JVM的堆空间上,是实际存在并占有一定内存空间的。

在这里插入图片描述

2. 类和对象的属性

对象有实例变量和方法两个属性:

  • 实例变量:对象已知的事物,代表了对象的状态
  • 方法:对象可执行的动作,代表了对象的行为

同一个类创建的对象的具有相同的方法和变量,但是变量值存在差异。

类的组成是由属性和行为两部分组成

  • 属性:在类中通过成员变量来体现(类中方法外的变量)
  • 行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)

下面给出一般类的定义:

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");

3. 对象内存图

创建对象时,对象名和地址是存储在栈内存中的,对象的属性内容存储在堆内存中,Java会根据对象的大小来分配内存空间,同时也会主动管理内存。当JVM发现某个对象不会再被使用时,该对象就会被标记为可回收,当内存不足时,垃圾收集器会启动来清理垃圾,回收空间。

单个对象内存图

在这里插入图片描述

多个对象内存图

在这里插入图片描述

多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自的内存区域中,成员方法多个对象共用的一份

多个对象指向相同地址内存图

在这里插入图片描述

当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)

只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据

4. 构造器

在上面提到了类的构造方法分为带参构造和无参构造,通过构造函数可以初始化一个对象,而构造函数的实际意义是什么呢?

可以解释如下:构造函数会在对象能够被赋值给引用变量之前执行,能够让我们介入到new的过程中去。

需要注意的是,编译器在调用构造函数时会调用无参构造,同时构造函数不会有返回值

在创建子类对象时,会发生“构造函数链”的过程,也就是会创建一部分父类:

在这里插入图片描述

在这里插入图片描述

由上图可以看到,在调用构造函数的时候是从子类到父类一层层的调用,但是最终**父类的构造函数一定会在子类构造函数之前结束。**对supper()的调用是子类构造函数的第一个语句。

在使用构造函数时,除了使用supper()调用父类函数以外,还可以使用this()调用对象的本身,但是需要注意的是,supper()和this()不能同时出现在同一个构造函数中

对象的堆内存中,会有专门是一块supper()区域来存放父类数据

在这里插入图片描述

5. 对象的生命周期

局部变量只存活在方法中,实例变量和对象的生命周期一致。

对象的生命周期取决于其“引用变量”只要一个对象存在引用变量,那么它就不会被垃圾收集器(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释放

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值