《Java从小白到大牛》纸质版已经上架了!!!
类实例化可生成对象,实例方法就是对象方法,实例变量就是对象属性。一个对象的生命周期包括三个阶段:创建、使用和销毁。前面章节已经多少用到了对象,这一章详细介绍一下对象的创建和销毁等相关知识。
创建对象包括两个步骤:声明和实例化。
1. 声明
声明对象与声明普通变量没有区别,语法格式如下:
type objectName;
其中type是引用类型,即类、接口和数组。示例代码如下:
String name;
该语句声明了字符串类型对象name。可以声明并不为对象分配内存空间,而只是分配一个引用。
2. 实例化
实例化过程分为两个阶段:为对象分配内存空间和初始化对象,首先使用new运算符为对象分配内存空间,然后再调用构造方法初始化对象。示例代码如下:
String name; name = new String("Hello World");
代码中String("Hello World")表达式就是调用String的构造方法。初始化完成之后如图11-1所示。
一个引用变量没有通过new分配内存空间,这个对象就是空对象,Java使用关键字null表示空对象。示例代码如下:
String name = null; name = "Hello World";
引用变量默认值是null。当试图调用一个空对象的实例变量或实例方法时,会抛出空指针异常NullPointerException,如下代码所示:
String name = null; //输出null字符串 System.out.println(name); //调用length()方法 int len = name.length(); ①
但是代码运行到第①行时,系统会抛出异常。这是因为调用length()方法时,name是空对象。程序员应该避免调用空对象的成员变量和方法,代码如下:
//判断对象是否为null if (name != null) { int len = name.length(); }
提示 产生空对象有两种可能性:第一是程序员自己忘记了实例化,第二是空对象是别人传递给我们的。第一种程序员必须防止这种情况发生,应该仔细检查自己的代码,为自己创建的所有对象进行实例化并初始化。第二种情况需要通过判断对象非null进行避免。
在11.1节使用了表达式new String("Hello World"),其中String("Hello World")是调用构造方法。构造方法是类中特殊方法,用来初始化类的实例变量,这个就是构造方法,它在创建对象(new运算符)之后自动调用。
Java构造方法的特点:
构造方法示例代码如下:
//Rectangle.java文件 package com.a51work6; // 矩形类 public class Rectangle { // 矩形宽度 int width; // 矩形高度 int height; // 矩形面积 int area; // 构造方法 public Rectangle(int w, int h) { ① width = w; height = h; area = getArea(w, h); } ... }
代码第①行是声明了一个构造方法,其中有两个参数w和h,用来初始化Rectangle对象的两个成员变量width和height,注意前面没有任何的返回值。
有时在类中根本看不到任何的构造方法。例如本节中User类代码如下:
//User.java文件 package com.a51work6; public class User { // 用户名 private String username; // 用户密码 private String password; }
从上述User类代码,只有两个成员变量,看不到任何的构造方法,但是还是可以调用无参数的构造方法创建User对象,见如下代码。
//HelloWorld.java文件 ... User user = new User();
Java虚拟机为没有构造方法的类,提供一个无参数的默认构造方法,默认构造方法其方法体内无任何语句,默认构造方法相当于如下代码:
//默认构造方法 public User() { }
默认构造方法的方法体内无任何语句,也就不能够初始化成员变量了,那么这些成员变量就会使用默认值,成员变量默认值是与数据类型有关,具体内容可以参考9.1.2节中的表9-1所示。这里不再赘述。
在一个类中可以有多个构造方法,它们具体有相同的名字(与类名相同),参数列表不同,所以它们之间一定是重载关系。
构造方法重载示例代码如下:
//Person.java文件 package com.a51work6; import java.util.Date; public class Person { // 名字 private String name; // 年龄 private int age; // 出生日期 private Date birthDate; public Person(String n, int a, Date d) { ① name = n; age = a; birthDate = d; } public Person(String n, int a) { ② name = n; age = a; } public Person(String n, Date d) { ③ name = n; age = 30; birthDate = d; } public Person(String n) { ④ name = n; age = 30; } public String getInfo() { StringBuilder sb = new StringBuilder(); sb.append("名字: ").append(name).append( /n ); sb.append("年龄: ").append(age).append( /n ); sb.append("出生日期: ").append(birthDate).append( /n ); return sb.toString(); } }
上述代码Person类代码提供了4个重载的构造方法,如果有准确的姓名、年龄和出生日期信息,则可以选用代码第①行的构造方法创建Person对象;如果只有姓名和年龄信息则可选用代码第②行的构造方法创建Person对象;如果只有姓名和出生日期信息则可选用代码第③行的构造方法创建Person对象;如果只有姓名信息则可选用代码第④行的构造方法创建Person对象。
构造方法也可以进行封装,访问级别与普通方法一样,构造方法的访问级别参考表11-1所示。示例代码如下:
//Person.java文件 package com.a51work6; import java.util.Date; public class Person { // 名字 private String name; // 年龄 private int age; // 出生日期 private Date birthDate; // 公有级别限制 public Person(String n, int a, Date d) { ① name = n; age = a; birthDate = d; } // 默认级别限制 Person(String n, int a) { ② name = n; age = a; } // 保护级别限制 protected Person(String n, Date d) { ③ name = n; age = 30; birthDate = d; } // 私有级别限制 private Person(String n) { ④ name = n; age = 30; } ... }
上述代码第①行是声明公有级别的构造方法。代码第②行是声明默认级别,默认级别只能在同一个包中访问。代码第③行是保护级别的构造方法,该构造方法在同一包中与默认级别相同,在不同包中可以被子类继承。代码第④行是私有级别构造方法,该构造方法只能在当前类中使用,不允许在外边访问,私有构造方法可以应用于单例设计模式等设计。
前面章节中使用过this关键字,this指向对象本身,一个类可以通过this来获得一个代表它自身的对象变量。this使用在如下三种情况中:
使用this变量的示例代码:
//Person.java文件 package com.a51work6; import java.util.Date; public class Person { // 名字 private String name; // 年龄 private int age; // 出生日期 private Date birthDate; // 三个参数构造方法 public Person(String name, int age, Date d) { ① this.name = name; ② this.age = age; ③ birthDate = d; System.out.println(this.toString()); ④ } public Person(String name, int age) { // 调用三个参数构造方法 this(name, age, null); ⑤ } public Person(String name, Date d) { // 调用三个参数构造方法 this(name, 30, d); ⑥ } public Person(String name) { // System.out.println(this.toString()); // 调用Person(String name, Date d)构造方法 this(name, null); ⑦ } @Override public String toString() { return "Person [name=" + name ⑧ + ", age=" + age ⑨ + ", birthDate=" + birthDate + "]"; } }
上述代码中多次用到了this关键字,下面详细分析一下。代码第①行声明三个参数构造方法,其中参数name和age与实例变量name和age命名冲突,参数是作用域为整个方法的局部变量,为了防止局部变量与成员变量命名发生冲突,可以使用this调用局部变量,见代码第②行和第③行。注意代码第⑧行和第⑨行的name和age变量没有冲突,所以可以不使用this调用。
this也可以调用本对象的方法,见代码第④行的this.toString()语句,这本例中this可以省略。
在多个构造方法重载时,一个构造方法可以调用其他的构造方法,这样可以减少代码量,上述代码第⑤行this(name, age, null)使用this调用其他构造方法。类似调用还有代码第⑥行的this(name, 30, d)和第⑦行的this(name, null)。
注意 使用this调用其他构造方法时,this语句一定是该构造方法的第一条语句。例如在代码第⑦行之前调用toString()方法则会发生错误。
对象不再使用时应该销毁。C++语言对象是通过delete语句手动释放,Java语言对象是由垃圾回收器(Garbage Collection)收集然后释放,程序员不用关系释放的细节。自动内存管理是现代计算机语言发展趋势,例如:C#语言的垃圾回收,Objective-C和Swift语言的ARC(内存自动引用计数管理)。
垃圾回收器(Garbage Collection)的工作原理是:当一个对象的引用不存在时,认为该对象不再需要,垃圾回收器自动扫描对象的动态内存区,把没有引用的对象作为垃圾收集起来并释放。
通过对本章的学习,可以了解如何创建Java对象,理解构造方法的作用。此外,还介绍了this关键的使用。
https://edu.csdn.net/combo/detail/594
http://www.zhijieketang.com/group/5