类类型的字段
一、类类型的字段
public class Car {
private String name; // 名称
private int width; // 宽度
private int height; // 高度
private int length; // 长度
private double x; // 当前位置的X坐标
private double y; // 当前位置的Y坐标
private double fuel; // 剩余燃料
private Day purchaseDay; // 购买日期
//--- 构造函数 ---//
public Car(String name, int width, int height, int length, double fuel,
Day purchaseDay) {
this.name = name; this.width = width; this.height = height;
this.length = length; this.fuel = fuel; x = y = 0.0;
this.purchaseDay = new Day(purchaseDay);
}
public double getX() { return x; } // 获取当前位置的X坐标
public double getY() { return y; } // 获取当前位置的Y坐标
public double getFuel() { return fuel; } // 获取剩余燃料
public Day getPurchaseDay() { // 获取购买日期
return new Day(purchaseDay);
}
//--- 显示型号 ---//
public void putSpec() {
System.out.println("名称:" + name);
System.out.println("车宽:" + width + "mm");
System.out.println("车高:" + height + "mm");
System.out.println("车长:" + length + "mm");
}
//--- 向X方向移动dx、向Y方向移动dy ---//
public boolean move(double dx, double dy) {
double dist = Math.sqrt(dx * dx + dy * dy); // 移动距离
if (dist > fuel)
return false; // 无法移动 … 燃料不足
else {
fuel -= dist; // 减掉移动距离所消耗的燃料
x += dx;
y += dy;
return true; // 移动结束
}
}
}
private Day purchaseDay;---是用于保存购买日期的字段purchaseDay, 字段的类刚是类类型也就是说,如图所示它不是Day类型的电路(实例)、而是遥控器(引用实例的变量);
this.purchaseDay = new Day(purchaseDay); ---中通过构造函数设置日期,使用new运算符和复制构造函数创建购买日期的实例;创建形参purchaseDay中接收到的日期的副本,并将该副本的引用赋给字段purchaseDay,因此,字段purchaseDay就会引用形参中接收到的日期的副本。
public Day getPurchaseDay() { // 获取购买日期
return new Day(purchaseDay);
}
是购买日期的getter方法这里也使用了复制构造函数、创建购买日期字段的副本、并返同该副本的引用。
二、返回引用的方法
购买日期的getter方法getPurchaseDay并不是直接返回字段purchaseDay的值,而是在调用复制构造函数创建副本之后、再返同该副本的引用, 我们来思考一下这么做的原因。
class CarTester1 {
public static void main(String[] args) {
Day d = new Day(2010, 10, 15);
Car myCar = new Car("爱车", 1885, 1490, 5220, 90.0, d);
Day p = myCar.getPurchaseDay();
System.out.println("爱车的购买日期:" + p);
p.set(1999, 12, 31); // 改写购买日期(?)
Day q = myCar.getPurchaseDay();
System.out.println("爱车的购买日期:" + q);
}
}
程序的运行结果如下图所示,图a是类Car按照代码进行定义的程序,图b是定义方法getPurchaseDay且接返回字段purchaseDay的值的程序;
myCar是2010 年10月15 日购买的汽乍。1中通过方法getPurchaseDay获取了购买日期,并将其显示出来;
2中对获取的日期 p调用方法set, 将日期设置为1999年12月31日。
3中再次获取并显示购买日期;图a中的购买日期仍然是2010年10月15日,但图b中的购买日期则被改写成了1999年12月31日
图a …方法getPurchaseDay返回new Oay(purchaseDay)
方法getPurchaseDay会创建purchaseDay引用的日期实例的副本,并返回引用目标。1中,由于p被初始化为该副本的引用,因此2中会改写购买日期字段的副本;
3中在确认购买日期时,,会再次创建购买日期的副本,q会引用该副本;因此,购买日期还是2010年10月15日。
图b...方法getPurchaseDay返回purchaseDay
方法getPurchaseDay直接返同购买日期purchaseDay的引用。
1中将p初始化为购买日期字段purchaseDay的引用, 因此,2中改写的是购买日期字段本身;
3中在确认购买日期时,q会引用该日期; 因此,购买日期就变成了改写后的1999年12月31日。
【请注意不要返回引用类型的字段值,因为外部能通过该引用值间接改写值】
二、总结
1、除了用完就舍弃的内容,类和方法的声明中都可以加上public, 这样就可以在任何地方使用;
2、在类中,可以根据需要定义访问器用于获取字段abc的值的getter方法可以定义为getAbc,用于设置值的setter方法可以定义为setAbc;
3、当使用赋值或初始化复制类类型变量的值时,复制的并不是所有字段的值,而是引用目标;当通过方法的参数传递类类型的变量时,传递的是实例的引用;
4、当使用相等运算符比较类类型变量的值时,判断的是引用目标是否相等,而不是判断所有字段的值是否相等;
5、如果重载构造函数,该类的实例构建方法的选择范闱就比较广了。在构造函数的开头, 可以使用this(...)调用同一个类中的构造函数;
6、复制复制构造函数中会接收同一类类型的参数,并复制其全部字段的值,可以根据需要进行定义;
7、不应该将相同或者类似的代码分散在类中。如果要执行的处理在其他的方法或者构造函数中已经实现,就应该调用这个方法或者构造函数,委托其处理;
8、在类中,如果需要一个方法以字符串表示来返回实例的“当前状态”, 可以定义public String toString () { } ,该方法在“类类型变量+字符串” 和”字符串+类类型变量” 的运算中会被自动调用;
9、创建类类型的数组时,类类型变量的全部元素都会被初始化为空引用null ,各个元素是类类型的变量, 并不是实例,必须使用初始化或者赋值,将实例的引用赋给各个元素;
10、注意不要返回引用类型的字段值,这是因为外部能通过该引用值间接改写值。
//--- 二维坐标类 ---//
public class Point2D {
private int x = 0; // X坐标
private int y = 0; // Y坐标
public Point2D() { }
public Point2D(int x, int y) { set(x, y); }
public Point2D(Point2D p) { this(p.x, p.y); }
public int getX() { return x; }
public int getY() { return y; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public void set(int x, int y) { setX(x); setY(y); }
public String toString() { return "(" + x + "," + y + ")"; }
}
//--- 圆类 ---//
public class Circle {
private Point2D center; // 圆心坐标
private int radius = 0; // 半径
public Circle() { center = new Point2D(); }
public Circle(Point2D c, int radius) {
center = new Point2D(c); this.radius = radius;
}
public Point2D getCenter() { return new Point2D(center); }
public int getRadius() { return radius; }
public void setCenter(Point2D c) {
center.set(c.getX(), c.getY());
}
public void setRadius(int radius) { this.radius = radius; }
public String toString() {
return "圆心坐标:" + center.toString() + " 半径:" + radius;
}
}
//--- 测试圆和坐标 ---//
public class CircleTester {
public static void main(String[] args) {
Point2D[] p = new Point2D[] {
new Point2D(3, 7), new Point2D(4, 6)
};
Circle c1 = new Circle();
Circle c2 = new Circle(new Point2D(10,15), 5);
for (int i = 0; i < p.length; i++)
System.out.println("p[" + i + "] = " + p[i].toString());
c1.setRadius(10);
System.out.println("c1 = " + c1.toString());
System.out.println("c2 = " + c2.toString());
}
}