Java学习之旅(二九):对象
Java 是一门面向对象的程序设计语言,对象是由类抽象出来的,所有的问题都通过对象来处理。对象可以操作类的属性和方法解决相应的问题,所以了解对象的创建、操作和销毁是十分必要的。
对象的创建
我们可以认为对象是在一类事物中抽象出某一个特例,可以通过这个特例来处理这类事物出现的问题。在 Java 语言中通过 new 操作符来创建对象。每实例化一个对象就会自动调用一次构造方法,实质上这个过程就是创建对象的过程。准确地说,可以在 Java 语言中使用 new 操作符调用构造方法创建对象。语法为:
Test test = new Test();
Test test = new Test("a");
其中,Test 为类名,test 为创建的 Test 类对象,new 为创建对象的操作符,a 为构造方法的参数。
test 对象被创建出来时,就是一个对象的引用,这个引用在内存中为对象分配了存储空间。在构造方法中初始化成员变量,当创建对象时,自动调用构造方法。也就是说,在 Java 语言中初始化与创建是被捆绑在一起的。每个对象都是相互独立的,在内存中占据独立的内存地址,并且每个对象都具有自己的生命周期,当一个对象的生命周期结束时,对象就变成垃圾,由 Java 虚拟机自带的垃圾回收机制处理,不能再被使用。
public class CreateObject {
//构造方法
public CreateObject() {
System.out.println("创建对象!");
}
public static void main(String[] args) {
//使用 new 操作符创建对象的同时,将自动调用构造方法中的代码
new CreateObject(); //创建对象
}
}
访问对象的属性和行为
用户使用 new 操作符创建一个对象后,可以使用“对象.类成员”来获取对象的属性和行为。我们已经知道对象的属性和行为在类中是通过类成员变量和成员方法的形式来表示的,所以当对象获取类成员时,也相应地获取了对象的属性和行为。
public class ObjectProperty {
int i = 10;//成员变量
//成员方法
public void call() {
System.out.println("调用 call() 方法");
for (int i = 0; i < 3; i++) {
System.out.print(i + " ");
if (i == 2) {
System.out.println("\n");
}
}
}
//构造方法
public ObjectProperty() {
}
public static void main(String[] args) {
ObjectProperty object1 = new ObjectProperty();
ObjectProperty object2 = new ObjectProperty();
object2.i = 60;
//使用第一个对象调用类成员变量
System.out.println("第一个实例对象调用变量 i 的结果:" + object1.i);
object1.call();
//使用第二个对象调用类成员变量
System.out.println("第二个实例对象调用变量 i 的结果:" + object2.i);
object2.call();
}
}
在该上述主方法中,首先实例化一个对象,然后使用“.”操作符调用类的成员变量和成员方法。但是在运行结果中可以看到,虽然使用两个对象调用同一个成员变量,结果却不相同,因为在打印这个成员变量的值之前将该值重新赋值为60,但在赋值时使用的是第二个对象 object2 调用成员变量,所以在第一个对象 object1 调用成员变量打印该值时仍然是成员变量的初始值。由此可见,两个对象的产生是相互独立的,改变了 object2 的 i 值,不会影响到 object1 的 i 值。在内存中这两个对象的布局如下:
如果希望成员变量不被其中任何一个对象改变,可以使用 static 关键字来将成员变量设置为静态成员变量,来被本类的对象共享。
public class ObjectProperty {
static int i = 10;//成员变量
//成员方法
public void call() {
System.out.println("调用 call() 方法");
for (int i = 0; i < 3; i++) {
System.out.print(i + " ");
if (i == 2) {
System.out.println("\n");
}
}
}
//构造方法
public ObjectProperty() {
}
public static void main(String[] args) {
ObjectProperty object1 = new ObjectProperty();
ObjectProperty object2 = new ObjectProperty();
object2.i = 60;
//使用第一个对象调用类成员变量
System.out.println("第一个实例对象调用变量 i 的结果:" + object1.i);
object1.call();
//使用第二个对象调用类成员变量
System.out.println("第二个实例对象调用变量 i 的结果:" + object2.i);
object2.call();
}
}
对象的引用
在 Java 语言中尽管一切都可以看作对象,但真正的操作标识符实质上是一个引用,那么引用在 Java 中是如何体现的呢?语法如下:
类名 对象引用名称
//如一个 Book 类的引用可以使用如下代码:
Book book;
//通常一个引用不一定需要有一个对象相关联。引用与对象相关联语法如下:
Book book = new Book();
引用只是存放一个对象的内存地址,并非存放一个对象。严格地说,引用和对象是不同的,但是可以将这种区别忽略,如可以简单地说 book 是 Book 类的一个对象,而事实上应该是 book 包含 Book 对象的一个引用。
对象的比较
在 Java 语言中有两种比较对象的方式,分别为“==”运算符与 equala() 方法。
public class Compare {
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("abc");
String s3 = s1;
System.out.println("s2 == s3 ? " + (s2 == s3));
System.out.println("s2.equals(s3) ? " + s2.equals(s3));
}
}
“==”运算符和 equals() 方法比较的内容是不相同的,equals() 方法是 String 类中的方法,它用于比较两个对象引用所指的内容是否相等;而“==”运算符比较的是两个对象引用的地址是否相等。由于 s1 与 s2 是两个不同的对象引用,两者在内存中的位置不同,而“String s3 = s1;”语句将 s1 的引用赋给 s3,所以 s1 和 s3 这两个对象引用是相等的,也就是打印 s1 == s3 时返回 true。
对象的销毁
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址需要被回收。在其他语言中,需要用户手动回收废弃的对象。Java 拥有一套完整的垃圾回收机制,用户其实不必担心废弃的对象占用内存,垃圾回收器会自动回收无用却占用内存的资源。
一般来说,在 Java 中,当对象引用超过其作用范围时,对象将消亡,这个对象将被视为垃圾;当对象被赋值为 null 时将消亡,这个对象也将被视为垃圾。虽然垃圾回收机制已经很完善,但垃圾回收器只回收那些由 new 操作符创建的对象。某些对象不是通过 new 操作符在内存中获取存储空间的,这种对象是无法被垃圾回收机制识别的。在 Java 中提供了一个 finalize() 方法,这个方法是 Object 类的方法,它被声明为 protected,用户可以在自己的类中定义这个方法。如果用户在类中定义了 finalize() 方法,在垃圾回收时会首先调用该方法,在下一次垃圾回收动作发生时,才真正回收被对象占用的内存。垃圾回收或 finalize() 方法并不保证一定会发生。如果 Java 虚拟机内存损耗殆尽,它将不会执行垃圾回收处理。由于垃圾回收不受人为控制,具体执行时间也不确定,所以 finalize() 方法也就无法执行。为此,Java 提供了 System.gc() 方法来强制启动垃圾回收器,这与给120打电话通知医院来救护病人的道理一样,主动告知垃圾回收器来进行处理。
下一篇: Python-简单网络抓取