Java语言程序设计 习题第十三章
13.1章节习题
13.1 在下面类的定义中,哪些定义了合法的抽象类?
a)
//错误,有只有抽象类中才能有抽象方法
class A {
abstract void unfinished() {
}
}
b)
// 关键字abstract写错了位置,应该写在class前面
// 习惯上会将访问修饰符(如 public、protected、private)放在前面,而将其他修饰符(如 abstract、final、static)放在后面
public class abstract A {
abstract void unfinished();
}
c)
// 错误,有只有抽象类中才能有抽象方法
class A {
abstract void unfinished():
}
d)
// 错误,抽象类中的普通方法需要有{},不能省略
abstract class A {
protected void unfinished();
}
e)
// 正确
abstract class A {
abstract void unfinished();
}
f)
// 正确
abstract class A {
abstract int unfinished();
}
13.2 getArea() 方法和 getPerimeter() 方法可以从 GeometricObject 类中删除。在 GeometricObject 类中将这两个方法定义为抽象方法的好处是什么?
在编译(compilation)期,一个声明为GeometricObject的对象可以使用这两个方法
否则,就没办法计算周长和面积
13.3 下面说法为真还是为假?
a. 除了不能使用 new 操作符创建抽象类的实例之外,一个抽象类可以像非抽象类一样使用。
真
b. 抽象类可以被继承
真
c. 非抽象的父类的子类不能是抽象的
假
d. 子类不能将父类中的具体方法重写,并定义为抽象的
假
e. 抽象方法必须是非静态的
真
13.3章节习题
13.4 为什么下面两行代码可以编译成功,但是会导致运行错误?
// 第二行等号右侧想要把Integer类型的numberRef转换为Double类型,而Integer和Double没有继承关系,如果Double是Integer的父类,就会运行成功
Number numberRef = new Integer(0);
Double doubleRef = (Double)numberRef;
13.5 为什么下面两行代码可以编译成功,但是会导致运行错误?
//和上一题类似,不能把Double转换成Integer
Number[] numberArray = new Integer[2];
numberArray[0] = new Double(1.5);
13.6 给出下面代码的输出。
public class Test {
public static void main(String[] args) {
Number x = 3;
System.out.println(x.intValue());
System.out.println(x.doubleValue());
}
}
3
3.0
13.7 下面代码有什么错误? (注意,Integer和Double类的compareTo方法在第10.7节中进行了介绍)
// 很好的例子,因为compareTo只是Integer和Double的方法,并不是Number的方法
public class Test {
public static void main(String[] args) {
Number x = new Integer(3);
System.out.println(x.intValue());
System.out.println(x.compareTo(new Integer(4)));
}
}
13.8 下面代码中有什么错误?
// 很好的例子,11章讲过,“.”是成员对象访问符,运算顺序优先于类型转化。所以编译器会先检查x.compareTo,自然不通过,理由在上一题
//应该改成((Integer)x).compareTo(new Integer(4))
public class Test {
public static void main(String[] args) {
Number x = new Integer(3);
System.out.println(x.intValue());
System.out.println((Integer)x.compareTo(new Integer(4)));
}
}
13.4 章节习题
13.9 可以使用Calendar类来创建一个Calendar对象吗?
不可以,Calendar是一个抽象类
13.10 Calendar类中哪个方法是抽象的?
add方法
13.11 如何为当前时间创建一个 Calendar 对象?
GregorianCalendar的无参构造方法
13.12 对于一个 Calendar 对象 c 而言,如何得到它的年、月、日期 、小时 、分钟以及秒钟?
package learning;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class Test {
public static void main(String[] args) {
Calendar c = new GregorianCalendar();
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
System.out.println(c.get(Calendar.HOUR));
System.out.println(c.get(Calendar.MINUTE));
System.out.println(c.get(Calendar.SECOND));
}
}
输出结果:
需要注意的是,Calendar类中的MONTH是从0计数的
2023
4
15
9
35
25
13.5章节习题
13.13 假设A是一个接口,可以使用newA()创建一个实例吗?
不可以
13.14 假设A是一个接口,可以如下声明一个类型A的引用变量x吗?
A x;
可以
13.15 下面哪个是正确的接口?
// 在抽象类中,既可以有抽象方法(没有方法体),也可以有具体的方法(有方法体),子类继承抽象类后,必须实现抽象方法,可以选择性的实现具体的方法
// 在旧版本的Java中,接口只能包含抽象方法,这些方法没有方法体。但是,自Java 8开始,接口也可以包含默认方法和静态方法
(a)
// 错误,接口不能有方法体
interface A {
void print() { }
}
(b)
// 错误,接口不能用abstract修饰,接口不能有方法体
abstract interface A {
abstract void print() { }
}
(c)
// 错误,接口不能用abstract修饰
abstract interface A {
print();
}
(d)
//正确
interface A {
void print();
}
(e)
//正确
interface A {
default void print() {
}
}
(f)
//正确
interface A {
static int get() {
return 0;
}
}
13.16 指出下面代码中的错误
// 在接口中声明的方法默认是public的,因此在实现接口方法时,必须使用public访问修饰符进行修饰
interface A {
void m1();
}
class B implements A {
void m1() {
System.out.println("m1");
}
}
13.6章节习题
13.17 下面说法为真还是为假? 如果一个类实现了Comparable, 那么该类的对象可以调用 compareTo 方法
正确
13.18 下面哪个是正确的 String 类中的 compareTo 方法的方法头?
// compareTo比较当前对象
public int compareTo(String o)
public int compareTo(Object o)
13.19 下面代码可以被编译吗? 为什么?
// 不可以,因为对象类型不一致
Integer n1 = new Integer(3);
Object n2 = new Integer(4);
System.out.println(n1.compareTo(n2));
13.20 可以在类中定义 compareTo 方法而不实现 Comparable 接口。实现 Comparable 接口的好处是 什么?
通过实现 Comparable 接口,可以将类的对象传递给需要 Comparable 类型的方法。
13.21 下面的代码有什么错误?
// Person类没有实现Comparable接口,而sort方法是依赖Camparable的
public class Test {
public static void main(String[] args) {
Person[] persons = {new Person(3), new Person(4), new Person(1)};
java.util.Arrays.sort(persons);
}
}
class Person {
private int id;
Person(int id) {
this.id = id;
}
}
13.7章节习题
13.22 如果一个对象的类没有实现 java.lang.Cloneable, 可以调用 clone() 方法来克隆这个对象吗? Date 类实现了 Cloneable 接口吗?
在编译阶段不会报错,可以正常编译。但是在运行阶段会报异常。因此,如果在main方法想要调用a.clone(),a对象所在的类必须实现Cloneable
实现了。如果没有实现,克隆时会报异常
13.23 如果 House 类(在程序清单 13-11 中定义)没有覆盖 clone() 方法,或者如果 House 类没有实现java.lang.Cloneable, 会发生什么?
如果没有覆盖clone(),编译器会报错
如果没有实现Cloneable,会报异常
13.24 给出下面代码的输出结果
java.util.Date date = new java.util.Date();
java.util.Date date1 = date;
java.util.Date date2 = (java.util.Date)(date.clone()); System.out.println(date == date1);
System.out.println(date == date2); System.out.println(date.equals(date2));
true
false
true
13.25 给出下面代码的输出结果
ArrayList<String> list = new ArrayList<>();
list.add("New York");
ArrayList<String> list1 = list;
ArrayList<String> list2 = (ArrayList<String>)(list.clone());
list.add("Atlanta");
System.out.println(list == list1);
System.out.println(list == list2);
System.out.println("list is " + list);
System.out.println("list1 is " + list1);
System.out.println("list2.get(0) is " + list2.get(0));
System.out.println("list2.size() is " + list2.size());
true
false
list is [New York, Atlanta]
list1 is [New York, Atlanta]
list2.get(0) is New York
list2.size() is 1
13.26 下面的代码有什么错误?
// 实现接口,重写方法
public class Test {
public static void main(String[] args) {
GeometricObject x = new Circle(3);
GeometricObject y = x.clone();
System.out.println(x == y);
}
}
13.8章节习题
13.27 给出一个例子显示接口相对于抽象类的优势。
多重继承
13.28 给出抽象类和接口的定义。抽象类和接口之间的相同点和不同点是什么?
- 定义:接口是一种完全抽象的类,只包含方法的声明而没有实现;抽象类是一个可以包含抽象方法和具体方法实现的类。
- 实现方式:一个类可以有多个接口,但只能继承一个类。
- 构造函数:接口没有构造方法,而抽象类可以有构造方法。
- 成员变量:接口中只能定义常量,不能定义实例变量;抽象类可以包含实例变量。
- 接口之间的继承:接口可以继承多个接口,形成接口之间的继承关系;抽象类之间只能通过类继承实现继承关系。
13.29 真或者假?
a。接口被编译为独立的字节码文件。
真
b。接口可以有静态方法。
真
c。接口可以扩展一个或多个接口。
真
d。接口可以扩展抽象类。
假
e。抽象类可以扩展接口。
真
13.9章节习题
13.30 给出下面代码的输出。
Rational r1 = new Rational(-2, 6);
System.out.println(r1.getNumerator());
System.out.println(r1.getDenominator());
System.out.println(r1.intValue());
System.out.println(r1.doubleValue());
-1
3
0
-0.3333333333333333
13.31 下面的代码错在何处?
// Object类没有compareTo方法
Rational r1 = new Rational(-2, 6);
Object r2 = new Rational(1, 45); System.out.println(r2.compareTo(r1));
13.32 下面的代码错在何处?
//调用方和参数必须都是Rational类型
Object r1 = new Rational(-2, 6);
Rational r2 = new Rational(1, 45); System.out.println(r2.compareTo(r1));
13.33 如何使用一行代码,而不使用if语句来简化程序清单13-13中82 - 85行的代码?
public boolean equals(Object o) {
return (this.subtract((Rational)(other)))
.getNumerator() == 0;
}
public int compareTo(Rational o) {
return this.subtract(o).getNumerator() > 0 ? 1 :
(this.subtract(o).getNumerator() == 0 ? 0 : 1);
}
13.34 仔细地跟踪程序的执行,给出下面代码的输出。
Rational r1 = new Rational(1, 2);
Rational r2 = new Rational(1, -2); System.out.println(r1.add(r2));
0/4
13.10章节习题
13.35 描述类的设计原则。
13.10.1 内聚性
13.10.2 — 致性
13.10.3 封装性
13.10.4 清晰性
13.10.5 完整性
13.10.6 实例和静态
13.10.7 继承与聚合
13.10.8 接口和抽象类
编程练习题
**13.1(三角形类)
设计一个扩展自抽象类GeometricObject的新的Triangle类。绘制Triangle类和GeometricObject类的UML图并实现Triangle类。编写一个测试程序,提示用户输入三角形的三条边、一种颜色以及一个表明该三角形是否填充的布尔值。程序应该根据用户的输入, 使用这些边以及颜色和是否填充的信息,创建一个Triangle对象。程序应该显示面积、周长、 颜色以及真或者假来表明是否被填充。
Test.java文章来源:https://www.toymoban.com/news/detail-480474.html
package learning;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.print("Input 3 sides of a triangle accordingly: ");
Scanner scanner = new Scanner(System.in);
double side1 = scanner.nextDouble();
double side2 = scanner.nextDouble();
double side3 = scanner.nextDouble();
System.out.print("Input the color: ");
String color = scanner.next();
System.out.print("Input the fill status(true / false): ");
boolean filled = scanner.nextBoolean();
Triangle test1 = new Triangle(side1, side2, side3, color, filled);
System.out.print(test1.toString());
scanner.close();
}
}
GeometricObject.java
package learning;
abstract class GeometricObject {
String color;
boolean filled;
abstract double getPerimeter();
abstract double getArea();
}
Triangle.java
package learning;
//__________________________UML DIAGRAM_____________________________*
/* |
* /GeometricObject/ |
*-------------------------------------------------------------------|
* color: String |
* filled: boolean |
*-------------------------------------------------------------------|
* /getArea()/: double/ |
* /getPerimeter(): double/ |
*___________________________________________________________________|
^
^
^
//______________________________________________________________________________________________|
/* |
* Triangle |
* ----------------------------------------------------------------------------------------------|
* side1: double |
* side2: double |
* side3: double |
* ----------------------------------------------------------------------------------------------|
* Triangle() |
* Triangle(side1:double, side2:double, side3:double, color:String, filled:boolean) |
* getPerimeter(): double |
* getArea(): double |
* +toString(): String |
*_______________________________________________________________________________________________|*/
class Triangle extends GeometricObject {
double side1;
double side2;
double side3;
Triangle() {
}
Triangle(double side1, double side2, double side3, String color, boolean filled) {
this.side1 = side1;
this.side2 = side2;
this.side3 = side3;
this.color = color;
this.filled = filled;
}
@Override
double getPerimeter() {
return side1 + side2 + side3;
}
@Override
double getArea() {
return Math.pow((getPerimeter() * 0.5) * (getPerimeter() - side1) * (getPerimeter() - side2) * (getPerimeter() - side3), 0.5);
}
@Override
public String toString() {
if (filled == true) {
return "The Perimeter is " + getPerimeter() + " and the area is " + getArea() + ".\nThis triangle is " + color + " and filled.";
}
return "The Perimeter is " + getPerimeter() + " and the area is " + getArea() + ".\nThis triangle is " + color + " and not filled.";
}
}
输出结果:
Input 3 sides of a triangle accordingly: 3 4 5
Input the color: blue
Input the fill status(true / false): true
The Perimeter is 12.0 and the area is 54.99090833947008.
This triangle is blue and filled.
*13.2 (打乱ArrayList)
编写以下方法,打乱ArrayList里面保存的数字
public static void shuffle(ArrayList<Number> list)
package learning;
import java.util.ArrayList;
// 代码的大意是,把初始的list数组创建为1-10的顺序数列,再使用temp数组随机生成0-9的乱序数列,用temp的元素作为list的参数,依次传递给afterShuffle数组,所以打乱完成
// 例如,temp的第一个元素是5,那么就把原数组list中的第5号元素,挪动到新数组afterShuffle中,相当于temp数组充当了参数
public class Test {
// 用户可以设置希望打乱多大的数组,本例中设置为10
private final static int SIZE = 10;
public static void main(String[] args) {
// 把1-10按顺序加进初始list数组
ArrayList<Number> list = new ArrayList<>();
for (int i = 1; i <= SIZE; i++) {
list.add(i);
}
System.out.print("The original array is: ");
System.out.println(list.toString());
// 执行打乱方法
shuffle(list);
}
public static void shuffle(ArrayList<Number> list) {
// 创建一个暂时的数组temp,用于储存随机的参数
ArrayList<Number> temp = new ArrayList<>();
// 只要这个temp的长度没有超过用户设置的“10”,就执行循环,添加新的随机参数到数组中
while (temp.size() < SIZE) {
// 随机生成一个0 - 10的数字,如果这个数字没有被添加过,就把这个数字添加进去
// 循环结束后,temp数组由0-9的乱序数列组成
int index = (int)(Math.random() * SIZE);
if (!temp.contains(index)) {
temp.add(index);
}
}
ArrayList<Number> afterShuffle = new ArrayList<>();
/* 循环解释:
* 假设
* list = [1, 2, 3, 4, 5]
* temp = [3, 1, 4, 5, 2]
* 那么
* 把temp[0]元素3拿出来,执行list.get(3),结果是4,把结果赋值给afterShuffle的第一位元素,因此afterShuffle的第一位元素是4
* 把temp[1]元素1拿出来,执行list.get(1),结果是2,把结果赋值给afterShuffle的第一位元素,因此afterShuffle的第二位元素是2
* ......以此类推
*/
for (int i = 0; i < SIZE; i++) {
//这里需要类型转换的原因是,内圈temp.get(i)得到的数字类型是Number,而外圈list.get()方法需要一个Integer参数
afterShuffle.add(list.get((int) temp.get(i)));
}
System.out.print("The shuffled array is: ");
System.out.println(afterShuffle.toString());
}
}
输出结果:
The original array is: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
The shuffled array is: [9, 5, 2, 3, 8, 1, 4, 6, 7, 10]
*13.3 (排序ArrayList)
编写以下方法,对 ArrayList 里面保存的数字进行排序。
public static void sort(ArrayList<Number> list)
package learning;
import java.util.ArrayList;
import java.util.Arrays;
//使用冒泡排序,在方法内先把ArrayList转化成int[]
public class Test {
public static void main(String[] args) {
ArrayList<Number> list = new ArrayList<>();
list.add(5);
list.add(9);
list.add(2);
list.add(7);
list.add(3);
System.out.print("初始排序 :");
System.out.println(list.toString());
sort(list);
}
public static void sort(ArrayList<Number> list) {
int[] arr = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
arr[i] = (int)list.get(i);
}
for (int i = arr.length - 1; i > 0; i--) { //外圈决定循环次数:规律是(length-1)次
for (int j = 0; j < i; j++) { // 内圈决定交换次数,规律一个length为n的数组只需交换(n-1)次(i次,j初始值为0所以无“=”)即可实现最大值冒泡
if (arr[j] > arr[j + 1]) {
// 交换
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println("最终排序 :" + Arrays.toString(arr)); //for外只输出最终数组
}
}
输出结果:
初始排序 :[5, 9, 2, 7, 3]
最终排序 :[2, 3, 5, 7, 9]
**13.4 (显示日历)
重写程序清单6-12中的PrintCalendar类,使用Calendar和GregorianCalendar类显示一个给定月份的日历。你的程序从命令行得到月份和年份的输入,例如:
java Exercisel3_04 5 2016
也可以不输入年份来运行程序。这种情况下,年份就是当前年份。 如果不指定月份和年份来运行程序,那么就是指当前月份
package learning;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class Test {
/** Main method */
public static void main(String[] args) {
Calendar calendar = new GregorianCalendar();
if (args.length == 2) {
printMonth(Integer.parseInt(args[1]), Integer.parseInt(args[0]));
}
if (args.length == 1) {
printMonth(calendar.get(Calendar.YEAR), Integer.parseInt(args[0]));
}
if (args.length == 0) {
printMonth(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1);
}
}
/** Print the calendar for a month in a year */
public static void printMonth(int year, int month) {
// Print the headings of the calendar
printMonthTitle(year, month);
// Print the body of the calendar
printMonthBody(year, month);
}
/** Print the month title, e.g., May, 1999 */
public static void printMonthTitle(int year, int month) {
System.out.println(" " + getMonthName(month)
+ " " + year);
System.out.println("-----------------------------");
System.out.println(" Sun Mon Tue Wed Thu Fri Sat");
}
/** Get the English name for the month */
public static String getMonthName(int month) {
String monthName = "";
switch (month) {
case 1: monthName = "January"; break;
case 2: monthName = "February"; break;
case 3: monthName = "March"; break;
case 4: monthName = "April"; break;
case 5: monthName = "May"; break;
case 6: monthName = "June"; break;
case 7: monthName = "July"; break;
case 8: monthName = "August"; break;
case 9: monthName = "September"; break;
case 10: monthName = "October"; break;
case 11: monthName = "November"; break;
case 12: monthName = "December";
}
return monthName;
}
/** Print month body */
public static void printMonthBody(int year, int month) {
// Get start day of the week for the first date in the month
int startDay = getStartDay(year, month);
// Get number of days in the month
int numberOfDaysInMonth = getNumberOfDaysInMonth(year, month);
// Pad space before the first day of the month
int i = 0;
for (i = 0; i < startDay; i++)
System.out.print(" ");
for (i = 1; i <= numberOfDaysInMonth; i++) {
System.out.printf("%4d", i);
if ((i + startDay) % 7 == 0)
System.out.println();
}
System.out.println();
}
/** Get the start day of month/1/year */
public static int getStartDay(int year, int month) {
final int START_DAY_FOR_JAN_1_1800 = 3;
// Get total number of days from 1/1/1800 to month/1/year
int totalNumberOfDays = getTotalNumberOfDays(year, month);
// Return the start day for month/1/year
return (totalNumberOfDays + START_DAY_FOR_JAN_1_1800) % 7;
}
/** Get the total number of days since January 1, 1800 */
public static int getTotalNumberOfDays(int year, int month) {
int total = 0;
// Get the total days from 1800 to 1/1/year
for (int i = 1800; i < year; i++)
if (isLeapYear(i))
total = total + 366;
else
total = total + 365;
// Add days from Jan to the month prior to the calendar month
for (int i = 1; i < month; i++)
total = total + getNumberOfDaysInMonth(year, i);
return total;
}
/** Get the number of days in a month */
public static int getNumberOfDaysInMonth(int year, int month) {
if (month == 1 || month == 3 || month == 5 || month == 7 ||
month == 8 || month == 10 || month == 12)
return 31;
if (month == 4 || month == 6 || month == 9 || month == 11)
return 30;
if (month == 2) return isLeapYear(year) ? 29 : 28;
return 0; // If month is incorrect
}
/** Determine if it is a leap year */
public static boolean isLeapYear(int year) {
return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
}
}
输出结果:
// 不指定年月
java /Users/kevinwang/eclipse-workspace/test/src/learning/Test.java
May 2023
-----------------------------
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
*13.5 (将 GeometricObject 类变成可比较的)
修改 GeometricObject 类以实现 Comparable 接口,并且在 GeometricObject 类中定义一个静态的求两个 GeometricObject 对象中较大者的 max 方法。画出 UML 图并实现这个新的 GeometricObject 类。编写一个测试程序,使用 max 方法求两个圆中的较大者和两个矩形中的较大者。
Test.java
package learning;
public class Test {
public static void main(String[] args) {
GeometricObject circle1 = new Circle(1);
GeometricObject circle2 = new Circle(10);
// max方法会利用多态,将声明为GeometricObject类型的变量匹配到Circle类型的方法
GeometricObject.max(circle1, circle2);
GeometricObject rec1 = new Rectangle(3, 5);
GeometricObject rec2 = new Rectangle(10, 20);
// max方法会利用多态,将声明为GeometricObject类型的变量匹配到Rectangle类型的方法
GeometricObject.max(rec1, rec2);
}
}
GeometricObject.java
package learning;
//__________________________UML DIAGRAM_____________________________*
/* |
* /GeometricObject/ |
*-------------------------------------------------------------------|
* color: String |
* filled: boolean |
*-------------------------------------------------------------------|
* /getArea: double/ |
* +compareTo(o: GeometricObject): int |
* +___max(obj1: GeometricObject, obj2: GeometricObject): void___ |
* +toString(): String |
* __________________________________________________________________| */
abstract class GeometricObject implements Comparable<GeometricObject>{
String color;
boolean filled;
abstract double getArea();
// Comparable接口实现了compareTo方法,实现这个接口的抽象类GeometricObject需要覆写,如果当前抽象类没有覆写,继承抽象类的常规子类就必须覆写
@Override
public int compareTo(GeometricObject o) {
if (getArea() > o.getArea())
return 1;
else if (getArea() < o.getArea())
return -1;
else
return 0;
}
// max方法会先调用上面的compareTo方法,得到返回值,根据返回值,调用toString方法进行输出
public static void max(GeometricObject obj1, GeometricObject obj2) {
if (obj1.compareTo(obj2) == 1)
System.out.println(obj1.toString());
else if (obj1.compareTo(obj2) == -1)
System.out.println(obj2.toString());
else
System.out.println("Equal");
}
// 需要注意的是,如果GeometricObject类,Circle类和Rectangle类都覆写了toString,那么调用哪个toString,会根据多态,取决于变量的实际类型
// 如果Circle类和Rectangle类没有覆写toString,那么就会调用GeometricObject类的toString
// 例如,GeometricObject类,Circle类和Rectangle类都覆写了toString,那么下面的toString就不会被调用
@Override
public String toString() {
return "I will not be invoked";
}
}
Circle.java
package learning;
class Circle extends GeometricObject{
double radius;
Circle(double radius) {
this.radius = radius;
}
// GeometricObject实现了抽象方法getArea,子类必须强制调用
@Override
double getArea() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "The " + radius + " radius object is larger";
}
}
Rectangle.java
package learning;
class Rectangle extends GeometricObject{
double width;
double height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
// GeometricObject实现了抽象方法getArea,子类必须强制调用
@Override
double getArea() {
return Math.PI * width * height;
}
@Override
public String toString() {
return "The " + width + " width and " + height + " height object is larger";
}
}
输出结果:
The 10.0 radius object is larger
The 10.0 width and 20.0 height object is larger
*13.6 (ComparableCircle类)
创建名为 ComparableCircle 的类,它继承自 Circle 类,并实现 Comparable 接口。画出 UML 图并实现 compareTo 方法,使其根据面积比较两个圆。编写一个测试程序求出 ComparableCircle 对象的两个实例中的较大者。
Test.java
package learning;
//___________________________UML DIAGRAM____________________________|
/* |
* Circle |
*-------------------------------------------------------------------|
* radius: double |
*-------------------------------------------------------------------|
* Circle() |
* Circle(radius: double) |
* getArea(): double |
* __________________________________________________________________| */
/* ^
^
^
//_____________________UML DIAGRAM_________________________________|
/* |
* ComparableCircle |
*------------------------------------------------------------------| //_______________________________________________|
* radius: double | * <<interface>> *
* ComparableCircle() |<<<<<<<<<<<<<<<<<<<<* Comparable |
* ComparableCircle(radius: double) | * +compareTo(circle: ComparableCircle): int |
* getArea(): double | //_______________________________________________|
* +compareTo(o: comparableCircle): int |
*__________________________________________________________________| */
public class Test {
public static void main(String[] args) {
ComparableCircle test1 = new ComparableCircle(5);
ComparableCircle test2 = new ComparableCircle(10);
System.out.print(test1.compareTo(test2));
}
}
Circle.java
package learning;
class Circle {
double radius;
Circle() {
radius = 1;
}
Circle(double radius) {
this.radius = radius;
}
double getArea() {
return Math.PI * radius * radius;
}
}
ComparableCircle.java
package learning;
class ComparableCircle extends Circle implements Comparable<ComparableCircle> {
double radius;
ComparableCircle() {
super();
}
ComparableCircle(double radius) {
this.radius = radius;
}
@Override
double getArea() {
return Math.PI * radius * radius;
}
@Override
public int compareTo(ComparableCircle o) {
if (getArea() > o.getArea())
return 1;
else if (getArea() < o.getArea())
return -1;
else
return 0;
}
}
输出结果:
-1
*13.7 (可着色接口Colorable)
设计一个名为 Colorable 的接口,其中有名为 howToColor() 的 void 方法。可着色对象的每个类必须实现 Colorable 接口。设计一个名为 Square 的类,继承自 CeometricObject 类并实现 Colorable 接口。实现 howToColor 方法,显示一个消息 Color all four sides(给所有的四条边着色)。
画出包含 Colorable、Square 和 CeometricObject 的 UML 图。编写一个测试程序,创建有五个 GeometricObject 对象的数组。对于数组中的每个对象而言,如果对象是可着色的, 那就调用 howToColor 方法。
Test.java
package learning;
//___________________________UML DIAGRAM____________________________|
/* |
* /GeometricObject/ |
*-------------------------------------------------------------------|
* color: String |
* filled: boolean |
*-------------------------------------------------------------------|
* GeometricObject() |
* __________________________________________________________________| */
/* ^
^
^
//_____________________UML DIAGRAM_________________________________|
/* |
* Square |
*------------------------------------------------------------------|
* sides: double | //_______________________________________________|
*------------------------------------------------------------------| * <<interface>> *
* Square() |<<<<<<<<<<<<<<<<<<<<* Colorable |
* Squaree(sides: double) | * howToColor(): void |
* +howToColor(): void | //_______________________________________________|
*__________________________________________________________________| */
public class Test {
public static void main(String[] args) {
Square square = new Square(5);
square.howToColor();
}
}
GeometricObject.java
package learning;
abstract class GeometricObject {
String color;
boolean filled;
GeometricObject() {
}
}
Square.java
package learning;
class Square extends GeometricObject implements Colorable {
double sides;
Square() {
}
Square(double sides){
this.sides = sides;
}
@Override
public void howToColor() {
System.out.println("Color all four sides");
}
}
Colorable.java
package learning;
interface Colorable {
void howToColor();
}
*13.8 (修改MyStack类)
重写程序清单11-10中的MyStack类, 执行list域的深度复制
Test.Java
package learning;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
MyStack start = new MyStack();
start.push(new String("One"));
start.push(new String("Two"));
start.push(new String("Three"));
// 返回的stackCloned返回声明类型是Object,但是实际类型是MyStack,所以可以进行转换
MyStack cloned = (MyStack) start.clone();
// 通过==判断这两个对象其实是不共享内存的,后续的追加数据也是独立的
System.out.println(cloned == start);
start.push(new String("Four"));
System.out.println("Cloned " + cloned.toString());
System.out.println("Original " + start.toString());
}
}
MyStack.java
package learning;
import java.util.ArrayList;
public class MyStack implements Cloneable {
private ArrayList<Object> list = new ArrayList<Object>();
public int getSize() {
return list.size();
}
public Object peek() {
return list.get(getSize() - 1);
}
public Object pop() {
Object obj = list.get(getSize() - 1);
list.remove(getSize() - 1);
return obj;
}
public void push(Object obj) {
list.add(obj);
}
public int search(Object obj) {
return list.indexOf(obj);
}
@Override
public Object clone() throws CloneNotSupportedException {
// 深拷贝的逻辑是,创建一个新的内存空间,储存新对象,新旧对象互不干涉,所以就需要新建一个实例变量,用来储存新的对象
// 创建一个新的实例变量stackCloned,先对start进行浅拷贝,将浅拷贝的结果储存进stackCloned
// 其中,super.clone()相当于start.clone(),调用Object类的clone()方法进行克隆,start的实际类型是MyStack,所以转型可以成功
MyStack stackCloned = (MyStack)super.clone();
// 调用deepClone()方法,将深拷贝储存到stackCloned中,在这里我们需要深拷贝的是list字段,所以deepClone()方法针对list字段进行深拷贝
stackCloned.list = deepClone();
// 返回深拷贝后的stackCloned
// 由于方法返回值类型是Object,所以可以返回任意子类类型
// 但是需要注意的是,返回的stackCloned还是一个Object类型(实际类型是MyStack),后续如果需要,就要类型转换
return stackCloned;
}
// 由于stackCloned.list = deepClone()语句中,我们是想要深拷贝list,而list的类型是ArrayList<Object>,所以下面方法的返回值也应该是ArrayList<Object>
// 相当于在stackCloned对象中,储存了一个ArrayList<Object>字段
ArrayList<Object> deepClone() {
// 方法的逻辑是,新建一个ArrayList<Object>数组,一个一个元素复制对象的list字段,最后返回这个新建的数组
ArrayList<Object> temp = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
temp.add(list.get(i));
return temp;
}
@Override
public String toString() {
return "Stack: " + list.toString();
}
}
输出结果:
false
Cloned Stack: [One, Two, Three]
Original Stack: [One, Two, Three, Four]
*13.9 (将 Circle 类改成可比较的)
改写程序清单13-2中的 Circle 类,它继承自 GeometricObject 类并实现 Comparable 接口。覆盖 Object 类中的 equals 方法。当两个 Circle 对象半径相等时,则这两个 Circle 对象是相同的。画出包括 Circle 、GeometricObject 和 Comparable 的 UML图。
Test.java
package learning;
//___________________________UML DIAGRAM____________________________|
/* |
* /GeometricObject/ |
*-------------------------------------------------------------------|
* color: String |
* filled: boolean |
*-------------------------------------------------------------------|
* GeometricObject() |
* __________________________________________________________________| */
/* ^
^
^
//_____________________UML DIAGRAM_________________________________|
/* |
* Circle |
*------------------------------------------------------------------|
* -radius: double | //_______________________________________________|
*------------------------------------------------------------------| * <<interface>> *
* +Circle() |<<<<<<<<<<<<<<<<<<<<* Comparable |
* +Circle(radius: double) | * +compareTo(other T): int |
* +getArea(): double | //_______________________________________________|
* +compareTo(c: Circle): int |
* +equals(ob: Object): boolean |
*__________________________________________________________________| */
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Circle c1 = new Circle(5);
Circle c2 = new Circle(5);
System.out.println(c1.equals(c2));
System.out.println(c1.compareTo(c2));
}
}
Circle.java
package learning;
// 通常情况下,Comparable接口的范型参数应该是当前的类名,以指定要比较的对象是当前类的实例,但是其实类型可以是当前类的任意子类或父类
// Comparable接口的范型参数应该和compareTo方法的范型参数保持一致
public class Circle extends GeometricObject implements Comparable<Circle> {
private double radius;
public Circle() {
}
public Circle(double radius) {
this.radius = radius;
}
public double getArea() {
return radius * radius * Math.PI;
}
@Override
public int compareTo(Circle c) {
if (getArea() > c.getArea())
return 1;
else if (getArea() < c.getArea())
return -1;
else
return 0;
}
@Override
public boolean equals(Object ob) {
Circle circle = (Circle) ob;
return this.radius == circle.radius;
}
}
GeometricObject.java
package learning;
abstract class GeometricObject {
String color;
boolean filled;
GeometricObject() {
}
}
输出结果:
true
0
*13.10(将Rectangle类变成可比较的)
改写程序清单13-3的Rectangle类,它继承自GeometricObject类并实现Comparable接口。覆盖Object类中的equals方法。当两个Rectangle对象面积相同时,则这两个对象是相同的。画出包括Rectangle,GeometricObject和Comparable的UML图
Test.java
package learning;
//___________________________UML DIAGRAM____________________________|
/* |
* /GeometricObject/ |
*-------------------------------------------------------------------|
* color: String |
* filled: boolean |
*-------------------------------------------------------------------|
* GeometricObject() |
* __________________________________________________________________| */
/* ^
^
^
//_____________________UML DIAGRAM_________________________________|
/* |
* Rectangle |
*------------------------------------------------------------------|
* -width: double -height: double | //_______________________________________________|
*------------------------------------------------------------------| * <<interface>> *
* +Rectangle() |<<<<<<<<<<<<<<<<<<<<* Comparable |
* +Rectangle(height: double, width: double) | * +compareTo(other T): int |
* +getArea(): double | //_______________________________________________|
* +compareTo(obj: Rectangle): int |
* +equals(ob: Object): boolean |
*__________________________________________________________________| */
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Rectangle c1 = new Rectangle(5, 10);
Rectangle c2 = new Rectangle(5, 10);
System.out.println(c1.equals(c2));
System.out.println(c1.compareTo(c2));
}
}
GeometricObject.java
package learning;
abstract class GeometricObject {
String color;
boolean filled;
GeometricObject() {
}
}
Rectangle.java
package learning;
public class Rectangle extends GeometricObject implements Comparable<Rectangle> {
private double width;
private double height;
public Rectangle() {
}
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double getArea() {
return width * height;
}
@Override
public int compareTo(Rectangle obj) {
if (this.getArea() > obj.getArea()) {
return 1;
} else if (this.getArea() < obj.getArea()) {
return -1;
} else
return 0;
}
@Override
public boolean equals(Object ob) {
Rectangle r = (Rectangle) ob;
double thisArea = this.getArea();
double rArea = r.getArea();
// 等号的左边必须是变量,因此前面新声明了一个变量表示面积
return thisArea == rArea;
}
}
*13.11 (八边形类Octagon)
编写一个名为Octagon的类,它继承自GeometricObject类并实现Comparable和Cloneable接口。假设八边形八条边的边长都相等。它的面积可以使用下面的公式计算:
面积 = ( 2 + 4 / √ 2 ) × 边长 × 边长 面积=(2+4/√2)×边长×边长 面积=(2+4/√2)×边长×边长
画出包括Octagon、GeometricObject、Comparable和Cloneable的UML图。编写一个测试程序,创建一个边长值为5的Octagon对象,然后显示它的面积和周长。使用clone方法创建一个新对象,并使用compareTo方法比较这两个对象。
Test.java
package learning;
//___________________________UML DIAGRAM____________________________|
/* |
* /GeometricObject/ |
*------------------------------------------------------------------|
* color: String |
* filled: boolean |
*------------------------------------------------------------------|
* GeometricObject() |
* /#getPerimeter(): double/ |
* /#getArea(): double/ |
* _________________________________________________________________| */
/* ^
^
^
^
/*_________________UML Diagram__________________*
* *
* Octagon *
*-----------------------------------------------*
* *
* side: double *
*-----------------------------------------------*
_____________________________________ * Octagon() * _____________________________________
* <<interface>> * * Octagon(side:double) * * <<interface>> *
* java.lang.Cloneable * * * * java.lang.Comparable<Octagon> *
*___________________________________* <<<<<<<<< * * >>>>>>>>> *____________________________________*
* #clone():Object * * #getArea(): double * * +compareTo(obj: T):int *
*___________________________________* * #getPerimeter(): double * *____________________________________*
* #clone(): Object *
* +compareTo(o: Octagon): int *
* ______________________________________________* */
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Octagon o1 = new Octagon(5);
System.out.println(o1.getPerimeter());
System.out.println(o1.getArea());
Octagon o2 = (Octagon)o1.clone();
System.out.print(o1.compareTo(o2));
}
}
GeometricObject.java
package learning;
abstract class GeometricObject{
String color;
boolean filled;
GeometricObject() {
}
protected abstract double getPerimeter();
protected abstract double getArea();
}
Octagon.java
package learning;
class Octagon extends GeometricObject implements Cloneable, Comparable<Octagon>{
private double side;
Octagon() {
this(1.0);
}
Octagon(double side) {
this.side = side;
}
@Override
protected double getPerimeter() {
return side * 8;
}
@Override
protected double getArea() {
return (2 + 4 / Math.pow(2, 0.5) * side * side);
}
@Override
public int compareTo(Octagon o) {
if (getArea() > o.getArea())
return 1;
else if (getArea() < o.getArea())
return -1;
else
return 0;
}
@Override
// 在覆写中,子类必须要选择可见性更高的修饰符,部分关键字不需要覆写(如abstract,native),父类方法声明的异常也不需要覆写
protected Object clone() throws CloneNotSupportedException {
// Object类中的clone方法是经过关键字native由虚拟机完成的,无法在Java源代码直接访问到
return super.clone();
}
}
输出结果:
40.0
72.71067811865474
0
*13.12(求几何对象的面积之和)
编写一个方法,求数组中所有几何对象的面积之和。方法签名如下:
public static double sumArea(Geometricobject[] a)
编写测试程序,创建四个对象(两个圆和两个矩形)的数组,然后使用sumArea方法求它们的总面积。
Test.java
package learning;
//___________________________UML DIAGRAM____________________________|
/* |
* /GeometricObject/ |
*------------------------------------------------------------------|
* color: String |
* filled: boolean |
*------------------------------------------------------------------|
* GeometricObject() |
* /#getArea(): double/ |
* _________________________________________________________________|
^
^
^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^ ^
^ ^
/*_________________UML Diagram___________________* /*_________________UML Diagram____________________*
* * * *
* Rectangle * * Circle *
*-----------------------------------------------* *------------------------------------------------*
* -width: double * * -radius: double *
* -height: double * *------------------------------------------------*
*-----------------------------------------------* * Circle() *
* Rectangle() * * Circle(radius: double) *
* Rectangle(width: double, height: double) * * #getArea(): double *
* #getArea(): double * * *
* ______________________________________________* * _______________________________________________* */
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
GeometricObject r1 = new Rectangle(3, 4);
GeometricObject r2 = new Rectangle(4, 5);
GeometricObject c1 = new Circle(3);
GeometricObject c2 = new Circle(4);
GeometricObject[] go = new GeometricObject[4];
go[0] = r1;
go[1] = r2;
go[2] = c1;
go[3] = c2;
System.out.print(sumArea(go));
}
public static double sumArea(GeometricObject[] a) {
double sum = 0;
for (int i = 0; i < a.length; i++) {
double area = a[i].getArea();
sum = sum + area;
}
return sum;
}
}
GeometricObject.java
package learning;
abstract class GeometricObject{
String color;
boolean filled;
GeometricObject() {
}
protected abstract double getArea();
}
Circle.java
package learning;
class Circle extends GeometricObject {
private double radius;
Circle() {
this(1);
}
Circle(double radius) {
this.radius = radius;
}
@Override
protected double getArea() {
return Math.PI * radius * radius;
}
}
Rectangle.java
package learning;
class Rectangle extends GeometricObject {
private double width;
private double height;
Rectangle() {
this(1, 1);
}
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
protected double getArea() {
return width * height;
}
}
输出结果:
110.53981633974483
*13.13 (使得 Course 类可复制)
重写程序淸单10-6中的 Course 类,增加一个 clone 方法,执行students 域上的深度复制。
Test.java
package learning;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Course c1 = new Course("English");
c1.addStudent("A");
c1.addStudent("B");
c1.addStudent("C");
c1.addStudent("D");
Course c2 = (Course)c1.clone();
System.out.println("c1 == c2 is " + (c1.getStudents() == c2.getStudents()));
}
}
Course.java
package learning;
public class Course implements Cloneable {
private String courseName;
private String[] students = new String[4];
private int numberOfStudents;
public Course(String courseName) {
this.courseName = courseName;
}
public void addStudent(String student) {
students[numberOfStudents] = student;
numberOfStudents++;
}
public String[] getStudents() {
return students;
}
public int getNumberOfStudents() {
return numberOfStudents;
}
public String getCourseName() {
return courseName;
}
@Override
protected Object clone() throws CloneNotSupportedException{
Course studentCloned = (Course)super.clone();
studentCloned.students = deepCloned();
return studentCloned;
}
protected String[] deepCloned() {
String[] temp = new String[4];
for (int i = 0; i < students.length; i++) {
temp[i] = students[i];
}
return temp;
}
}
输出结果:
c1 == c2 is false
*13.14(演示封装的好处)
使用新的分子分母的内部表达改写13.13节中的Rational类。创建有两个整数的数组,如下所示:
private long[] r = new 1ong[2]:
使用r[0]表示分子,使用r[1]表示分母。在Rational类中的方法签名没有改变,因此,无须重新编译,前一个Rational类的客户端应用程序可以继续使用这个新的Rational类。
// 替换字段处即可
private long[] r = new long[2];
private long numerator = r[0];
private long denominator = r[1];
13.15(在 Rational 类中使用 Biglnteger)
使用 Biglnteger 表示分子和分母,重新设计和实现
package learning;
import java.math.BigInteger;
public class Rational extends Number implements Comparable<Rational> {
// Data fields for numerator and denominator
private BigInteger numerator = BigInteger.ZERO;
private BigInteger denominator = BigInteger.ONE;
public Rational() {
this(0, 1);
}
public Rational(long numerator) {
this(numerator, 1);
}
public Rational(long numerator, long denominator) {
BigInteger gcd = gcd(numerator, denominator);
this.numerator = BigInteger.valueOf(((denominator > 0) ? 1 : -1) * numerator).divide(gcd);
this.denominator = BigInteger.valueOf(Math.abs(denominator)).divide(gcd);
}
private static BigInteger gcd(long n, long d) {
BigInteger b1 = BigInteger.valueOf(n);
BigInteger b2 = BigInteger.valueOf(d);
return b1.gcd(b2);
}
public long getNumerator() {
return numerator.longValue();
}
public long getDenominator() {
return denominator.longValue();
}
public Rational add(Rational secondRational) {
long n = numerator.longValue() * secondRational.getDenominator() +
denominator.longValue() * secondRational.getNumerator();
long d = denominator.longValue() * secondRational.getDenominator();
return new Rational(n, d);
}
public Rational subtract(Rational secondRational) {
long n = numerator.longValue() * secondRational.getDenominator()
- denominator.longValue() * secondRational.getNumerator();
long d = denominator.longValue() * secondRational.getDenominator();
return new Rational(n, d);
}
public Rational multiply(Rational secondRational) {
long n = numerator.longValue() * secondRational.getNumerator();
long d = denominator.longValue() * secondRational.getDenominator();
return new Rational(n, d);
}
public Rational divide(Rational secondRational) {
long n = numerator.longValue() * secondRational.getDenominator();
long d = denominator.longValue() * secondRational.numerator.longValue();
return new Rational(n, d);
}
@Override
public String toString() {
if (denominator.intValue() == 1)
return numerator + "";
else
return numerator + "/" + denominator;
}
@Override
public boolean equals(Object other) {
if ((this.subtract((Rational) (other))).getNumerator() == 0)
return true;
else
return false;
}
@Override
public int intValue() {
return (int) doubleValue();
}
@Override
public float floatValue() {
return (float) doubleValue();
}
@Override
public double doubleValue() {
return numerator.longValue() * 1.0 / denominator.longValue();
}
@Override
public long longValue() {
return (long) doubleValue();
}
@Override
public int compareTo(Rational o) {
if (this.subtract(o).getNumerator() > 0)
return 1;
else if (this.subtract(o).getNumerator() < 0)
return -1;
else
return 0;
}
}
*13.16(创建一个有理数的计算器)
编写一个类似于程序清单7-9的程序。这里不使用整数,而是使用有理数,如图13-10a所示。需要使用在10.10.3节中介绍的String类中的split方法来获取分子字符串和分母字符串,并使用Integer.parseInt方法将字符串转换为整数
Test.java
package learning;
public class Test {
public static void main(String[] args) {
String num1 = "1/3";
String opera = "*";
String num2 = "1/3";
String[] sepNum1 = new String[2];
String[] sepNum2 = new String[2];
sepNum1 = num1.split("/");
sepNum2 = num2.split("/");
long numerator1 = Integer.parseInt(sepNum1[0]);
long denominator1 = Integer.parseInt(sepNum1[1]);
long numerator2 = Integer.parseInt(sepNum2[0]);
long denominator2 = Integer.parseInt(sepNum2[1]);
switch(opera) {
case "+":
System.out.println(new Rational(numerator1, denominator1).add(new Rational(numerator2, denominator2)));
break;
case "-":
System.out.println(new Rational(numerator1, denominator1).subtract(new Rational(numerator2, denominator2)));
break;
case "*":
System.out.println(new Rational(numerator1, denominator1).multiply(new Rational(numerator2, denominator2)));
break;
case "/":
System.out.println(new Rational(numerator1, denominator1).divide(new Rational(numerator2, denominator2)));
}
}
}
Rational.java
package learning;
public class Rational extends Number implements Comparable<Rational> {
// Data fields for numerator and denominator
private long numerator = 0;
private long denominator = 1;
/** Construct a rational with default properties */
public Rational() {
this(0, 1);
}
/** Construct a rational with specified numerator and denominator */
public Rational(long numerator, long denominator) {
long gcd = gcd(numerator, denominator);
this.numerator = (denominator > 0 ? 1 : -1) * numerator / gcd;
this.denominator = Math.abs(denominator) / gcd;
}
/** Find GCD of two numbers */
private static long gcd(long n, long d) {
long n1 = Math.abs(n);
long n2 = Math.abs(d);
int gcd = 1;
for (int k = 1; k <= n1 && k <= n2; k++) {
if (n1 % k == 0 && n2 % k == 0)
gcd = k;
}
return gcd;
}
/** Return numerator */
public long getNumerator() {
return numerator;
}
/** Return denominator */
public long getDenominator() {
return denominator;
}
/** Add a rational number to this rational */
public Rational add(Rational secondRational) {
long n = numerator * secondRational.getDenominator() +
denominator * secondRational.getNumerator();
long d = denominator * secondRational.getDenominator();
return new Rational(n, d);
}
/** Subtract a rational number from this rational */
public Rational subtract(Rational secondRational) {
long n = numerator * secondRational.getDenominator()
- denominator * secondRational.getNumerator();
long d = denominator * secondRational.getDenominator();
return new Rational(n, d);
}
/** Multiply a rational number to this rational */
public Rational multiply(Rational secondRational) {
long n = numerator * secondRational.getNumerator();
long d = denominator * secondRational.getDenominator();
return new Rational(n, d);
}
/** Divide a rational number from this rational */
public Rational divide(Rational secondRational) {
long n = numerator * secondRational.getDenominator();
long d = denominator * secondRational.numerator;
return new Rational(n, d);
}
@Override
public String toString() {
if (denominator == 1)
return numerator + "";
else
return numerator + "/" + denominator;
}
@Override // Override the equals method in the Object class
public boolean equals(Object other) {
if ((this.subtract((Rational)(other))).getNumerator() == 0)
return true;
else
return false;
}
@Override // Implement the abstract intValue method in Number
public int intValue() {
return (int)doubleValue();
}
@Override // Implement the abstract floatValue method in Number
public float floatValue() {
return (float)doubleValue();
}
@Override // Implement the doubleValue method in Number
public double doubleValue() {
return numerator * 1.0 / denominator;
}
@Override // Implement the abstract longValue method in Number
public long longValue() {
return (long)doubleValue();
}
@Override // Implement the compareTo method in Comparable
public int compareTo(Rational o) {
if (this.subtract(o).getNumerator() > 0)
return 1;
else if (this.subtract(o).getNumerator() < 0)
return -1;
else
return 0;
}
}
输出结果:
1/9
*13.17(數学: Complex类)
一个复数是一个形式为a+bi加的数,这里的a和b都是实数,i是 − 1 \sqrt{-1} −1的平方根。数字a和b分别称为复数的实部和虚部。可以使用下面的公式完成复数的加、减、乘、除:
a + bi + c + di = (a + c) + (b + d)i
a + bi - (c + di) = (a - c) + (b - d)i
(a + bi)*(c + di) = (ac - bd) + (bc + ad)i
(a + bi)/(c + di) = (ac + bd)/(c2 + d2) + (bc - ad)i/(c^2 + d^2)
还可以使用下面的公式得到复数的绝对值:
∣ a + b i ∣ = a 2 + b 2 |a + bi| = \sqrt{a^2 + b^2} ∣a+bi∣=a2+b2
(复数可以解释为一个平面上的点,将(a,b)值作为该点的坐标。复数的绝对值是该点到原点的距离,如图13-10b所示。)
设计一个名为Complex的复数来表示复数以及完成复数运算的add、substract、 multiply、divide和abs方法,并且覆盖toString方法以返回一个表示复数的字符串。 方法toString返回字符串a+bi。如果b是0,那么它只返回a。Complex类应该也实现Cloneable接口。
提供三个构造方法Complex(a,b)、Complex(a)和Complex()。Complex()创建数字0的Complex对象,而Complex(a)创建一个b为0的Complex对象。还提供getRealPart() 和getImaginaryPart()方法以分别返回复数的实部和虚部。
编写一个测试程序,提示用户输人两个复数,然后显示它们做加、减、乘、除之后的结果。下面是一个运行示例:
Test.java
package learning;
public class Test {
public static void main(String[] args) {
Complex c1 = new Complex(3.5, 5.5);
Complex c2 = new Complex(-3.5, 1);
System.out.println(c1.add(c2));
System.out.println(c1.sub(c2));
System.out.println(c1.mul(c2));
System.out.println(c1.div(c2));
System.out.println(c1.abs());
}
}
Complex.java
package learning;
class Complex {
public double a;
public double b;
//会依次调用之后的两个构造方法,注意如果没有传入值,默认0.0
public Complex() {
this(0);
}
public Complex(double a) {
this(a, 0);
}
public Complex(double a, double b) {
this.a = a;
this.b = b;
}
public Complex add(Complex c2) {
double c = c2.a;
double d = c2.b;
double complex1 = a + c;
double complex2 = b + d;
return new Complex(complex1, complex2);
}
public Complex sub(Complex c2) {
double c = c2.a;
double d = c2.b;
double complex1 = a - c;
double complex2 = b - d;
return new Complex(complex1, complex2);
}
public Complex mul(Complex c2) {
double c = c2.a;
double d = c2.b;
double complex1 = a * c - b * d;
double complex2 = b * c + a * d;
return new Complex(complex1, complex2);
}
public Complex div(Complex c2) {
double c = c2.a;
double d = c2.b;
double complex1 = (a * c + b * d) / (c * c + d * d);
double complex2 = (b * c - a * d) / (c * c + d * d);
return new Complex(complex1, complex2);
}
public double abs() {
return Math.pow(a * a + b * b, 0.5);
}
public double getRealPart() {
return a;
}
public double getImaginaryPart() {
return b;
}
@Override
// 输出对象时,会自动调用toString
public String toString() {
if (b == 0)
return a + "";
else
return a + " + " + b + "i";
}
}
输出结果:
0.0 + 6.5i
7.0 + 4.5i
-17.75 + -15.75i
-0.5094339622641509 + -1.7169811320754718i
6.519202405202649
13.18(使用 Rational 类)
编写程序,使用 Rational 类计算下面的求和数列:
1 2 + 2 3 + 3 4 + ⋅ ⋅ ⋅ + 99 100 \frac{1}{2} + \frac{2}{3} + \frac{3}{4} + ··· + \frac{99}{100} 21+32+43+⋅⋅⋅+10099
你将会发现输出是不正确的 ,因为整数溢出(太大了)。为了解决这个问题 ,参见编程练习題13.15。
直接复制13.15的Rational代码,下面只给出Test测试类
Test.java
package learning;
public class Test {
public static void main(String[] args) {
Rational resultRational = new Rational();
long i = 2;
while (i <= 100) {
Rational rational = new Rational(i - 1, i);
System.out.print(rational.getNumerator() + "/" + rational.getDenominator());
if (i == 100) System.out.print(" = ");
else if (i % 10 == 0) System.out.println(" + ");
else System.out.print(" + ");
resultRational = resultRational.add(rational);
i++;
}
System.out.println(resultRational.getNumerator() + " / " + resultRational.getDenominator());
}
}
输出结果:
1/2 + 2/3 + 3/4 + ... + 97/98 + 98/99 + 99/100 = 1349247664274259951 / 1822963237492290880
13.19 (将十进制數转化为分教)
编写一个程序,提示用户输入一个十进制数,然后以分数的形式显示该数字。提示 :将十进制数以字符串的形式读入 ,从字符串中抽取其整数部分和小数部分 ,然后运用编程练习题 13.15 中使用 Biglnteger 实现的 Rational 类,来获得该十进制数的有理数。这里是一些运行示例:
最后3题比较考察数学功底,编程逻辑不难,但是数学难哈哈哈。。。
直接复制13.15的Rational代码,下面只给出Test测试类
Test.java
package learning;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Enter a decimal number: ");
String decVal = in.next();
try {
System.out.println("The fraction number is " + decimalToFraction(decVal));
} catch (Exception e) {
System.out.println(e.getMessage());
}
in.close();
}
private static String decimalToFraction(String val) throws Exception {
boolean isNegative = val.startsWith("-");
String[] decimalNumberParts = val.split("\\.");
if (decimalNumberParts.length < 2) {
throw new Exception("You must enter a decimal number like: 123.12");
}
if (val.startsWith("-")) {
isNegative = true;
}
Rational leftSideOfDecimal = new Rational(Long.parseLong(decimalNumberParts[0]));
String denominatorRightSide = "1";
for (int i = 0; i < decimalNumberParts[1].length(); i++) {
denominatorRightSide += "0";
}
Rational rightSideOfDecimal = new Rational(Long.parseLong(decimalNumberParts[1]), Long.parseLong(denominatorRightSide));
Rational result = leftSideOfDecimal.add(rightSideOfDecimal);
return (isNegative ? "-" : "") + result.toString();
}
}
输出结果:
Enter a decimal number: 3.25
The fraction number is 13/4
13.20 (數学:求解二元方程)
重写编程练习题3.1,如果行列式小于0,则使用编程练习题13.17中的 Complex 类来得到虚根。这里是一些运行示例:
最后3题比较考察数学功底,编程逻辑不难,但是数学难哈哈哈。。。
直接复制13.17的Complex代码,下面只给出Test测试类
Test.java
package learning;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
try (Scanner input = new Scanner(System.in)) {
System.out.print("Enter a, b, c: ");
double a = input.nextDouble();
double b = input.nextDouble();
double c = input.nextDouble();
double discriminant = b * b - 4 * a * c;
if (discriminant > 0) {
double r1 = ((-1 * b) + Math.sqrt(discriminant)) / (2 * a);
double r2 = ((-1 * b) - Math.sqrt(discriminant)) / (2 * a);
System.out.printf("Two real roots: %2.5f and %2.5f", r1, r2);
} else if (discriminant == 0) {
double r = ((-1 * b) + Math.sqrt(discriminant)) / (2 * a);
System.out.print("One real root: " + r);
} else {
Complex complexR1 = new Complex(-b / (2 * a), Math.sqrt(2 * a));
Complex complexR2 = new Complex(-b / (2 * a), -Math.sqrt(2 * a));
System.out.println("The roots are " + complexR1 + " and " + complexR2);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
Enter a, b, c: 1 2 3
The roots are -1.0 + 1.4142135623730951i and -1.0 + -1.4142135623730951i
13.21(代数:顶点式方程)
抛物线方程可以表达为标准形式(y=ax2+bx+c)或者顶点式(y=a(x-h)2+k)。编写一个程序,提示用户输人标准形式下的整数a、b和c值,显示顶点式下面的h和k值。这里是一些运行示例:
最后3题比较考察数学功底,编程逻辑不难,但是数学难哈哈哈。。。
直接复制13.15的Rational代码,下面只给出Test测试类
Test.java
package learning;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Enter a, b, c (as integers): ");
int a = in.nextInt();
int b = in.nextInt();
int c = in.nextInt();
Rational aRational = new Rational(a);
Rational bRational = new Rational(b);
Rational cRational = new Rational(c);
Rational h = new Rational(bRational.multiply(new Rational(-1)).longValue(),
aRational.multiply(new Rational(2)).longValue());
Rational k = aRational.multiply(h.multiply(h)).add(bRational.multiply(h)).add(cRational);
System.out.println("h is " + h + ", k is " + k);
}
}
输出结果:文章来源地址https://www.toymoban.com/news/detail-480474.html
Enter a, b, c (as integers): 1 3 1
h is -3/2, k is -5/4
到了这里,关于《Java黑皮书基础篇第10版》 第13章【习题】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!