学习《java语言程序设计》的记录
类抽象(class abstraction)是将类的实现和使用分离。类的创建者提供类的描述,让使用者明白如何才能使用类。此类外可以访问的全部方法和数据域,以及期望这些成员如何行动的描述,合称为类的合约(class’s contract)。下图展示 类的使用者不需要知道类是如何实现的。
实现的细节经过封装,对用户隐藏起来,这称为类的封装(class encapsulation)。例如可以创建一个Circle对象,并且可以在不知道面积是如何计算出来的情况下,求出这个圆的面积。
类的抽象和封装是一个问题的两个方面。现实生活中的许多例子都可以说明类抽象的概念。例如:考虑建立一个计算机系统。个人 计算机有很多组件—–CPU、内存、磁盘、主板和风扇等。每个组件都可以看做是一个有属性和方法的对象。要使各个组件一起工作,只需要知道每个部件是怎么用的,以及如何与其他部件进行交互的。无需了解这些组件内部是如何工作的。内部功能的实现被封装起来,对你是隐藏的。所以,你可以组装一台计算机,而不需要了解每个组件是如何实现功能的。
对计算机系统的模拟准确地反应了面向对象方法。每个部件可以看成组件类的对象。例如:你可能已经建立了一个类,模拟用在计算机上的各种类型的风扇,它具有风扇尺寸和速度等属性,还有像开始和停止这样的方法。一个具体的风扇就是该类具有特定属性值的实例。
将得到一笔贷款作为另一个例子。一笔具体的贷款可以看做贷款类Loan的一个对象,利率、贷款额以及还贷时间都是它的数据属性, 计算每月偿还金额和总偿还金额是它的方法。 当你购买一辆汽车时,就用贷款利率、贷款额和还贷时间实例化这个类、创建一个贷款对象。然后,就可以使用这些方法计算贷款的月偿还额和总偿还额。作为一个贷款类Loan的用户,是不需要知道这些方法是如何实现的。
用户可以在不知道如何实现的情况下使用类。假设Loan类是可用的。我们从编写一个使用Loan类的测试类开始
import java.util.Scanner;
public class TestLoanClass {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//Enter yearly interest rate
System.out.println("Enter yearly interest rate,for example,8.25:");
double annualInterestRate = input.nextDouble();
//Enter number of years
System.out.println("Enter number of years as an integer");
int numberOfYears = input.nextInt();
//Enter loan amount
System.out.println("Enter loan amount,for example,120000.95:");
double loanAmount = input.nextDouble();
//Create a Loan object
Loan loan = new Loan(annualInterestRate,numberOfYears, loanAmount);
//Display loan date,monthly payment,and total payment
System.out.println("The loan was created on %s\n" +
"The monthly payment is %.2f\nThe total payment is %.2f\n",
loan.getLoanDate().toStirng,loan.getMonthlyPayment(),loan.getTotalPayment());
}
}
main方法读取利率、还贷时间(以年为单位)、贷款总额;创建一个Loan对象;然后使用Loan类中的实例方法获取月偿还额(第29行)和总偿还额(第30行)
Loan类的实现如下所示
class Loan{
private double annualInterestRate;
private int numberOfYears;
private double loanAmount;
private Date loanDate;
/** Default constructor */
public Loan() {
this(2.5,1,1000);
}
/** Construct a loan with specified annual interest rate,
* number of years,and loan amount
*/
public Loan(double annualInterestRate, int numberOfYears, double loanAmount){
this.annualInterestRate = annualInterestRate;
this.numberOfYears = numberOfYears;
this.loanAmount = loanAmount;
loanDate = new Date();
}
/**return annualInterestRate*/
public double getAnnualInterestRate() {
return annualInterestRate;
}
/** Set a new annualInterestRate */
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
/**return numberOfYears*/
public int getNumberOfYears() {
return numberOfYears;
}
/** Set a new annualInterestRate*/
public void setNumberOfYears(int numberOfYears) {
this.numberOfYears =numberOfYears ;
}
/** Return numberOfYears*/
public double getLoanAmount() {
return loanAmount;
}
/** Set a new loanAmount */
public void setLoanAmount(double loanAmount) {
this.loanAmount = loanAmount;
}
/** Find monthly payment */
public double getMonthlyPayment() {
double monthlyInterestRate = annualInterestRate / 1200;
double monthlyPayment = loanAmount * monthlyInterestRate / (1-
(Math.pow(1/(1+monthlyInterestRate), numberOfYears*12)));
return monthlyPayment;
}
/** Find total payment */
public double getTotalPayment() {
double totalPayment = getMonthlyPayment() * numberOfYears *12;
return totalPayment;
}
/** Return loan date */
public Date getLoanDate() {
return loanDate;
}
}
从类的开发者的角度来看,设计类是为了让很多不同的用户所使用。 为了在更大的应用范围内使用类,类应该通过构造方法、属性和方法提供不同方式的定制。
Loan类包含两个构造方法,四个get方法、三个set方法,以及求月偿还额和总偿还额的方法。可以通过使用无参构造方法或者带三个参数: 年利率、年数和贷款额的构造方法来构造一个Loan对象。当创建一个贷款对象时,它的数据存储在loanDate域中。getLoanDate方法返回日期。三个get方法:getAnnualInterest、getNumberOfYears、getLoanAmount分别返回年利率、还款时间以及贷款总额。这个类的所有数据属性和方法都被绑定到Loan类的某个特定实例。它们都是实例变量或方法。
Loan类的UML图如图所示。学习应该从编写使用Loan类的测试程序开始,
它演示开发类和实用类是两个不同的任务。
它能使你跳过某个类的复杂实现,而不干扰整个类的顺序。
如果你通过使用它熟悉了类,那么你更容易学会如何实现一个类。