软件构造 笔记

冰雹序列
冰雹序列的定义
从正整数n开始,如果n是偶数,则下一个数是n/2,否则下一个数是3n+1,直到n等于1。
示例如下:

如果n是偶数,下一个数会比n小。如果n是奇数,下一个数会比n大。n的取值忽大忽小,那么n最后都会归为1么?(目前没有解决办法)

冰雹序列的计算代码

这里需要注意的是:
python以缩进分割语句块,以换行判断语句的结束。
Java以花括号分割语句块,以分号判断语句的结束。
这是我认为两种语言风格上较大的区别。

数据类型
在上面的代码当中我们就可以看到,Python和Java最大的不同在于,Java需要指定变量的类型。Java提供的数据类型部分如下:
·原始类型:
byte short int long boolean double char float
·包装类型(对象类型):
Byte Short Integer Long Boolean Double String Float
对于Java来说,原始类型用小写字母,对象类型的大写字母开头。

操作符
操作符是一些能接受输入并输出结果的功能。
Java3种常见操作符:

静态类型
Java是一种静态类型的语言。所有变量的类型在编译的时候就已经知道了(程序还没有运行)。静态类型是静态检查的一种——检查发生在编译的时候。而在动态类型语言中(例如Python),这种类型检查是发生在程序运行的时候。

这里有一些经验,告诉你这静态和动态检查通常会发现什么bug:

静态检查
·语法错误,例如多余的标点符号或者错误的关键词。即使在动态类型的语言例如Python中也会做这种检查:如果你有一个多余的缩进,在运行之前就能发现它。
·错误的名字,例如Math.sine(2). (应该是 sin.)
·参数的个数不对,例如 Math.sin(30, 20).
·参数的类型不对 Math.sin(“30”).
·错误的返回类型 ,例如一个声明返回int类型函数return “30”;
对比动态检查的经验:

动态检查
·非法的变量值。例如整型变量x、y,表达式x/y。只有在运行后y为0才会报错,否则就是正确的。
·无法表示的返回值。例如最后得到的返回值无法用声明的类型来表示。
·越界访问。例如在一个字符串中使用一个负数索引。
·使用一个null对象解引用。(null相当于Python中的None)
静态检查倾向于类型错误,即与特定的值无关的错误。
而动态检查倾向于特定的值会触发的错误。

原始类型并不是真正的数字!
原始类型并不是真正的数字!
在Java和许多其他语言中存在一个“陷阱”——原始数据类型的对象在有些时候并不像真正的数字那样得到应有的输出。
例如有一些我们很常见的错误:
·整数的除法:5/2不会返回2.5。
·整型溢出:当数值过大的时候,发生负溢出。
·浮点类型中的特殊值:NaN、无穷的表示。

练习

1

int n = 5;
if (n) {
n = n + 1;
}
1
2
3
4
静态错误
2

int big = 200000; // 200,000
big = big * big; // big should be 40 billion now
1
2
无报错,但是得到错误的结果
3

double probability = 1/5;
1
无报错,但是得到错误的结果
4

int sum = 0;
int n = 0;
int average = sum/n;
1
2
3
动态错误
5

double sum = 7;
double n = 0;
double average = sum/n;
1
2
3
无报错,但是得到错误的结果
浮点数除零为Infinity

数组和列表
在Java中有两种常用的线性存储结构:array和list。
数组是一连串类型相同的元素组成的结构,而且它的长度是固定的(元素个数固定)。
int[] a = new int[100];
需要注意的是,当你求取数组长度的时候:
a. length (注意和 String.length() 的区别—— a.length 不是一个类内方法调用,你不能在它后面写上括号和参数)
下面是我们利用数组写的第一个求“冰雹序列”的代码,它存在一些bug:

相信很快你就能发现错误:幻数100?
注:幻数是指那些特定的设计好的数值.
像这样的bug称为越界访问,在Java中能够被动态检查检测出来,但是在C和C++这样的语言中则会造成缓冲区溢出(能通过编译),这也是很多漏洞的来源。
解决方式是使用list类型。
列表类型是一个长度可变的序列结构。我们可以这样声明列表:
List list = new ArrayList();
常用的操作符有下:
·索引一个元素: list.get(2)
·赋予一个元素特定的值: list.set(2, 0)
·求列表的长度: list.size()
这里要注意List是一个接口,这种类型的对象无法直接用new来构造,必须用能够实现List要求满足的操作符的方法来构造。ArrayList是一个实类型的类(concrete type),它提供了List操作符的具体实现。当然,ArrayList不是唯一的实现方法(还有LinkedList等),但是最常用的一个)。
另外要注意的是,我们要写List 而不是List。因为List只会处理对象类型而不是原始类型。当我们使用尖括号参量化一个类型时,Java要求我们使用对象类型而非原始类型。在其他的一些情况中,Java会自动在原始类型和对等的对象类型之间相转换。例如在上面的代码中我们可以使用Integer i = 0
下面是用列表写的“冰雹序列”的实现:

遍历
例如,找到list当中最大元素的代码:

方法
在Java中,声明通常必须在一个方法中,而每个方法都要在一个类型中,所以写“冰雹序列”程序最简单可以这么写:

不变性
Java也给我们提供了不变的索引:只要变量被初始化后就不能再次被赋值了——只要在声明的时候加上final :

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值