Java 是一门面向对象的程序设计语言,对象是由类抽象出来的,所有的问题都是通过对象来处理,对象可以操作类的属性和方法解决相应的问题,所以了解对象的产生、操作和消亡对学习 Java 语言是十分必要的。
对象是在一类事物中抽象出某一个特例,通过这个特例来处理这类事物出观的问题。在 Java 语言中通过 new 操作符来创建对象。每实例化一个对象就会自动调用一次类的构造方法,实质上这个过程就是创建对象的过程。准确地说,可以在 Java 语言中使用 new 操作符调用构造方法来创建时象。
Person 类定义:
public class Person { public Person() {} public Person(String name, int age) { //... } //... }
创建对象语法格式:
// 调用默认构造方法创建对象 Person p1 = new Person(); // 调用带有名称和年龄的构造方法创建对象 Person p2 = new Person("Tom", 30);
详细说明:
(1)Person 表示类名
(2)p1 和 p2 表示两个指向 Person 类的对象,它们被创建出来时就是一个对象的引用,这个引用在内存中为对象分配了存储空间,可以在构造方法中初始化成员变量。
(3)new 是一个关键字,用来创建对象
(4)"Tom" 和 30 表示 Person 类的构造方法的实参参数
示例:
package com.hxstrive.demo; public class Person { // 姓名 private String name; // 年龄 private int age; public Person() { } public Person(String name, int age) { System.out.println("创建对象"); this.name = name; this.age = age; } public static void main(String[] args) { // 创建对象 p,对象类型为 Person Person p = new Person("Tom", 30); System.out.println("name=" + p.name + ", age=" + p.age); } }
运行示例,输出如下:
创建对象 name=Tom, age=30
当用户使用 new 操作符创建一个对象后,可以使用 “对象.类成员” 来获取对象的属性和行为。前文已经提到过,对象的属性和行为在类中是通过类成员变量和成员方法的形式来表示的,所以当对象获取类成员,也就相应地获取了对象的属性和行为。
示例:创建一个 Person 类,然后在 main 方法中创建该类的对象,通过该对象设置和打印用户姓名和年龄,演示如何访问对象的属性和行为。
package com.hxstrive.demo; public class Person { // 姓名 private String name; // 年龄 private int age; // 定义一个行为,用来返回用户名和年龄 public String show() { // this 表示当前对象 return "name=" + this.name + ", age=" + this.age; } public Person(String name, int age) { System.out.println("创建对象"); // 初始化成员 this.name = name; this.age = age; } public static void main(String[] args) { Person p = new Person("Tom", 30); // 引用对象属性 // 重新将 name 成员的值设置为 “NewTom” p.name = "NewTom"; // 引用对象行为 System.out.println(p.show()); } }
运行示例,输出如下:
创建对象 name=NewTom, age=30
在上面的 Person 例子中,有如下语句:
Person p = new Person("Tom", 30);
上面语句创建了有一个 Person 实例,也被称为 Person 对象,这个 Person 对象被赋给 p 变量。该语句实际产生了两个东西:
(1)一个 p 变量,变量类型为 Person。
(2)一个 Person 实例,即 Person 对象,p 变量指向该对象。
从 Person 类的定义可知,Person 独享包含两个成员(name 和 age)。因此,当创建 Person 对象时,必然需要有对应的内存来存储 Person 对象自身和成员。Person 对象由多块内存组成,不同内存块分别存储了 Person 对象的不同成员。当把这个 Person 对象赋值给一个引用变量时,变量就指向了这个对象。
因此,变量 p 实际上就是一个引用,它被存放在栈内存里,指向实际的 Person 对象。而真正的 Person 对象则存放在堆(heap)内存中。栈内存里的引用变量并未真正存储对象的成员数据,对象的成员数据实际存放在堆内存里;而引用变量只是指向该堆内存里的对象。
引用变量指向实际对象示意图:
在 Java 语言中有两种对象的比较方式,分别为 “==” 运算符与 equals() 方法。它们的区别如下:
==:对于基本类型,比较的是值是否相等;对于引用类型,比较的是地址是否相等;
equals:比较的是对象是否相等(不能比较基本类型,因为 equals 是 Object 超类中的方法,而 Object 是所有类的父类);
示例:
public class Compare { public static void main(String[] args) { // 创建两个String型对象引用 String c1 = new String("abc"); String c2 = new String("abc"); // 将 c1 对象引用赋予 c3 String c3 = c1; // 使用 “==” 运算符比较 c2 与 c3 System.out.println("c2==c3 的运算结果为:" + (c2 == c3)); // 使用 equals() 方法比较 c2 与 c3 System.out.println("c2.equals(c3) 的运算结果为:" + (c2.equals(c3))); } }
运行示例,输出如下:
c2==c3 的运算结果为:false c2.equals(c3) 的运算结果为:true
从上述运行结果中可以看出,“==” 运算符和 equals() 方法比较的内容是不相同的。equals() 方法是 String 类中的方法,它用于比较两个对象引用所指的内容是否相等;而 “==” 运算符比较的是两个对象引用的地址是否相等。
由于 c1 与 c2 是两个不同的对象引用,两者在内存中的位置不同,而 “Stringc3=cl;" 语句将 c1 的引用赋给 c3,所以 c1 与 c3 这两个对象引用是相等的。
Java 中,每个对象都有其生命周期,当对象的生命周期结束时,分配给该对象的内存将会被回收,而在其他语言中则需要手动回收废弃的对象,但是 Java 语言拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器将回收无用的占用内存的资源。
在谈到垃圾回收机制之前,首先需要了解何种对象会被 Java 虚拟机视为垃圾。主要包括以下两种情况:
(1)对象引用超过其作用范围,则这个对象将被视为垃圾,例如:
System.out.println("1"); { // 该 p 变量的作用范围仅在该大花括号中 Person p = new Person("Tom", 30); System.out.println(p.show()); } System.out.println("3");
(2)将对象赋值为 null,例如:
Person p = new Person("Tom", 30); System.out.println(p.show()); p = null; // 手动将 p 设为废弃对象
虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由 new 操作符创建的对象,如果某些对象不是通过 new 操作符在内存中获取一块内存区域,这种对象可能不被垃圾回收机制所识别。所以在 Java 语言中提供了一个 finalize() 方法,这个方法是 Object 类的方法,它被声明为 protected,用户可以在自己的类中定义这个方法,如果用户在类中定义了 finalize() 方法,在垃圾回收时首先调用该方法,并且在下一次垃圾回收动作发生时,才能真正回收对象占用的内存。
由于垃圾回收不受人为控制,具体执行时间也不确定,所以 finalize() 方法的执行不能得到保证,为此,Java 提供了 System.gc() 方法强制启动垃圾回收器。
Java 提供了一个 this 关键字,this 关键字总是指向调用该方法的对象。根据 this 出现位置的不同,this 作为对象的默认引用有两种情形:
(1)构造器中,this 引用该构造器正在初始化的对象;
(2)在方法中 this 引用调用该方法的对象;
this 关键字最大的作用就是让类中一个方法访问该类里的另一个方法或成员。例如:
public class Dog { private String name; public Dog(String name) { // this 引用正在初始化的对象 this.name = name; } public void run() { // this 引用调用该方法的对象 System.out.println("run() name=" + this.name); this.jump(); } public void jump() { System.out.println("jump() name=" + this.name); } public static void main(String[] args) { Dog dog = new Dog("Tom"); dog.run(); } }
运行示例,输出如下:
run() name=Tom jump() name=Tom