Post on 30-Dec-2015
description
计算器与工程问题解析导论
第五课
类别与对象
史帝芬 .R.雷门教授贾德森 .霍华教授Prof. Steven R. Lerman
and
Dr. V. Judson Harward
物件
• 对象是「东西」– 回想一下在第一讲中所提到关于梁,楼板等的描述。
• 我们将程序问题分解成一组对象,这些对象可以做为整个状态的「自然」代表性质。举例来说 :– 一幢建筑物
• 物件列表– 每一个对象可以包含其它对象。将它们列出来。
– 通过路由器的数据封包• 物件列表
– 每一个对象可以包含其它对象。将它们列出来。
物件
• 一幢建筑物– 物件有:梁、版、墙、窗、管线、风管、热水锅炉、… ..
• 窗户包含了玻璃板、窗框• 构件 (像玻璃板 )是有属性的,如:外层、高度、宽度
• 通过路由器的数据封包– 物件有:网络进入的连结与送出的连结,路由器。这每一个对象可包含其它的对象:
• 网络连结:包含了资料封包• 路由器:包含了封包序列、缓冲器、处理器
范例:银行
• 顾客:– 数据域:
• 资料列表– 方法或动作
• 资料列表• 柜台:
– 数据域:• 资料表列
– 方法:• 资料表列
• 交易:– 数据域:
• 资料列表– 方法:
• 资料列表
范例:银行
• 顾客:– 数据域:
• 姓名、地址、职业、生日……
– 方法或动作• 开账号、变更地址、变更姓名、删除账号
• 柜台:– 数据域:
• 顾客、对帐、打字、交易– 方法:
• 新增、关闭、对帐检查、交易报告• 交易:
– 数据域:• 存款、提款、转帐、支票兑现、自动提款
– 方法:• 新增、执行交易
范例:鸟
建立对象模型
• 建立对象模型 (选择对的问题代表 )就像一般地建立模型– 一般来说没有固定的单一「正确」答案 (即使是我们的问题集也
是 )– 有弹性的、正确的、有效率的标准形态 /范例可以参考。
• 稍后我们会介绍给你「软件形态」– Java中已有许多的标准对象– 你可以建立属于自己的 Java对象库以供在未来的程序中使用。
类别
• 类别是由对象所构成的型态或样版– 你可以用一个模拟来做出很多鸟
• 一个鸟的类别 (或有更多的鸟的种类 )• 许多鸟的对象 (鸟的实例 )• 模拟
– 另一个范例• JOptionPane 是个属于 Swing套件中的类别。一个程序可能有许多的对话窗,每一个对话窗都是一个 JOptionPane类别的对象。
定义类别
• 类别包含了:– 数据 (构件、字段 )
• 主要的数据型态,例如:整数或双精度 (如鸟的重量 )• 哪些物件 (如鸟的嘴 )
– 方法 ( 功能、程序 )• 对象可以执行的动作 (如鸟的飞行 /移动 )
定义类别
• 类别来自于:– Java 类别库: JOptionPane, Vector(向量 ), Array(数组 )等。那里有数以千计的类别 ( 详 Javadoc) 。
– 其它资源的类别库: Video(影像 )等– 自行撰写的类别库。
• 类别在问题的叙述中通常是一个名词 (如:鸟 )• 方法则通常是动词 (如:飞 )
建立类别
• 类别会对使用者 (程序设计师使用预先写好的类别 )隐藏其执行的细节:– 其数据不能直接存取,而且对「外部」对象或程序也不知道其细
节。– 其数据几乎均为 private( 关键词 )
建立类别
• 藉由呼叫其方法来使用该对象– 外部使用者知道对象有什么方法,以及会传回何种结果,就是这
样 (通常来说 )。• 「外人」并不知道这些方法是如何被撰写的细节。
– 方法通常是 public ( 关键词 )• 藉由独立这些对象程序写作的细节,使得建立一支大型的程序变得更简单,也可以再利用先前工作中建立的对象。
• 这就称为「数据封装 (encapsulation) 」或「信息隐藏 (information hiding) 」
类别与对象
• 类别是一种「型态」 (pattern)– 一个类别可以拥有许多储存在类别内的数据项– 一个类别可以拥有许多操作 (或修改 )其数据与结果回传的方法
• 对象是类别的一部份– 对象拥有自己的数据、类别方法以及身份辨识 (一个名称 )
类别与对象
• Java类别库中的类别与你自行建立的并没有任何差别– 当你建立了一个类别 , 你就是在 Java中正在定义一个新的数据型态
– 实质上 , 你正在扩展 Java 语言• 类别也可以从其它的类别中来建立。
– 从其它的类别所建立的类别就扩展了原来的类别。– 这就称为「继承」 (inheritance) ,容后再述。
使用已存在的类别
• 内建的类别会比你自己撰写的更为理论与一般化。• BigInteger是一个处理任意大整数的 Java类别
– 使用这个类别而不要用你自己所写的来处理任意的运算
使用已存在的类别
• 要使用对象:– 首先要建构对象并指定他们的起始状态
• 建构子 (constructor) 是一个特殊的方法,是用来建构与设定对象的起始状态。• 他们可能需要自变量 (参数 )
– 然后对对象加上方法• 就好像「传送讯息」给对象来唤起他们的动作
物件 BigInteger 的建构子
• 要建构一个新的 BigInteger 对象,有两件事情是必要的:– 建立对象 (使用它的建构子 )
new BigInteger(“1000000000000”);
// ‘new’ 会配置内存并呼叫建构子– 给定对象一个名称或识别代号
BigInteger a;
// 对象的名称是对该对象的参考// BigInteger 为 a 的数据型态
物件 BigInteger 的建构子
– 将两件必要的事情结合为一件:BigInteger a = new BigInteger(“1000000000000”);– 现在我们拥有了一个内含值为 1,000,000,000,000的物件BigInteger。我们现在可以对这个对象设定方法。
• 方法是使用点 (.) 运算子来唤起的– 方法通常会用括号” ()”来结尾
BigInteger a= new BigInteger(“1000000000000”);
BigInteger z= new BigInteger(“23”);
BigInteger c= a.add(z); // c= a + z
If (z.isProbablePrime(15)) // z 是质数吗 ? System.out.println(“z is probably prime”);
• Public的数据域位也可以利用点运算子来唤起。– 在字段名称后不需要加上括号int j – a.somePublicField; // 只是范例
使用方法
对象与名称
对象与名称
对象与名称
对象与名称
对象与名称
对象与名称
使用 BigInteger 类别 ( 编注 :for random 与 random 漏译 , 已改正 )
给 BigInteger 使用
nbr 随机数产生器
c=b+a
质数
为了使用随机数而引入
取得随机数
练习一:现有的类别
• 利用 BigDecimal类别 ( 浮点数 )来:– 建构 BigDecimal a=13 x 10500– 以随机数建构 BigDecimal b
• 提示:建构一个随意的 BigInteger ,然后使用适当的 BigDecimal 建构子。详见 Javadoc 。
– 计算 BigDecimal c = a+b– 计算 BigDecimal d = c/a
• 在 Javadoc 中查询进位的型式– 分别计算出 a,b,c,d 后将结果打印出来
练习一:现有的类别
• 阶段式地撰写程序:– 建构 a, 将结果印出来。编译及除错
• 千万不要去数到底有多少个零 !
– 再建构 b,将结果印出来。编译及除错– 计算其相加与相除。编译及除错
练习二:撰写一个类别
• 在家庭作业中,你将要开始撰写自己的类别。– 你已经在所有的练习中看过类别的示范,但它们并不是典型的
• 它们都只有单一的方法 , main()
– 大部份的类别是没有main( )这个方法的• 建立一支程序,你将要撰写数个类别,而其中一个包含有
main( )的方法。
Point 类别public class SimplePoint {
private double x, y; // 资料成员public SimplePoint() { // 建构子
x= 0.0;y= 0.0; }
// 方法public double getX() { return x;}public double getY() { return y;}public void setX(double xval) { x= xval;}public void setY(double yval) { y= yval;}public void move(double deltaX, double deltaY) {
x += deltaX;y += deltaY; }
} // SimplePoint 类别的结束
// 这并不是一支程序,因为它没有 main( )// 但是可以藉由 main( )被类别使用
Point 类别 , main( )
练习二
• 使用极坐标来取代卡氏坐标,撰写一个不同的SimplePoint 类别。– 如前述 SimplePoint 类别般地执行相同的 public 方法– 使用 r 及 theta 做为 private 数据域位– 回顾:
• x = r cos(theta)• y = r sin(theta)• r = sqrt(x2 + y2)• theta= tan-1(y/x)
– 使用 Java 的 Math类别 ( 前缀为大写 M)• 使用 Math.atan2( ) 来表示 arctan 的功能
• 使用与前述相同的 main( ) 。
为何要做这练习 ?
• 透过建立一个具有 public方法但含有 private数据的类别,你只是指定一个接口,而非执行。– 如果你要改变执行,你可以用这样的方式来做而且不用修改相关
的程序代码,只要维持接口 (set of methods) 相同。– 变更坐标系统、计算方法等是相当平常的,如同这个范例一样。这样可让软件保有弹性来成长与改变。
Point 类别 , 以极坐标计算 ( 编注 :下方蓝色内文漏译 , 已修正 )class SimplePoint {
private double r, theta; // 资料成员为 publicSimplePoint() { // 建构子
r= 0.0;theta= 0.0; }
// 方法 (以弪度值为自变量的三角函数 )public double getX() { return r* Math.cos(theta);}public double getY() { return r* Math.sin(theta);}public void setX(double xval) {
double yval= r*Math.sin(theta);r= Math.sqrt(xval*xval + yval*yval);theta= Math.atan2(yval, xval); }
Point 类别 , 以极坐标计算 ( 续 )public void setY(double yval) {
double xval= r*Math.cos(theta);r= Math.sqrt(xval*xval + yval*yval);theta= Math.atan2(yval, xval); }
public void move(double deltaX, double deltaY) {double xval= r*Math.cos(theta);double yval= r*Math.sin(theta);xval += deltaX;yval += deltaY;r= Math.sqrt(xval*xval + yval*yval);theta= Math.atan2(yval, xval);}
}
// 可以从前述相同的 main()来唤起// 而且会产生相同的结果 (除了进位错误外 )
Java? 是 Sun Microsystems, Inc. 在美国及其它国家的注册商标。