对象
类实例化可生成对象, 实例方法就是对象方法,实例变量就是对象属性。 一个对象的生命周期包括三个阶段: 创建、使用和销毁。
创建对象
创建对象包括两个步骤:声明和实例化。
1. 声明
声明对象与声明普通变量没有区别,语法格式如下:
type objectName;
其中 type 是引用类型,即类、接口和数组。示例代码如下:
String name;
该语句声明了字符串类型对象 name。可以声明并不为对象分配内存空间,而只是分配一个引用。
2. 实例化
实例化过程分为两个阶段:为对象分配内存空间和初始化对象,首先使用 new 运算符为对象分配内存空间,然后再调用构造方法初始化对象。示例代码如下:
String name;
name = new String("Hello World");
代码中 String("Hello World")表达式就是调用 String 的构造方法。初始化完成之后如图 所示。
空对象
一个引用变量没有通过 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进行避免。
构造方法
构造方法是类中特殊方法,用来初始化类的实例变量,这个就是构造方法,它在创建对象(new 运算符)之后自动调用。
Java 构造方法的特点:
1. 构造方法名必须与类名相同。
2. 构造方法没有任何返回值,包括 void。
3. 构造方法只能与 new 运算符结合使用。
构造方法示例代码如下:
//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文件
packagecom.a51work6;
publicclass User {
//用户名
privateString username;
//用户密码
privateString password;
}
从上述 User 类代码,只有两个成员变量,看不到任何的构造方法,但是还是可以调用无参数的构造方法创建 User 对象,见如下代码。
//HelloWorld.java文件
...
Useruser = new User();
Java 虚拟机为没有构造方法的类,提供一个无参数的默认构造方法,默认构造方法其方法体内无任何语句,默认构造方法相当于如下代码:
//默认构造方法
publicUser() {
}
默认构造方法的方法体内无任何语句,也就不能够初始化成员变量了,那么这些成员变量就会使用默认值,成员变量默认值是与数据类型有关。
构造方法重载
在一个类中可以有多个构造方法,它们具体有相同的名字(与类名相同),参数列表不同,所以它们之间一定是重载关系。
构造方法重载示例代码如下:
/
//Person.java文件
packagecom.a51work6;
importjava.util.Date;
publicclass Person {
//名字
privateString name;
//年龄
privateint age;
//出生日期
privateDate birthDate;
publicPerson(String n, int a, Date d) { ①
name= n;
age= a;
birthDate= d;
}
publicPerson(String n, int a) { ②
name= n;
age= a;
}
publicPerson(String n, Date d) { ③
name= n;
age= 30;
birthDate= d;
}
publicPerson(String n) { ④
name= n;
age= 30;
}
publicString getInfo() {
StringBuildersb = new StringBuilder();
sb.append("名字:").append(name).append('\n');
sb.append("年龄: ").append(age).append('\n');
sb.append("出生日期:").append(birthDate).append('\n');
returnsb.toString();
}
}
上述代码 Person 类代码提供了 4 个重载的构造方法,如果有准确的姓名、年龄和出生日期信息,则可以选用代码第①行的构造方法创建 Person 对象;如果只有姓名和年龄信息则可选用代码第②行的构造方法创建 Person 对象;如果只有姓名和出生日期信息则可选用代码第③行的构造方法创建 Person 对象;如果只有姓名信息则可选用代码第④行的构造方法创建 Person 对象。
构造方法封装
构造方法也可以进行封装,访问级别与普通方法一样,构造方法的访问级别参考表11-1所示。示例代码如下:
//Person.java文件
packagecom.a51work6;
importjava.util.Date;
publicclass Person {
//名字
privateString name;
//年龄
privateint age;
//出生日期
privateDate birthDate;
//公有级别限制
publicPerson(String n, int a, Date d) { ①
name= n;
age= a;
birthDate= d;
}
//默认级别限制
Person(Stringn, int a) { ②
name= n;
age= a;
}
//保护级别限制
protectedPerson(String n, Date d) { ③
name= n;
age= 30;
birthDate= d;
}
//私有级别限制
privatePerson(String n) { ④
name= n;
age= 30;
}
...
}
上述代码第①行是声明公有级别的构造方法。代码第②行是声明默认级别,默认级别只能在同一个包中访问。代码第③行是保护级别的构造方法,该构造方法在同一包中与默认级别相同,在不同包中可以被子类继承。代码第④行是私有级别构造方法,该构造方法只能在当前类中使用,不允许在外边访问,私有构造方法可以应用于单例设计模式等设计。
this关键字
前面章节中使用过 this 关键字, this 指向对象本身,一个类可以通过 this 来获得一个代表它自身的对象变量。 this 使用在如下三种情况中:
调用实例变量。
调用实例方法。
调用其他构造方法。
使用 this 变量的示例代码:
//Person.java文件
packagecom.a51work6;
importjava.util.Date;
publicclass Person {
//名字
privateString name;
//年龄
privateint age;
//出生日期
privateDate birthDate;
//三个参数构造方法
publicPerson(String name, int age, Date d) { ①
this.name= name; ②
this.age= age; ③
birthDate= d;
System.out.println(this.toString());④
}
publicPerson(String name, int age) {
//调用三个参数构造方法
this(name,age, null); ⑤
}
publicPerson(String name, Date d) {
//调用三个参数构造方法
this(name,30, d); ⑥
}
publicPerson(String name) {
//System.out.println(this.toString());
//调用Person(String name, Date d)构造方法
this(name,null); ⑦
}
@Override
publicString 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()方法则会发生错误。