350 likes | 483 Views
计算器与工程问题解析导论. 第五课 类别与对象. 史帝芬 .R. 雷门教授 贾德森 . 霍华教授 Prof. Steven R. Lerman and Dr. V. Judson Harward. 物件. 对象是「东西」 回想一下在第一讲中所提到关于梁,楼板等的描述。 我们将程序问题分解成一组对象,这些对象可以做为整个状态的「自然」代表性质。举例来说 : 一幢建筑物 物件列表 每一个对象可以包含其它对象。将它们列出来。 通过路由器的数据封包 物件列表 每一个对象可以包含其它对象。将它们列出来。. 物件. 一幢建筑物
E N D
计算器与工程问题解析导论 第五课 类别与对象 • 史帝芬.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( )被类别使用
练习二 • 使用极坐标来取代卡氏坐标,撰写一个不同的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; // 资料成员为 public • SimplePoint() { // 建构子 • 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.在美国及其它国家的注册商标。