java学习笔记4--对象的初始化与回收
1、对象初始化和回收
对象初始化
系统在生成对象时,会为对象分配内存空间,并自动调用构造方法对实例变量进行初始化
对象回收
对象不再使用时,系统会调用垃圾回收程序将其占用的内存回收
构造方法
-
一种和类同名的特殊方法
-
用来初始化对象
-
Java中的每个类都有构造方法,用来初始化该类的一个新的对象
-
没有定义构造方法的类,系统自动提供默认的构造方法
-
方法名与类名相同
-
没有返回类型,修饰符void也不能有
-
通常被声明为公有的(public)
-
可以有任意多个参数
-
主要作用是完成对象的初始化工作
-
不能在程序中显式的调用
-
在生成一个对象时,系统会自动调用该类的构造方法为新生成的对象初始化
系统提供的默认构造方法
如果在类的声明中没有声明构造方法,则Java编译器会提供一个默认的构造方法;默认的构造方法没有参数,其方法体为空;使用默认的构造方法初始化对象时,如果在类声明中没有给实例变量赋初值,则对象的属性值为零或空
例:声明一个银行帐号类及测试代码
public class BankAccount{ String ownerName; int accountNumber; float balance; } public class BankTester{ public static void main(String args[]){ BankAccount myAccount = new BankAccount(); System.out.println("ownerName=" + myAccount.ownerName); System.out.println("accountNumber=" + myAccount.accountNumber); System.out.println("balance=" + myAccount.balance); } }
ownerName=null
accountNumber=0
balance=0.0
可在生成对象时给构造方法传送初始值,使用希望的值给对象初始化
构造方法可以被重载,构造方法的重载和方法的重载一致
一个类中有两个及以上同名的方法,但参数表不同,这种情况就被称为方法重载。在方法调用时,Java可以通过参数列表的不同来辨别应调用哪一个方法为BankAccount声明一个有三个参数的构造方法
public BankAccount(String initName, int initAccountNumber, float initBalance) { ownerName = initName; accountNumber = initAccountNumber; balance = initBalance; }
假设一个新帐号的初始余额可以为0,则可增加一个带有两个参数的构造方法
public BankAccount(String initName, int initAccountNumber) { ownerName = initName; accountNumber = initAccountNumber; balance = 0.0f; }
自定义无参的构造方法
无参的构造方法对其子类的声明很重要。如果在一个类中不存在无参的构造方法,则要求其子类声明时必须声明构造方法,否则在子类对象的初始化时会出错
在声明构造方法时,好的声明习惯是不声明构造方法;如果声明,至少声明一个无参构造方法
class Bush { Bush(int i) {} Bush(double d) {} }
如果写:new Bush(); 编译器将要告诉你找不到对应的构造方法
说明:
用户在进行类声明时,如果没有声明任何构造方法,系统会赋给此类一个默认(无参)的构造方法。但是,只要用户声明了构造方法,即使没有声明无参的构造方法,系统也不再赋默认的构造方法
例:创建一个拥有两个构造方法的Tree类,一个有参,一个无参。
import java.util.*; class Tree { int height; Tree() { prt("Planting a seedling"); height = 0; } Tree(int i) { prt("Creating new Tree that is "+ i + " feet tall"); height = i; } void info() { prt("Tree is " + height + " feet tall"); } void info(String s) { prt(s + ": Tree is " + height + " feet tall"); } static void prt(String s) { System.out.println(s); } }
测试Tree类:
public class javatest { public static void main(String[] args) { for(int i = 0; i < 5; i++) { Tree t = new Tree(i); t.info(); t.info("overloaded method"); } new Tree(); } }
测试结果:
Creating new Tree that is 0 feet tall
Tree is 0 feet tall
overloaded method: Tree is 0 feet tall
Creating new Tree that is 1 feet tall
Tree is 1 feet tall
overloaded method: Tree is 1 feet tall
Creating new Tree that is 2 feet tall
Tree is 2 feet tall
overloaded method: Tree is 2 feet tall
Creating new Tree that is 3 feet tall
Tree is 3 feet tall
overloaded method: Tree is 3 feet tall
Creating new Tree that is 4 feet tall
Tree is 4 feet tall
overloaded method: Tree is 4 feet tall
Planting a seedling
this关键字的使用:
-
可以使用this关键字在一个构造方法中调用另外的构造方法
-
代码更简洁,维护起来也更容易
-
通常用参数个数比较少的构造方法调用参数个数最多的构造方法
使用this关键字,修改BankAccout类中无参数和两参数的构造方法:
public BankAccount() { this("", 999999, 0.0f); } public BankAccount(String initName, int initAccountNumber) { this(initName, initAccountNumber, 0.0f); } public BankAccount(String initName, int initAccountNumber, float initBalance) { ownerName = initName; accountNumber = initAccountNumber; balance = initBalance; }
2、内存回收技术
当一个对象在程序中不再被使用时,就成为一个无用对象,当前的代码段不属于对象的作用域,把对象的引用赋值为空
Java运行时系统通过垃圾收集器周期性地释放无用对象所使用的内存
Java运行时系统会在对对象进行自动垃圾回收前,自动调用对象的finalize()方法
垃圾收集器
自动扫描对象的动态内存区,对不再使用的对象做上标记以进行垃圾回收
作为一个线程运行,通常在系统空闲时异步地执行
当系统的内存用尽或程序中调用System.gc()要求进行垃圾收集时,与系统同步运行
finalize()方法
-
在类java.lang.Object中声明,因此 Java中的每一个类都有该方法
-
用于释放系统资源,如关闭打开的文件或socket等
-
声明格式
protected void finalize() throws throwable
如果一个类需要释放除内存以外的资源,则需在类中重写finalize()方法
应用举例:
对银行帐户类BankAccount进行一系列修改和测试:
-
声明BankAccount类
-
声明toString()方法
-
声明存取款方法
-
使用DecimalFormat类
-
声明类方法生成特殊的实例
-
声明类变量
-
包括状态、构造方法、get方法及set方法
public class BankAccount{ private String ownerName; private int accountNumber; private float balance; public BankAccount() { this("", 0, 0); } public BankAccount(String initName, int initAccNum, float initBal) { ownerName = initName; accountNumber = initAccNum; balance = initBal; } public String getOwnerName() { return ownerName; } public int getAccountNumber() { return accountNumber; } public float getBalance() { return balance; } public void setOwnerName(String newName) { ownerName = newName; } public void setAccountNumber(int newNum) { accountNumber = newNum; } public void setBalance(float newBalance) { balance = newBalance; } }
声明测试类AccountTester
public class AccountTester { public static void main(String args[]) { BankAccount anAccount; anAccount = new BankAccount("ZhangLi", 100023,0); anAccount.setBalance(anAccount.getBalance() + 100); System.out.println("Here is the account: " + anAccount); System.out.println("Account name: " + anAccount.getOwnerName()); System.out.println("Account number: " + anAccount.getAccountNumber()); System.out.println("Balance: $" + anAccount.getBalance()); } }
Here is the account: BankAccount@372a1a
Account name: ZhangLi
Account number: 100023
Balance: $100.0
声明toString()方法
将对象的内容转换为字符串
Java的所有类都有一个默认的toString()方法,其方法体如下:
getClass().getName() + '@' + Integer.toHexString(hashCode())
下面的两行代码等价:
System.out.println(anAccount); System.out.println(anAccount.toString());
如果需要特殊的转换功能,则需要自己重写toString()方法
toString()方法的几点说明
-
必须被声明为public
-
返回类型为String
-
方法的名称必须为toString,且没有参数
-
在方法体中不要使用输出方法System.out.println()
public String toString() { return("Account #" + accountNumber + " with balance $" + balance); }