第11章 对象的生命周期
一、创建对象的方式
4种显式地创建对象的方式:
(1)用new语句创建对象;
(2)运用反射手段;
(3)调用对象的clone()方法;
(4)运用反序列化手段。
public class Customer implements Cloneable{
private String name;
private int age;
public Customer(){
this("unknown",0);
System.out.println("call default constructor");
}
public Customer(String name,int age){
this.name=name;
this.age=age;
System.out.println("call second constructor");
}
public Object clone()throws CloneNotSupportedException{
return super.clone();
}
public boolean equals(Object o){
if (this==o)
return true;
if(!(o instanceof Customer))
return false;
final Customer other=(Customer)o;
if(this.name.equals(other.name)&&this.age==other.age)
return true;
else
return false;
}
public String toString(){
return "name="+name+",age="+age;
}
public static void main(String args[])throws Exception{
//运用反射手段创建对象
Class objClass=Class.forName("Customer");
Customer c1=(Customer)objClass.newInstance(); //这里会调用默认构造方法
System.out.println("c1: "+c1);
//用new语句创建对象
Customer c2=new Customer("Tom",20);
System.out.println("c2: "+c2);
//运用克隆手段创建对象
Customer c3=(Customer)c2.clone(); //这里不会调用Customer的构造方法
System.out.println("c2==c3 : "+(c2==c3));
System.out.println("c2.equals(c3) : "+c2.equals(c3));
System.out.println("c3: "+c3);
}
}
打印结果如下:
call second constructor
call default constructor
c1: name=unknown,age=0
call second constructor
c2: name=Tom,age=20
c2==c3 : false
c2.equals(c3) : true
c3: name=Tom,age=20
二、构造方法
构造方法负责对象的创建工作,并为其实例变量赋予合适的初始值。必须满足以下语法规则:
(1)方法名必须与类名相同。
(2)不要声明返回类型。
(3)不能被static/final/synchronized/abstract/native修饰。构造方法不能被子类继承。
1、重载构造方法
示例:
public class Employee{
private String name;
private int age;
//当雇员姓名和年龄已知
public Employee(String name,int age){
this.age=age;
this.name=name;
}
//当雇员姓名已知,而年龄未知
public Employee(String name){
this(name,-1);//调用上一个构造函数,用-1表示年龄未知
}
//当雇员姓名和年龄都未知
public Employee(){
this("无名氏");
}
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
以下程序分别通过3个构造方法创建了3个Employee对象
Employee zhangsan=new Employee("zhangsan",25);
Employee lisi=new Employee("lisi");
Employee someone=new Employee();
关于this语句的用法必须注意:
(1)如果在构造方法中使用this语句,那它必须作为该方法的第一条语句。
(2)只能在构造方法中使用this语句调用类的其他构造方法,不能在类的实例方法中使用。
2、默认构造方法
默认构造方法是指没有参数的构造方法,分为两种:
(1)隐式包含的默认构造方法。
当类的定义中没有任何显式的构造方法(无参或有参)时,则系统默认会给该类一个隐式的无参构造方法。
(2)显式定义的默认构造方法。
当类中显式定义了一个无参构造方法。
要注意的是:当类中显式定义了一个或多个构造方法,并且所有构造方法都带参数,则这个类就失去了默认构造方法。
3、子类调用父类的构造方法
父类的构造方法不能被子类继承,如MyException类继承了java.lang.Exception类:
public class MyException extends Exception{}
上述MyException只有一个隐式的默认构造方法。虽然Exception类用如下的构造方法:
public Exception(String msg){...}
但Myexception是无法继承该构造方法的,以下代码编译出错:
MyException myExcp=new MyException("Hey,Error!");
但是,在子类的构造方法中,可以通过super语句调用父类的构造方法,比如:
public MyException(){
super("something is error");
}
public MyException(String msg){
super(msg);
}
用super语句来调用父类的构造方法,必须遵守以下规则:
(1)在子类构造方法中,不能直接通过父类方法名调用父类构造方法,而必须用super。
(2)当使用super语句调用父类构造方法时,它必须作为构造方法的第一条语句。
在创建子类对象时,Java虚拟机先执行父类构造方法,再执行子类构造方法,在多级继承中,将从继承树最上层父类开始依次执行各个类的构造方法,如下例:
public class Base{
private int a;
public Base(int a){
this.a=a;
System.out.println("父类Base有参构造函数执行了!");
}
public int getA(){
return this.a;
}
}
public class Test extends Base{
private int b;
public Test(int a,int b){
super(a);
this.b=b;
System.out.println("子类Test有参构造函数执行了");
}
public int getB(){
return this.b;
}
public static void main(String[] args){
Test test=new Test(1,2);
System.out.println("a="+test.getA()+" b="+test.getB());
}
}
输出如下:
父类Base无参构造函数执行了!
子类Test有参构造函数执行了
a=0 b=2
4、构造方法的作用域
构造方法只能通过以下方式被调用:
(1)当前类的其他构造方法通过this语句调用它;
(2)当前类的子类的构造方法通过super语句调用它;
(3)在程序中通过new语句调用它。
5、构造方法的访问级别
构造方法可以处于public/protected/private和默认中之一,当构造方法为private级别时,意味着只能在当前类中访问它:在当前类的其他构造方法中可以通过this语句调用,也可以在当前类的成员方法中通过new语句调用它。