《Head First Java》笔记(2)

2024-08-24 09:08
文章标签 java 笔记 head first

本文主要是介绍《Head First Java》笔记(2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2.1 面向过程与面向对象之间的战争

面向过程与面向对象之间的战争是由下面一则小故事引起的。

从前,有一个软件小铺,该小铺的老板娘(同时也是项目经历)手下有两个小兵:阿朱和阿娇。有一天,老板娘故意刁难两个兵,并且让她两进行比赛,看谁的程序写的好。要求:在图形接口画出正方形、圆形与三角形。当用户点选某个图形时,图形要顺时针旋转360度,并且根据形状的不同而播放不同的AIF音效的音乐文件。 最终赢的人会坐上象征身份地位的宝座!

当接到这个任务的时候,阿朱首先想到的是:这个程序要执行什么动作?会需要什么样的程序?一会她就想到了,需要旋转(rotate)和播放音乐(playSound)这两个动作。于是,阿朱就迫不及待的写下了下面的程序:
这里写图片描述

当接到这个任务的时候,阿娇首先想到的是:这个程序有什么样的事物?有什么关键角色?她首先想到的时候形状体(shape)。当然,她还想到了用户、声响等对象与点击等事件。但是这些对象早就已经建立好了,而她只需要专注于创建形状体就ok了。于是,她就写下了如下程序:
这里写图片描述

此时,当阿朱看到阿娇的代码这么长的时候,心里已经乐开花了,心想,这次赢定了,那个宝座是自己的了!!!

然而,万恶的老板娘此时却又说规格需要有点改动。在原有的基础上,加上阿米巴原虫形状(不规则形状体),用户点选时也是旋转并播放.hif声音的文件。

听到这个改动后,阿朱心想rotate这个程序还可以接着用,但是playSound这个就得需要修改了,于是,她奋笔写下了如下程序:
这里写图片描述

听到这个改动后,阿娇苦笑一下,在原有的基础上又增加了一个类,如下:
这里写图片描述

当她们两把各自的程序拿给老板娘看时,老板娘失望的说:“唉呀,不对呀,阿米巴原虫不是这样旋转的…..”。
原来两个人都把旋转部分写成了这样:
1) 找出指定形状的外接四边形
2) 计算出外接四边形的中心点,以此点为中心进行旋转。
但是老板娘认为阿米巴原虫是这样旋转的:绕着一端进行旋转。
听到这里,阿朱一脸的懵逼,最后奋力的在rotate函数中加上“if/else”,于是写下了下面的程序:
这里写图片描述

这样做之后,就会造成其有一堆程序需要修改,从而本来已经测试号的东西全部又要重来一遍。

而阿娇仅仅在Amoeda这类上作了相应的修改,其他已经测试通过的部分完全不需要修改。其实现如下:
这里写图片描述

此时,阿朱看到阿娇的改动非常小,心有不甘。于是,就质问道:“阿娇,你写的代码中,冲的部分太多,而且设计的时候需要同时维护4个不同的rotate方法,效率有点低”。面对阿朱的质疑。阿娇不紧不慢的回答道:“阿朱,让我告诉你什么叫做面向对象的继承(inheritance)”。

第一步:找出4个类中的共同部分
这里写图片描述

第二步:它们都是形状(Shape),而且都有rotate和playSound这两个方法,因此可以提取出新的类
这里写图片描述

第三步:将上面的4个不同的形状体以继承的关系连接到Shape这个新类中,如下:
这里写图片描述

我们可以称“Square继承自Shape”,“Circle继承自Shape”,“Triangle继承自Shape”,“Amoeda继承自Shape”,而rotate和playSound这两个方法已经移出了Square、Circle、Triangle和Amoeda这四个类了。这里,我们称Shape这个类为父类(基类),称Square、Circle、Triangle和Amoeda这四个类为子类(派生类)。

到这里,阿朱还不死心,继续提出了质疑:“你这样设计,岂不是阿米巴原虫也是继承自Shape,那旋转的功能不就是都变成一样的了吗?”
阿娇说:“问的号。Amoeda这个类可以覆盖(override)Shape的方法。Java虚拟机会知道在遇到Amoeda时会使用不同的rotate方法。”

第四步:让Amoeda这个类去覆盖Shape这个父类中的rotate()和playSound()的两个方法。
这里写图片描述

覆盖的意思就是由子类重新定义继承下来的方法,以改变或延伸此方法的行为。

到此,你是不是就觉得这场比赛,阿娇大获全胜呢??非也,其实获胜的是阿花(老板娘的侄女)。看到这里,各位看官想必都明白:出来混社会,关系一定要硬啊!!!!

2.2 类与对象

首先要明白:类不是对象,类是用来创建对象的模型

创建对象需要两个类:一个是要被操作于对象的类,另一个是用来测试该类的类。

测试用的类带有main()方法,并且会在其中建立与存取被测的对象。
习惯用法:测试用的类一般命名为“受测类名称”+TestDrive。

下面就来创建第一个对象Dog
第1步:编写被测对象Dog类

class Dog
{//定义实例变量int size;String breed;String name;//定义方法void bark(){System.out.println("Ruff ! Ruff !");}   
}

第2步:编写测试用的类DogTestDrive

class DogTestDrive
{public static void main(String[] args){Dog d = new Dog(); //创建一个Dog对象,对象名为dd.size = 40; //采用圆点运算符存取对象的变量d.bark();  //采用圆点运算符调用对象的方法}
}

命令行中执行命令:(必须在绝对路径下去执行)

>javac DogTestDirve.java
>java DogTestDrive

运行结果:
这里写图片描述

2.3 快离开main

只要还待在main中,你就是游离在对象村之外!因为,对于面向对象应用程序来说,我们需要用对象来与对象交互。

2.3.1 main()的两种用途:

  1. 测试真正的类
  2. 启动Java应用程序

真正的Java程序只会让对象与对象交互。这里所说的交互是指相互调用方法。

2.3.2 猜数字游戏

游戏规则:
游戏开始先产生一个0~9之间的随机数作为谜底,然后由三个玩家进行猜数字,只要有一个玩家猜的数字与谜底数字相同,游戏就结束,否则一直进行下去。

对象设计:
这里涉及到两个对象:Player(玩家)和Game(游戏),针对游戏规则,我们设计三个类:Player、GuessGame、GuessLauncher,如下:
这里写图片描述

程序源码:

class GuessGame
{public void startGame(){//先创建三个玩家Player p1 = new Player();Player p2 = new Player();Player p3 = new Player();//定义三个变量,分别存放玩家所猜的数字int guessP1 = 0;int guessP2 = 0;int guessP3 = 0;//声明三个变量,保存玩家是否猜中boolean p1isRight = false;boolean p2isRight = false;boolean p3isRight = false;//随机产生一个0~9之间的数作为谜底数字int targetNumber = (int)(Math.random() * 10);System.out.println("Target Number is " + targetNumber);while(true){//获取每个玩家所猜的数字p1.guess();guessP1 = p1.number;System.out.println("Player one guessed is " + guessP1);p2.guess();guessP2 = p2.number;System.out.println("Player two guessed is " + guessP2);p3.guess();guessP3 = p3.number;System.out.println("Player three guessed is " + guessP3);if(guessP1 == targetNumber){p1isRight = true;}if(guessP2 == targetNumber){p2isRight = true;}if(guessP3 == targetNumber){p3isRight = true;}if(p1isRight || p2isRight || p3isRight)//只要有一人猜中,游戏就结束{System.out.println("We have a winner !");System.out.println("Player one  guessed right ? " + p1isRight);System.out.println("Player two  guessed right ? " + p2isRight);System.out.println("Player three  guessed right ? " + p3isRight);System.out.println("Game Over");break; //游戏结束,跳出循环}else{System.out.println("No one guess right, and game must be continue");}       }       }
}class Player
{int number = 0; //保存玩家猜的数字public void guess(){number = (int) (Math.random() * 10);        }
}public class GameLauncher
{public static void main(String[] args){GuessGame game = new GuessGame();game.startGame();}
}

编译遇到的问题:
1> 命令行编译java源文件提示“编码GBK的不可映射字符”
解决方法:
在输入 javac 命令时,额外输入 -encoding utf-8, 例如:如果编译的源文件名为 Test.java ,那么编译时原先只需输入javac Test.java,而现在需要输入 javac -encoding utf-8 Test.java

2> 显示错误
1. 类GuessGame是公共的,应在名为GuessGame.java文件中声明。
2. 类Player是公共的,应在名为Player.java文件中声明
解决方法:
产生上面的错误原因是,将三个类都写在了同一个.java文件中了,并且类的前面都用了public修饰符进行了修饰,而一个.java文件里面只能有一个public class XXX{} 。
所以将GuessGame和Player这两个类前面的public修饰符去掉,或者将这两个类写在不同的.java文件中即可。
运行结果:
这里写图片描述

这篇关于《Head First Java》笔记(2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102052

相关文章

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J

Spring AI Alibaba接入大模型时的依赖问题小结

《SpringAIAlibaba接入大模型时的依赖问题小结》文章介绍了如何在pom.xml文件中配置SpringAIAlibaba依赖,并提供了一个示例pom.xml文件,同时,建议将Maven仓... 目录(一)pom.XML文件:(二)application.yml配置文件(一)pom.xml文件:首

SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤

《SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤》本文主要介绍了SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤,文中通过示例代码介绍的非常详... 目录 目标 步骤 1:确保 ProxySQL 和 mysql 主从同步已正确配置ProxySQL 的