本系列文章经补充和完善,已修订整理成书《Java编程的逻辑》,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接http://item.jd.com/12299018.html


正所谓,道生一,一生二,二生三,三生万物,如果将二进制表示和运算看做一,将基本数据类型看做二,基本数据类型形成的类看做三,那么,类的组合以及下节介绍的继承则使得三生万物。

上节我们通过类Point介绍了类的一些基本概念和语法,类Point中只有基本数据类型,但类中的成员变量的类型也可以是别的类,通过类的组合可以表达更为复杂的概念。

程序是用来解决现实问题的,将现实中的概念映射为程序中的概念,是初学编程过程中的一步跨越。本节通过一些例子来演示,如何将一些现实概念和问题,通过类以及类的组合来表示和处理。

我们先介绍两个基础类String和Date,他们都是Java API中的类,分别表示文本字符串和日期。

基础类

String

String是Java API中的一个类,表示多个字符,即一段文本或字符串,它内部是一个char的数组,它提供了若干方法用于方便操作字符串。

String可以用一个字符串常量初始化,字符串常量用双引号括起来(注意与字符常量区别,字符常量是用单引号),例如,如下语句声明了一个String变量name,并赋值为"老马说编程"

String name = "老马说编程";

String类提供了很多方法,用于操作字符串。在Java中,由于String用的非常普遍,Java对它有一些特殊的处理,本节暂不介绍这些内容,只是把它当做一个表示字符串的类型来看待。

Date

Date也是Java API中的一个类,表示日期和时间,它内部是一个long类型的值,它也提供了若干方法用于操作日期和时间。

用无参的构造方法新建一个Date对象,这个对象就表示当前时间。

Date now = new Date();

日期和时间处理是一个比较长的话题,我们留待后续章节详解,本节我们只是把它当做表示日期和时间的类型来看待。

图形类

扩展 Point

我们先扩展一下Point类,在其中增加一个方法,计算到另一个点的距离,代码如下:

public double distance(Point p){
return Math.sqrt(Math.pow(x-p.getX(), 2)
+Math.pow(y-p.getY(), 2));
}

线 - Line

在类型Point中,属性x,y都是基本类型,但类的属性也可以是类,我们考虑一个表示线的类,它由两个点组成,有一个实例方法计算线的长度,代码如下:

public class Line {
private Point start;
private Point end; public Line(Point start, Point end){
this.start= start;
this.end = end;
} public double length(){
return start.distance(end);
}
}

Line由两个Point组成,在创建Line时这两个Point是必须的,所以只有一个构造方法,且需传递这两个点,length方法计算线的长度,它调用了Point计算距离的方法获取线的长度。可以看出,在设计线时,我们考虑的层次是点,而不考虑点的内部细节。每个类封装其内部细节,对外提供高层次的功能,使其他类在更高层次上考虑和解决问题,是程序设计的一种基本思维方式。

使用这个类的代码如下所示:

public static void main(String[] args) {
Point start = new Point(2,3);
Point end = new Point(3,4); Line line = new Line(start, end);
System.out.println(line.length());
}

这个也很简单。我们再说明一下内存布局,line的两个实例成员都是引用类型,引用实际的point,整体内存布局大概如下图所示:

start, end, line三个引用型变量分配在栈中,保存的是实际内容的地址,实际内容保存在堆中,line的两个实例变量还是引用,同样保存的是实际内容的地址。

电商概念

接下来,我们用类来描述一下电商系统中的一些基本概念,电商系统中最基本的有产品、用户和订单:

  • 产品:有产品唯一Id、名称、描述、图片、价格等属性。
  • 用户:有用户名、密码等属性。
  • 订单:有订单号、下单用户、选购产品列表及数量、下单时间、收货人、收货地址、联系电话、订单状态等属性。

当然,实际情况可能非常复杂,这是一个非常简化的描述。

这是产品类Product的代码:

public class Product {
//唯一id
private String id; //产品名称
private String name; //产品图片链接
private String pictureUrl; //产品描述
private String description; //产品价格
private double price;
}

我们省略了类的构造方法,以及属性的getter/setter方法,下面大部分示例代码也都会省略。

这是用户类User的代码:

public class User {
private String name;
private String password;
}

一个订单可能会有多个产品,每个产品可能有不同的数量,我们用订单条目OrderItem这个类来描述单个产品及选购的数量,代码如下所示:

public class OrderItem {
//购买产品
private Product product; //购买数量
private int quantity; public OrderItem(Product product, int quantity) {
this.product = product;
this.quantity = quantity;
} public double computePrice(){
return product.getPrice()*quantity;
}
}

OrderItem引用了产品类Product,我们定义了一个构造方法,以及计算该订单条目价格的方法。

下面是订单类Order的代码:

public class Order {
//订单号
private String id; //购买用户
private User user; //购买产品列表及数量
private OrderItem[] items; //下单时间
private Date createtime; //收货人
private String receiver; //收货地址
private String address; //联系电话
private String phone; //订单状态
private String status; public double computeTotalPrice(){
double totalPrice = 0;
if(items!=null){
for(OrderItem item : items){
totalPrice+=item.computePrice();
}
}
return totalPrice;
}
}

Order类引用了用户类User,以及一个订单条目的数组orderItems,它定义了一个计算总价的方法。这里用一个String类表示状态status,更合适的应该是枚举类型,枚举我们后续文章再介绍。

以上类定义是非常简化的了,但是大概演示了将现实概念映射为类以及类组合的过程,这个过程大概就是,想想现实问题有哪些概念,这些概念有哪些属性,哪些行为,概念之间有什么关系,然后定义类、定义属性、定义方法、定义类之间的关系,大概如此。概念的属性和行为可能是非常多的,但定义的类只需要包括哪些与现实问题相关的就行了。

人 - Person

上面介绍的图形类和电商类只会引用别的类,但一个类定义中还可以引用它自己,比如我们要描述人以及人之间的血缘关系,我们用类Person表示一个人,它的实例成员包括其父亲、母亲、和孩子,这些成员也都是Person类型。

下面是代码:

public class Person {
//姓名
private String name; //父亲
private Person father; //母亲
private Person mother; //孩子数组
private Person[] children; public Person(String name) {
this.name = name;
}
}

这里同样省略了setter/getter方法。对初学者,初看起来,这是比较难以理解的,有点类似于函数调用中的递归调用,这里面的关键点是,实例变量不需要一开始都有值。我们来看下如何使用。

public static void main(String[] args){
Person laoma = new Person("老马");
Person xiaoma = new Person("小马"); xiaoma.setFather(laoma);
laoma.setChildren(new Person[]{xiaoma}); System.out.println(xiaoma.getFather().getName());
}

这段代码先创建了老马(laoma),然后创建了小马(xiaoma),接着调用xiaoma的setFather方法和laoma的setChildren方法设置了父子关系。内存中的布局大概如下图所示:


目录和文件

接下来,我们介绍两个类MyFile和MyFolder,分别表示文件管理中的两个概念,文件和文件夹。文件和文件夹都有名称、创建时间、父文件夹,根文件夹没有父文件夹,文件夹还有子文件列表和子文件夹列表。

下面是文件类MyFile的代码:

public class MyFile {
//文件名称
private String name; //创建时间
private Date createtime; //文件大小
private int size; //上级目录
private MyFolder parent; //其他方法 .... public int getSize() {
return size;
}
}

下面是MyFolder的代码:

public class MyFolder {
//文件夹名称
private String name; //创建时间
private Date createtime; //上级文件夹
private MyFolder parent; //包含的文件
private MyFile[] files; //包含的子文件夹
private MyFolder[] subFolders; public int totalSize(){
int totalSize = 0;
if(files!=null){
for(MyFile file : files){
totalSize+=file.getSize();
}
}
if(subFolders!=null){
for(MyFolder folder : subFolders){
totalSize+=folder.totalSize();
}
}
return totalSize;
}
//其他方法...
}

MyFile和MyFolder,我们都省略了构造方法、settter/getter方法,以及关于父子关系维护的代码,主要演示实例变量间的组合关系,两个类之间可以互相引用,MyFile引用了MyFolder,而MyFolder也引用了MyFile,这个是没有问题的,因为正如之前所说,这些属性不需要一开始就设置,也不是必须设置的。另外,演示了一个递归方法totalSize(),返回当前文件夹下所有文件的大小,这是使用递归函数的一个很好的场景。

一些说明

类中定义哪些变量,哪些方法是与要解决的问题密切相关的,本节中并没有特别强调问题是什么,定义的属性和方法主要用于演示基本概念,实际应用中应该根据具体问题进行调整。

类中实例变量的类型可以是当前定义的类型,两个类之间可以互相引用,这些初听起来可能难以理解,但现实世界就是这样的,创建对象的时候这些值不需要一开始都有,也可以没有,所以是没有问题的。

类之间的组合关系,在Java中实现的都是引用,但在逻辑关系上,有两种明显不同的关系,一种是包含,另一种就是单纯引用。比如说,在订单类Order中,Order与User的关系就是单纯引用,User是独立存在的,而Order与OrderItem的关系就是包含,OrderItem总是从属于某一个Order。
小结

对初学编程的人来说,不清楚如何用程序概念表示现实问题,本节通过一些简化的例子来解释,如何将现实中的概念映射为程序中的类。

分解现实问题中涉及的概念,以及概念间的关系,将概念表示为多个类,通过类之间的组合,来表达更为复杂的概念以及概念间的关系,是计算机程序的一种基本思维方式。

类之间的关系除了组合,还有一种非常重要的关系,那就是继承,让我们下节来探索继承及其本质。

----------------

未完待续,查看最新文章,敬请关注微信公众号“老马说编程”(扫描下方二维码),从入门到高级,深入浅出,老马和你一起探索Java编程及计算机技术的本质。原创文章,保留所有版权。

-----------

更多相关原创文章

计算机程序的思维逻辑 (13) - 类

计算机程序的思维逻辑 (15) - 初识继承和多态

计算机程序的思维逻辑 (16) - 继承的细节

计算机程序的思维逻辑 (17) - 继承实现的基本原理

计算机程序的思维逻辑 (18) - 为什么说继承是把双刃剑

计算机程序的思维逻辑 (19) - 接口的本质

计算机程序的思维逻辑 (20) - 为什么要有抽象类?

计算机程序的思维逻辑 (21) - 内部类的本质

Java编程的逻辑 (14) - 类的组合的更多相关文章

  1. Java编程的逻辑 (13) - 类

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  2. 《Java编程的逻辑》 - 文章列表

    <计算机程序的思维逻辑>系列文章已整理成书<Java编程的逻辑>,由机械工业出版社出版,2018年1月上市,各大网店有售,敬请关注! 京东自营链接:https://item.j ...

  3. Java编程的逻辑 (15) - 初识继承和多态

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  4. Java编程的逻辑 (16) - 继承的细节

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  5. Java编程的逻辑 (17) - 继承实现的基本原理

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  6. Java编程的逻辑 (18) - 为什么说继承是把双刃剑

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  7. Java编程的逻辑 (19) - 接口的本质

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  8. Java编程的逻辑 (20) - 为什么要有抽象类?

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  9. Java编程的逻辑 (21) - 内部类的本质

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

随机推荐

  1. OI回忆录第一章 逐梦之始

    2013年春,初中零年级.GXZ来到吉大高中机房,参加一位老师曾在班级宣传的"计算机培训".同行的有这位老师,以及近80名同学.和同学们一样,GXZ也是为了在机房玩游戏而参加所谓的 ...

  2. docker--从仓库下载镜像到推送自己的项目到仓库步骤详解

    怎样从仓库下载的镜像,变成容器,并在容器中制作项目,再将容器变成镜像,然后将镜像推送到仓库? 一:从官网下载镜像 官方的https://hub.docker.com/提供了数十万个镜像提供大家下载 以 ...

  3. Django_终端打印原生SQL语句

    打印所有的sql语句 在Django项目的settings.py文件中,在最后复制粘贴如下代码: LOGGING = { 'version': 1, 'disable_existing_loggers ...

  4. 沉迷AC自动机无法自拔之:[UVALive 4126] Password Suspects

    图片加载可能有点慢,请跳过题面先看题解,谢谢 一看到这么多模式串就非常兴奋,又是\(AC\)自动机 题目就是要求:经过 \(n\) 个节点,把所有单词都遍历一遍的方案数,和那道题差不多嘛 所以这样设: ...

  5. BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流

    传送门 BZOJ 1565 题解 这道题也是个经典的最大权闭合子图-- 复习一下最大权闭合子图是什么? 就是一个DAG上,每个点有个或正或负的点权,有的点依赖于另外一些点(如果选这个点,则被依赖点必选 ...

  6. 标记,上传并下载自己创建的镜像 image

    1. 首先使用 docker images 查看已有镜像: 2. 获得 docker-whale 的 IMAGE ID,然后为 docker-whale 镜像 image 打上标签 Tag.使用命令: ...

  7. 洛谷 P5162 WD与积木 解题报告

    P5162 WD与积木 题目背景 WD整日沉浸在积木中,无法自拔-- 题目描述 WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同).由于一些特殊原因,商家会 ...

  8. CF1110E Magic Stones(构造题)

    这场CF怎么这么多构造题…… 题目链接:CF原网 洛谷 题目大意:给定两个长度为 $n$ 的序列 $c$ 和 $t$.每次我们可以对 $c_i(2\le i<n)$ 进行一次操作,也就是把 $c ...

  9. non-transactional

    this.getHibernateTemplate().getSessionFactory().getCurrentSession().createQuery(queryString)报错No Hib ...

  10. linux查看硬盘详细信息

    最近公司新进了一批设备,为了弄清楚厂家有没有忽悠我们,分配给我一个任务 查看磁盘是不是二手的,window上有鲁大师啥的那么linux有什么软件吗? 答案是有的! 叫做smart 具体请查看: htt ...