目录
1.代码呈现
1.1编写toString、equals方法
1.2测试代码
1.3有理数类的代码
2.论述题
3.有理类设计
1.代码呈现
1.1编写toString、equals方法
(1)toString方法
@Override public String toString(){ if(this.v2==0){ return "Undefined"; } return this.v1 +"/"+ this.v2; }
(2)equals方法
@Override public boolean equals(Object obj) { // 首先检查引用是否相同 if (this == obj) { return true; } // 检查是否为同一个类的对象 if (!(obj instanceof Rational)) { return false; } // 强制转换为 Rational 类型 Rational other = (Rational) obj; // 检查分母是否为零,如果其中一个对象的分母为零,则它们不能相等 if( v2 == 0 || other.v2 == 0) { return false; } // 计算两个有理数的交叉乘积并比较 return (v1 * other.v2) == (other.v1 * v2); }
1.2测试代码
(1)在与有理数类不同包的其他类中调用有理数类
(2)测试代码与测试结果
package test01; import Rational.Rational; public class Rationaltest { public static void main(String[] args) { // 创建两个有理数对象 Rational r1 = new Rational(1, 2); // 1/2 Rational r2 = new Rational(3, 4); // 3/4 // 创建第三个对象用于存放结果 Rational result = new Rational(0, 1);//分母不能为0 // 测试加法 System.out.println("Adding 1/2 and 3/4:"); r1.Add(r1, r2, result); System.out.println("Result= " + result.getV1() + "/" + result.getV2()); // 测试乘法 System.out.println("Multiplying 1/2 and 3/4:"); r1.Multiply(r1, r2, result); System.out.println("Result= " + result.getV1() + "/" + result.getV2()); //测试getRational System.out.println("getRational:"); int e=0; System.out.println("e="+r1.getRational(r1,2,e)); //toString System.out.println("r1 的输出结果为: "); System.out.println("r1 = "+r1.toString()); //equals System.out.println("r1和r2的比较结果为:"); System.out.println(r1.equals(r2)); } }
1.3有理数类的代码
package Rational;
public class Rational{
//属性
private int v1;
private int v2;
//构造函数
public Rational(int v1,int v2){
this.v1=v1;
this.v2=v2;
}
//setter与getter
public int getV1() {
return v1;
}
public void setV1(int v1) {
this.v1 = v1;
}
public int getV2() {
return v2;
}
public void setV2(int v2) {
this.v2 = v2;
}
//方法
//add方法
public void Add(Rational T1,Rational T2,Rational T3){
int t;
T3.v2 = T1.v2 * T2.v2;
T3.v1 = T1.v1 * T2.v2 + T2.v1 * T1.v2;
t = Gcd(T3.v2,T3.v1);
T3.v2 /= t;
T3.v1 /= t;
}
//Multiply方法
public void Multiply(Rational T1,Rational T2,Rational T3){
int t;
T3.v2 = T1.v2 * T2.v2;
T3.v1 = T1.v1 * T2.v1;
t = Gcd(T3.v2, T3.v1);
T3.v2 /= t;
T3.v1 /= t;
}
private static int Gcd(int m,int n){
int t;
while(m % n != 0)
{
t = n;
n = m%n;
m = t;
}
return n;
}
public int getRational(Rational T,int i,int e){
if(i==1){
e=T.v1;
}
else{
e=T.v2;
}
return e;
}
@Override
public String toString(){
if(this.v2==0){
return "Undefined";
}
return this.v1 +"/"+ this.v2;
}
@Override
public boolean equals(Object obj) {
// 首先检查引用是否相同
if (this == obj) {
return true;
}
// 检查是否为同一个类的对象
if (!(obj instanceof Rational)) {
return false;
}
// 强制转换为 Rational 类型
Rational other = (Rational) obj;
// 检查分母是否为零,如果其中一个对象的分母为零,则它们不能相等
if( v2 == 0 || other.v2 == 0) {
return false;
}
// 计算两个有理数的交叉乘积并比较
return (v1 * other.v2) == (other.v1 * v2);
}
}
2.论述题
1.尝试回答与c语言的有理数代码相比较,为什么你设计的类更加面向对象?
(1)
- 在Java中,我们利用类来封装数据和行为。我们将有理数的分子分母封装在一个类里,并通过方法(get方法)的调用来访问数据,且类里的数据都被保护起来,不允许外部直接修改。
- 而在C语言中,通常利用结构体来存储数据,数据是公开的可以任意修改。
(2)
- 在 Java 中,方法属于类的一部分。每个 Rational对象都有自己的方法,如加法、减法等。这些方法可以直接在对象上调用,使得代码更加直观和易于理解。
- 在 C 语言中,方法通常是独立于数据结构的全局函数。虽然可以通过传递指向结构体的指针来操作数据,但这不如 Java 中的对象方法那样自然。
(3)
- Java 支持继承,允许从现有类派生新类(利用extends关键字)。子类可以复用父类的行为并添加新的特性。
- C 语言没有内置的继承机制。虽然可以通过包含结构体或其他技巧来模拟继承,但这种做法并不像 Java 中那么直接和强大。
2. 尝试从代码复用的角度来描述你设计的有理数类。从几个方面讨论。
2.1别人如何复用你的代码?
(1)通过注释了解类的属性和方法,必要时在JDK文档中查找类的功能
(2)通过代码测试检测代码是否可以正常运行
2.2别人的代码是否依赖你的有理数类的内部属性?当你升级了你的有理数类,将其的属性名改变时。是否会影响他人以前编写的调用你有理数类的代码(假设他将使用了你升级后有理数类)?
(1)封装是面向对象编程的一个核心原则,它确保了对象的内部状态对外部是不可见的,并且只能通过定义好的方法来访问和修改。
(2)私有化(private)Rational类的属性且提供公共的方法(getV1()和getV2())访问。
(3)
ational
类遵循了良好的封装原则,并且外部代码只通过公共接口(如 getter 和 setter 方法、运算方法等)来访问和操作Rational
对象,那么更改类的内部属性名不会影响外部代码。这是因为外部代码并不直接依赖于这些内部属性。
2.3有理数类的public方法是否设置合适?为什么有的方法设置为private?
(1)Rational类中的public方法有:构造函数,setter与getter方法,运算方法(add,multiply),toString(),equals()。
公共方法是类对外提供的接口,用户可以通过这些方法与对象进行交互。
(2)Rational类中的private方法有:Gcd()。
私有方法是类的内部实现细节,外部代码无法直接调用这些方法。将类中的辅助方法(Gcd())设为私有方法。避免外部代码直接调用他们,有利于保护内部的状态。
2.4你的类里面有static属性或方法吗?如果有,为什么要设置为static的?
类中的工具方法(提供辅助的方法),如Rational类中的Gcd()。设置为static那么方法可以通过类名直接调用,而不需要创建类的实例。
//求最大公约数 private static int Gcd(int m,int n){ int t; while(m % n != 0) { t = n; n = m%n; m = t; } return n; }
3.有理类设计
在设计面向对象的有理数类时,我深刻体会到了面向对象编程的精髓,也发现了自己在设计过程中的一些不足。
有理数类的设计需要考虑数据的封装、方法的实现以及异常处理等多个方面。通过将分子和分母封装为私有成员变量,并提供公共的构造函数和方法,我成功实现了有理数的基本运算,如加法、减法、乘法和除法。同时,我也为有理数类添加了化简功能,确保结果总是以最简形式表示。
然而,在设计过程中,我也遇到了一些问题。例如,我没有充分考虑到分母为零的情况,导致程序在运行时可能会出现异常。此外,在实现有理数的比较方法时,我最初没有考虑到浮点数精度问题,导致比较结果可能不准确。通过不断调试和优化,我逐步解决了这些问题,并加深了对面向对象编程的理解。
这次设计让我认识到,面向对象编程不仅仅是代码的封装,更是一种思维方式。我们需要从对象的角度去思考问题,将问题分解为一个个类和对象,并通过合理的方法和属性来实现功能。同时,我也意识到在设计过程中要充分考虑各种边界情况和异常情况,以提高程序的健壮性和可靠性。