面向对象编程(Java)

面向对象思考

面向对象程序设计之前,先进行问题求解和基本程序设计。

面向过程和面向对象程序设计的不同之处。

面向对象程序设计的优点。

如何在应用程序中设计新类、如何使用这些类,以及 Java API 中的一些新的类。

类的抽象和封装

类的抽象是指将类的实现和类的使用分离开,实现的细节被封装并且对用户隐藏,这被称为类的封装。

方法的抽象,

Java 提供了多层次的抽象。类抽象 (class abstraction) 是将类的实现和使用分离。从类外可以访问的方法和数据域的集合以及预期这些成员如何行为的描述,合称为类的合约 (class’s contract)。类的创建者描述类的功能,让使用者明白如何才能使用类。类的使用者不需要知道类是如何实现的。实现的细节经过封装,对用户隐藏起来,这称为类的封装 (class encapsulation)。由于这个原因;类也称为抽象数据类型 (Abstract Data Type, ADT)。类的抽象和封装是一个问题的两个方面。类抽象将类的实现与类的使用分离。

传统的面向过程式编程是动作驱动的,数据和动作是分离的。面向对象编程的范式重点在于对象,动作和数据一起定义在对象中。

从类的开发者的角度来看,设计类是为了让很多不同的用户所使用。为了在更大的应用范围内使用类,类应该通过构造方法、属性和方法提供各种方式的定制。

面向对象的思考

面向过程的范式重点在于设计方法。面向对象的范式将数据和方法耦合在一起构成对象。使用面向对象范式的软件设计重点在对象以及对对象的操作上。

类为构建可重用软件提供了更高的灵活性和更多的模块化。使用对象和类来开发可重用代码。

面向对象范式比面向过程范式有优势的地方:
面向过程范式重在设计方法。面向对象范式将数据和方法都组合在对象中。使用面向对象范式的软件设计重在对象和对象上的操作。面向对象方法结合了面向过程范式的功能以及将数据和操作集成在对象中的特性。

在面向过程程序设计中,数据和数据上的操作是分离的,而且这种做法要求传递数据给方法。面向对象程序设计将数据和对它们的操作都放在一个对象中。这个方法解决了很多面向过程程序设计固有的问题。面向对象程序设计方法以一种反映真实世界的方式组织程序,在真实世界中,所有的对象和属性及动作都相关联。使用对象提高了软件的可重用性,并且使程序更易于开发和维护。Java 程序设计涉及对对象的思考,一个 Java 程序可以看作是一
个相互操作的对象集合。

类的关系

为了设计类,需要探究类之间的关系。类中间的关系通常是关联、聚合、组合以及继承。

关联
关联是一种常见的二元关系,描述两个类之间的活动。

关联可以使用 UML 图形标识来表达:
关联由两个类之间的实线表示,可以有一个可选的标签描述关系。
每个关系可以有一个可选的小的黑色三角形表明关系的方向。
关系中涉及的每个类可以有一个角色名称,描述在该关系中担当的角色。

关联中涉及的每个类可以给定一个多重性 (multiplicity) ,放置在类的边上用于给定 UML 图中关系所涉及的类的对象数。多重性可以是一个数字或者一个区间,决定在关系中涉及类的多少个对象。字符 * 意味着无数多个对象,而 m…n 表示对象数处于 m 和 n 之间,并且包括 m 和 n 。

在 Java 代码中,可以通过使用数据域以及方法来实现关联。

注意: 实现类之间的关系可以有很多种可能的方法。

聚集和组合
聚集是关联的一种特殊形式,代表了两个对象之间的归属关系。聚集建模 has-a 关系。所有者对象称为聚集对象,它的类称为聚集类。而从属对象称为被聚集对象,它的类称为被
聚集类。

一个对象可以被多个其他的聚集对象所拥有。如果一个对象只归属于一个聚集对象,那么它和聚集对象之间的关系就称为组合 (composition) 。

在 UML 中,附加在聚集类上的实心菱形表示它和被聚集类之间具有组合关系;而附加在聚集类上的空心菱形表示它与被聚集类之间具有聚集关系。

聚集关系通常被表示为聚集类中的一个数据域。

聚集可以存在于同一类的多个对象之间。

注意:由于聚集和组合关系都以同样的方式用类来表示,我们不区分它们,将两者都称为
组合。

将基本数据类型值作为对象处理

基本数据类型值不是一个对象,但是可以使用 Java API 中的包装类来包装成一个对象。

出于对性能的考虑,在 Java 中基本数据类型不作为对象使用。处理对象需要额外的系统开销,如果将基本数据类型当作对象,就会给语言性能带来负面影响。然而,Java 中的许多方法需要将对象作为参数。Java 将基本数据类型并入对象或包装成对象(例如,将 int 包装成 Integer 类,将 double 包装成 Double 类,将 char 包装成 Character 类)。通过使用包装类,可以将基本数据类型值作为对象处理。Java为基本数据类型提供了 Boolean、Character、Double、Float、 Byte、Short、Integer 和 Long 等包装类。这些包装类都打包在 java.lang 包里。
注意:

  • Boolean 类包装了布尔值 true 或者 false 。
  • 大多数基本类型的包装类的名称与对应的基本數据类型名称一样,第一个字母要大写。Integer 和 Character 例外。

包装类提供构造方法、常量和处理各种数据类型的转换方法。

数值包装类相互之间都非常相似。每个都包含了 doubleValue() 、floatValue() 、 intValue()、longValue()、shortValueO 和 byteValue() 方法。这些方法返回包装对象的 double、float、int、long 或 short 值,将对象“转换”为基本类型值。

既可以用基本数据类型值也可以用表示数值的字符串来构造包装类。

包装类没有无参构造方法。所有包装类的实例都是不可变的,这意味着一旦创建对象后,它们的内部值就不能再改变。

每一个数值包装类都有常量 MAX_VALUE 和 MIN_VALUE。MAX_VALUE 表示对应的基本数据类型的最大值。对于 Byte 、Short、Integer 和 Long 而言,MIN_VALUE 表示对应的基本类型 byte、short、int 和 long 的最小值。对 Float 和 Double 类而言, MIN_VALUE 表示 float 型和 double 型的最小正值。

下 String 类中包含 compareTo 方法用于比较两个字符串。数值包装类中包含
compareTo 方法用于比较两个数值,并且如果该数值大于、等于或者小于另外一个数值时,分别返回 1、0、-1 。

数值包装类有一个有用的静态方法 valueOf(String s) 。该方法创建一个新对象,并将它初始化为指定字符串表示的值。

Integer 类中的 parselnt 方法将一个数值字符串转换为一个 int 值,而且使用过 Double 类中的 parseDouble 方法将一个数值字符串转变为一个 double 值。每个数值包装类都有两个重载的方法,将数值字符串转换为正确的以 10 (十进制) 或指定值为基数 (例如,2 为二进制,8 为八进制,16 为十六进制) 的数值。

注意,可以使用 format 方法返回一个格式化的字符串。

基本类型和包装类类型之间的自动转换

根据上下文环境,基本数据类型值可以使用包装类自动转换成一个对象,反过来的自动转换也可以。

将基本类型值转换为包装类对象的过程称为装箱 (boxing) ,相反的转换过程称为开箱 (unboxing) 。Java 允许基本类型和包装类类型之间进行自动转换。如果一个基本类型值出现在需要对象的环境中,编译器会将基本类型值进行自动装箱;如果一个对象出现在需要基本类型值的环境中,编译器会将对象进行自动开箱。这称为自动装箱和自动开箱。

Biglnteger 和 BigDecimal 类

Biglnteger 类和 BigDecimal 类可以用于表示任意大小和精度的整教或者十进制数。

如果要进行非常大的数的计算或者高精度浮点值的计算,可以使用 java.math 包中的 Biglnteger 类和 BigDecimal 类。它们都是不可变的。long 类型的最大整数值为 long.MAX_VALUE (即 9223372036854775807) 。Biglnteger 的实例可以表示任意大小的整数。可以使用 new Biglnteger(String) 和 new BigDecimal(String) 来创建 Biglnteger 和 BigDecimal 的实例,使用 add、subtract、multiple、divide 和 remainder 方法完成算术运算,使用 compareTo 方法比较两个大数字。

对 BigDecimal 对象的精度没有限制。如果结果不能终止,那么divide 方法会抛出 ArithmeticException 异常。但是,可以使用重载的 divide(BigDecimal d.int scale, int roundingMode) 方法来指定尺度和舍入方式来避免这个异常,这里的 scale 是指小数点后最小的整数位数。

String 类

String 对象是不可改变的。字符串一旦创建,内容不能再改变。

字符串是对象,可以通过 charAt(index) 方法从字符串中得到某个指定位置的字符。length() 方法返回字符串的大小,substring 方法返回字符串中的子串,indexOf 和 lastIndexOf 方法返回第一个或者最后一个匹配的字符或者子字符串。String 类中有 13 个构造方法以及 40 多个处理字符串的方法。

构造字符串
可以用字符串直接量或字符数组创建一个字符串对象。使用如下语法,用字符串直接量
创建一个字符串:

String newString = new String(stringLiteral);

参数 StringLiteral 是一个括在双引号内的字符序列。

Java 将字符串直接量看作 String 对象。还可以用字符数组创建一个字符串。

注意: String 变量存储的是对 String 对象的引用,String 对象里存储的才是字符串的值。严格地讲,术语 String 变量、String 对象和字符串值是不同的。但在大多教情况下,它们之间的区别是可以忽略的。为简单起见,术语字符串将经常被用于指 String 变量、String 对象和字符串的值。

不可变字符串与限定字符串
String 对象是不可变的,它的内容是不能改变的。

字符串在程序设计中是不可变的,但同时又会频繁地使用,Java 虚拟机为了提高效率并节约内存,对具有相同字符序列字符串直接量使用同一个实例。这样的实例称为限定的 (interned) 字符串。

字符串的替换和分隔
String 类提供替换和分隔字符串的方法。

一旦创建了字符串,它的内容就不能改变。但是,方法 repalce、replaceFirst 和 replaceAll 会返回一个源自原始字符串的新字符串 (并未改变原始字符串!) 。它们实现用新的字符或子串替换字符串中的某个字符或子串。

split 方法可以从一个指定分隔符的字符串中提取标识。

依照模式匹配、替换和分割
正则表达式 (regular expression) (缩写 regex) 是一个字符串,用于描述匹配一个字符串集的模式。可以通过指定某个模式来匹配、替换或分隔一个字符串。这是一种非常有用且功能强大的特性。

matches 方法的功能强大。它不仅可以匹配定长的字符串,还能匹配一套遵从某种模式的字符串。

  • .*是一个正则表达式,与 0个或多个字符相匹配。它描述的字符串模式是字符串后面紧跟任意 0 个或多个字符。
  • \d 表示单个数字位,\{3} 表示三个数字位。
  • 正则表达式 [$+#] 表示能够匹配 $、+ 或者 * 的模式。
  • 正则表达式 [.,:;?] 指定的模式是指匹配 . , : ; 或者 ? 。这里的每个字符都是分隔字符串的分隔符。

方法 replaceAll、replaceFirst 和 split 也可以和正则表达式结合在一起使用。

字符串与数组之间的转换
字符串不是数组,但是字符串可以转换成数组,反之亦然。为了将字符串转换成一个字符数组,可以使用 toCharArray 方法。

还可以使用方法 getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin) 将下标从 srcBegin 到 srcEnd-1 的子串复制到字符数组 dst 中下标从 dstBegin 开始的位置。

为了将一个字符数组转换成一个字符串,应该使用构造方法 String(Char[]) 或者方法 value0f(char[]) 。

将字符和数值转换成字符串

可以使用 Double.parseDouble(str) 或者 Integer_ parselnt(str) 将一个字符串转换为一个 double 值或者一个 int 值,也可以使用字符串的连接操作符来将字符或者数字转换为字符串。另外一种将数字转换为字符串的方法是使用重载的静态 valueOf 方法。该方法可以用于将字符和数值转换成字符串

格式化字符串

String 类包含静态 format 方法,它可以创建一个格式化的字符串。调用该方法的语法是:

String.format(format, item l, item 2, ···, item k)

这个方法很像 Printf 方法,只是 format 方法返回一个格式化的字符串,而 printf 方法显示一个格式化的字符串。

StringBuilder 和 StringBuffer 类

StringBuilder 和 StringBuffer 类似于 String 类,区别在于 String 类是不可改变的。

一般来说,只要使用字符串的地方,都可以使用 StringBuilder/StringBuffer 类。StringBuilder/StringBuffer 类比 String 类更灵活。可以给一个 StringBuilder 或 StringBuffer 中添加、插入或追加新的内容,但是 String 对象一旦创建,它的值就确定了。

除了 StringBuffer 中修改缓冲区的方法是同步的,这意味着只有一个任务被允许执行方法之外,StringBuilder 类与 StringBuffer 类是很相似的。如果是多任务并发访问,就使用 StringBuffer ,因为这种情况下需要同步以防止 StringBuffer 崩溃。如果是单任务访问,使用 StringBuilder 会更有效。StringBuffer 和 StringBuilder 中的构造方法和其他方法几乎是完全一样的。StringBuilder 都可以替换为 StringBuffer。

修改 StringBuilder 中的字符串
在字符串构建器的末尾追加新内容,在字符串构建器的特定位置插人新的内容,还可以删除或替换字符串构建器中的字符。

StringBuilder 类提供了几个重载方法,可以将 boolean、char、char 数组、double、float、int、long 和 String 类型值追加到字符串构建器。
StringBuilder 类也包括几个重载的方法,可以将 boolean、char 、char 数组、double、float、int,long 和 String 类型值插人到字符串构建器。

使用 delete 方法将字符从构建器中的字符串中删除,使用 reverse 方法倒置字符串,使用 replace 方法替换字符串中的字符,或者使用 setCharAt 方法在字符串中设置一个新字符。除了 setCharAt 方法之外,所有这些进行修改的方法都做两件事:

  • 改变字符串构建器的内容。
  • 返回字符串构建器的引用。

所有带返回值类的方法都可以被当作语句调用。在这种情况下,Java 就简单地忽略掉返回值。

提示: 如果一个字符串不需要任何改变,则使用 String 类而不使用 StringBuffer 类。Java 可以完成对 String 类的优化,例如,共享限定字符串等。

toString、capacity、length、setLength 和 charAt 方法
StringBuilder 类提供了许多其他处理字符串构建器和获取它的属性的方法。
capacity() 方法返回字符串构建器当前的容量。容量是指在不增加构建器大小的情况下能够存储的字符数量。
length()方法返回字符串构建器中实际存储的字符数量。setLength(newLength) 方法设置字符串构建器的长度。如果参数 newLength 小于字符串构建器的当前长度,则字符串构建器会被截短到恰好能包含由参数 newLength 给定的字符个数。如果参数 newLength 大于或等于当前长度,则给字符串构建器追加足够多的空字符 ("\uOOOO") , 使其长度 length 变成新参数 newLength 。参数 newLength 必须大于等于 0。
charAt(index)方法返回字符串构建器中某个特定下标 index 的字符。下标是基于 0 的,字符串构建器中的第一个字符的下标为 0, 第二个字符的下标为1,依此类推。参数 index必须大于或等于 0, 并且小于字符串构建器的长度。

注意: 字符串的长度总是小于或等于构建器的容量。长度是存储在构建器中的字符串的实际大小,而容量是构建器的当前大小。如果有更多的字符添加到字符串构建器,超出它的容量,则构建器的容量就会自动增加。在计算机内部,字符串构建器是一个字符数组,因此,构建器的容量就是数组的大小。如果超出构建器的容量,就用新的数组替換现有数组。新数组的大小为 2x(之前数组的长度+1) 。

提示: 可以使用 new StringBuilder(initialCapacity) 创建指定初始容量的 StringBuilder。通过仔细选择初始容量能够使程序更有效。如果容量总是超过构建器的实际使用长度,JVM 将永远不需要为构建器重新分配内存。另一方面,如果容量过大将会浪费内存空间。可以使用 trimToSize() 方法将容量降到实际的大小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值