豪仕知识网--知识就是力量!

微信
手机版
生活常识

JAVA初学者常见的的30个不同于其他编程语言的问题

作者 :耶律楚材 2024-01-07 07:17:37 围观 : 评论

JAVA初学者常见的的30个不同于其他编程语言的问题

豪士君测试所用平台

以下就是我们整理的JAVA初学者常见的的30个不同于其他编程语言的问题,一起来看看,希望能帮助到您。

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

本文回答了30个JAVA入门级初学者的常见问题。 我可以用%除以一个小数吗? a += b 和 a = a + b 的效果有区别吗? 声明一个数组为什么需要花费大量时间? 为什么JAVA库不用随机pivot方式的快速排序?

豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

1.2 基本数据类型

豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.为什么 -0/3 结果是0,而 -0.0/3.0 结果是-0.0?(注意后边的结果0带负号)

A.在Java里,整数是用补码表示的。在补码中0只有一种表示方法。另一方面,浮点数则是用IEEE 标准表示的, 对于0有两种表示方法, 0 和-0。

●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

Q.我可以用%除以一个小数吗?

A.当然可以。比如,如果angle是一个非负数,那么angle % (2 * Math.PI)就会把 angle 转换到 0 到2 π之间。

Q.当 a b 都是基本类型变量时,a += b和a = a + b的效果有区别吗?

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

A.当 a 和 b 的类型不同时,那两条语句的效果就可能有区别。a += b等同于a = (int) (a + b),这种情况下可以是a是int型,b是float型。但是同等情况下a = a + b就会编译报错。

1.3条件语句和循环语句

HTTP://WWW.haoz.net◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐豪仕知识网

Q.为什么判断字符串相等不能使用==?

A.这反映了基础类型(int,double,boolean)和引用类型(String)的区别。

Q.有没有在什么情况下,一条语句块的花括号不能省略的?

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

A.在下面的例子中,第一段代码是合法的,第二段代码会引发编译错误。从技术角度说,那一条语句是一个变量声明,而不是语句,所以会报错。

//legalfor(inti=0;i<=N;i++){intx=5;}//illegalfor(inti=0;i<=N;i++)intx=5;

Q.在下面的两段代码里,有没有情况,它们的效果不一样?

for(;){};while(){}

A.有的。如果在循环块里使用continue语句。在for的代码里,计数器会加一;而在while的代码里,因为被continue略过了,计数器不加一。

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

1.4 数组

Q.某些Java开发人员使用int a[]而不是int[] a去声明一个数组。这两者有什么区别?

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

A.在Java中这两种用法都是合法的,他们的作用都是一样的。前者是在C中的定义数组的方法。后者是JAVA推荐的方法,因为它的写法int[]更能表明这是一个int的数组。

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.为什么数组下标从0 开始 而不是从 1 开始?

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.这种传统起源于机器语言的编程方法。在机器语言中,数组下标被用来计算元素位置与第一个元素之间的偏移量。如果从1开始的话,计算偏移时还需要做一次减法运算,那是种浪费。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

Q.如果我用 负数 作为数组下标会发生什么事?

A.下标小于0 或者 大于等于数组长度,JAVA运行时会抛出ArrayIndexOutOfBoundsException异常,并且中止程序运行。

Q.使用数组时还有其他需要注意的陷阱吗?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

A.需要记住,JAVA在你创建一个数组时会去初始化它,所以声明一个数组需要 O(N)的时间。

Q.既然a[]是一个数组,为什么System.out.println(a)会打印出一个16进制的数,就像@f62373这样,而不是打印出数组的元素?

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

A.好问题。这条语句打印出的是 数组在内存中的地址,不幸的是,在绝大多数情况下,这不是你需要的。

●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

1.5 输入输出语句

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

Q.我可以从标准input中重新读一次数据吗?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

A.不可以,你只能读一次。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.怎样输入 end-of-file (eof) 符号?

A.操作系统自动包括它了。

Q.使用printf() 时还有哪些用法?

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.对于整数来说,使用o输出八进制,使用x输出十六进制。对于浮点数来说,使用e或者g输出科学计数法形式。

Q.行结束的符号是什么?

A.不同的文件系统使用了不同的符号。在 Unix 系统上,新行的符号是'\n' ;在Windows 系统上,每一行都有两个字符组成的字符串终结"\r\n" ;在Macs 系统上,终结符号是"\n\r" 。如果要打印行号,可以使用System.out.println(),或者使用下面的语句得到当前操作系统下的行结束符:

StringNEWLINE=System.getProperty("line.separator");
●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

Q.下面两种写法,哪一种更有效率?

Strings;while(!StdIn.isEmpty()){while(!StdIn.isEmpty()){s=StdIn.readString();Strings=StdIn.readString();......}}

A.从效率角度说,两者没有区别。 但是第二种写法更好,因为它限制了变量的作用域。

2.1 函数调用

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

Q.当把数组当作函数调用时的参数时,我常常感到疑惑?

A.是的。你需要牢记传值参数(参数是基本变量类型)和传引用参数(比如数组)之间的区别。

豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.那为什么不把所有的参数都使用传值的方式,包括对待数组?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

A.但数组很大时,复制数组需要大量的性能开销。因为这个原因,绝大多数变成语言支持把数组传入函数但不复制一个副本——MATLAB语言除外。

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

2.3 递归调用

Q.有没有只能用循环而不能用递归的情况?

A.不可能,所有的循环都可以用递归替代,虽然大多数情况下,递归需要额外的内存。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

Q.有没有只能用递归而不能用循环的情况?

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.不肯能,所有的递归调用都可以用循环来表示。比如你可以用while的方式来实现栈。

Q.那我应该选择哪个,递归的方式 还是 循环的方式?

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

A.根据代码的可读性和效率性之间做权衡。

Q.我担心使用递归代码时的空间开销和重复计算(例如用递归解Fibonacci)的问题。有没有其他需要担心的?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

A.在递归代码中创建大数据类型(比如数组)时需要额外注意,随着递归的推进,内存使用将会迅速增加,由于内存使用增加,操作系统管理内存的时间开销也会增加。

4.2 排序与查找

Q.为什么我们要花大篇幅来证明一个程序是正确的?

◐◐◐◐●☛█▼▲豪仕知识网HT●☛█▼▲◐◐◐◐●☛█▼▲

A.为了防止错误的结果。二分查找就是一个例子。现在,你懂得了二分查找的原理,你就能把递归形式的二分查找改写成循环形式的二分查找。Knuth 教授在 1946年就发表了二分查找的论文,但是第一个正确的二分查找的程序在 1962年在出现。

Q.在JAVA内建库中有没有排序和查找的函数?

HTTP://WWW.haoz.net◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐豪仕知识网

A.有的。在java.util.Arrays中包含了Arrays.sort()和Arrays.binarySearch()方法。对于Comparable 类型它使用了 归并排序,对于基本数据类型,它使用了快速排序。因为基本类型是值传递,快速排序比归并排序更快而且不需要额外的空间。

Q. 为什么JAVA库不用 随机pivot方式的快速排序?

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A. 好问题。 因为某些程序员在调试代码时,可能需要确定性的代码实现。使用随机pivot违背了这个原则。

4.3 栈和队列

Q.在Java库中有对stacks 和 queues 的实现吗?

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.Java库中内建java.util.Stack,但是你应该避免使用它如果你需要一个真正的栈的话。因为它是实现了额外的功能,比如访问第N个元素。另外,它也支持从栈底部插入元素,所以它看上去更像是一个队列。尽管实现了这些额外的功能对编程人员是一个加分,可是我们使用数据结构并不只是想使用所有功能,而是需要我们正好需要的那种结构。JAVA对于栈的实现就是一个典型的宽接口的例子。

Q.我想使用数组来表示一个包含通用结构的栈,但是以下代码编译报错。为什么?

privateItem[]a=newItem[max];oldfirst=first;

A.不错的尝试。不幸的是,创建一个包含通用结构的数组在 Java 1.5里已经不支持了。你可以使用cast,比如下面的写法:

privateItem[]a=(Item[])newObject[max];oldfirst=first;
http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

根本的原因是JAVA中的数组是“协变的(covariant)”,但是通用结构并不是。比如,String[]是Object[]的一种子类型,但是Stack并不是Stack 的一种子类型。许多程序员认为“协变的”数组是JAVA在数据类型方面的一个缺点。但是,如果我们不考虑通用结构,“协变的”数组是有用的,比如实现Arrays.sort(Comparable[])方法,然后当参数是String[]时它也可以被正常调用。

Q.可不可以在数组上使用 foreach 方式?

A.可以的(虽然 数组并没有实现Iterator接口)。请参考下面的代码:

publicstaticvoidmain(String[]args){for(Strings:args)StdOut.println(s);}
HTTP://WWW.haoz.net◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐豪仕知识网

Q.在 linked list 上使用 iterator 是不是比循环或者递归更有效率?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

A.编译器在翻译时,可能把那种“尾递归”形式翻译成等价的循环形式。所以可能并没有可以被观测到的性能提升。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

尾部递归是一种编程技巧。如果在递归函数中,递归调用返回的结果总被直接返回,则称为尾部递归。尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。比如f(n, sum) = f(n-1) + value(n) + sum; 会保存n个函数调用堆栈,而使用尾递归f(n, sum) = f(n-1, sum+value(n)); 这样则只保留后一个函数堆栈即可,之前的可优化删去。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

Q.自动装箱机制会怎么处理下面的情况?

Integera=null;intb=a;

A.它将返回一个运行时错误。基础类型不允许它对应的装箱类型里的值是null。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.为什么第一组打印的是true,但是后面两组打印的是false?

Integera1=100;Integera2=100;System.out.println(a1==a2);//trueIntegerb1=newInteger(100);Integerb2=newInteger(100);System.out.println(b1==b2);//falseIntegerc1=150;Integerc2=150;System.out.println(c1==c2);//false

A.第二组代码打印false是因为b1和b2指向不同的 Integer 对象引用。第一组和第三组依赖于自动装箱机制。 令人意外的第一组打印了 true 是因为在 -128 和 127 之间的值会自动转换成同样的immutable型的Integer对象。对于超出那个范围的数,Java会对于每一个数创建一个新的Integer对象。

本文翻译自《Introduction to Programming in Java》一书中部分章节的 Q&A 部分。作者为普林斯顿大学计算机系教授Robert Sedgewick 和 Kevin Wayne。

●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

本文回答了30个JAVA入门级初学者的常见问题。 我可以用%除以一个小数吗? a += b 和 a = a + b 的效果有区别吗? 声明一个数组为什么需要花费大量时间? 为什么JAVA库不用随机pivot方式的快速排序?

1.2 基本数据类型

Q.为什么 -0/3 结果是0,而 -0.0/3.0 结果是-0.0?(注意后边的结果0带负号)

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

A.在Java里,整数是用补码表示的。在补码中0只有一种表示方法。另一方面,浮点数则是用IEEE 标准表示的, 对于0有两种表示方法, 0 和-0。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.我可以用%除以一个小数吗?

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.当然可以。比如,如果angle是一个非负数,那么angle % (2 * Math.PI)就会把 angle 转换到 0 到2 π之间。

Q.当 a b 都是基本类型变量时,a += b和a = a + b的效果有区别吗?

A.当 a 和 b 的类型不同时,那两条语句的效果就可能有区别。a += b等同于a = (int) (a + b),这种情况下可以是a是int型,b是float型。但是同等情况下a = a + b就会编译报错。

豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

1.3条件语句和循环语句

Q.为什么判断字符串相等不能使用==?

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.这反映了基础类型(int,double,boolean)和引用类型(String)的区别。

Q.有没有在什么情况下,一条语句块的花括号不能省略的?

A.在下面的例子中,第一段代码是合法的,第二段代码会引发编译错误。从技术角度说,那一条语句是一个变量声明,而不是语句,所以会报错。

//legalfor(inti=0;i<=N;i++){intx=5;}//illegalfor(inti=0;i<=N;i++)intx=5;
◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.在下面的两段代码里,有没有情况,它们的效果不一样?

for(;){};while(){}
豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.有的。如果在循环块里使用continue语句。在for的代码里,计数器会加一;而在while的代码里,因为被continue略过了,计数器不加一。

1.4 数组

Q.某些Java开发人员使用int a[]而不是int[] a去声明一个数组。这两者有什么区别?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

A.在Java中这两种用法都是合法的,他们的作用都是一样的。前者是在C中的定义数组的方法。后者是JAVA推荐的方法,因为它的写法int[]更能表明这是一个int的数组。

Q.为什么数组下标从0 开始 而不是从 1 开始?

A.这种传统起源于机器语言的编程方法。在机器语言中,数组下标被用来计算元素位置与第一个元素之间的偏移量。如果从1开始的话,计算偏移时还需要做一次减法运算,那是种浪费。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.如果我用 负数 作为数组下标会发生什么事?

A.下标小于0 或者 大于等于数组长度,JAVA运行时会抛出ArrayIndexOutOfBoundsException异常,并且中止程序运行。

Q.使用数组时还有其他需要注意的陷阱吗?

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

A.需要记住,JAVA在你创建一个数组时会去初始化它,所以声明一个数组需要 O(N)的时间。

豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.既然a[]是一个数组,为什么System.out.println(a)会打印出一个16进制的数,就像@f62373这样,而不是打印出数组的元素?

A.好问题。这条语句打印出的是 数组在内存中的地址,不幸的是,在绝大多数情况下,这不是你需要的。

1.5 输入输出语句

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.我可以从标准input中重新读一次数据吗?

A.不可以,你只能读一次。

Q.怎样输入 end-of-file (eof) 符号?

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

A.操作系统自动包括它了。

Q.使用printf() 时还有哪些用法?

A.对于整数来说,使用o输出八进制,使用x输出十六进制。对于浮点数来说,使用e或者g输出科学计数法形式。

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.行结束的符号是什么?

A.不同的文件系统使用了不同的符号。在 Unix 系统上,新行的符号是'\n' ;在Windows 系统上,每一行都有两个字符组成的字符串终结"\r\n" ;在Macs 系统上,终结符号是"\n\r" 。如果要打印行号,可以使用System.out.println(),或者使用下面的语句得到当前操作系统下的行结束符:

StringNEWLINE=System.getProperty("line.separator");

Q.下面两种写法,哪一种更有效率?

Strings;while(!StdIn.isEmpty()){while(!StdIn.isEmpty()){s=StdIn.readString();Strings=StdIn.readString();......}}
豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.从效率角度说,两者没有区别。 但是第二种写法更好,因为它限制了变量的作用域。

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

2.1 函数调用

◐◐◐◐●☛█▼▲豪仕知识网HT●☛█▼▲◐◐◐◐●☛█▼▲

Q.当把数组当作函数调用时的参数时,我常常感到疑惑?

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.是的。你需要牢记传值参数(参数是基本变量类型)和传引用参数(比如数组)之间的区别。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

Q.那为什么不把所有的参数都使用传值的方式,包括对待数组?

A.但数组很大时,复制数组需要大量的性能开销。因为这个原因,绝大多数变成语言支持把数组传入函数但不复制一个副本——MATLAB语言除外。

2.3 递归调用

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

Q.有没有只能用循环而不能用递归的情况?

A.不可能,所有的循环都可以用递归替代,虽然大多数情况下,递归需要额外的内存。

Q.有没有只能用递归而不能用循环的情况?

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.不肯能,所有的递归调用都可以用循环来表示。比如你可以用while的方式来实现栈。

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.那我应该选择哪个,递归的方式 还是 循环的方式?

A.根据代码的可读性和效率性之间做权衡。

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.我担心使用递归代码时的空间开销和重复计算(例如用递归解Fibonacci)的问题。有没有其他需要担心的?

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

A.在递归代码中创建大数据类型(比如数组)时需要额外注意,随着递归的推进,内存使用将会迅速增加,由于内存使用增加,操作系统管理内存的时间开销也会增加。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

4.2 排序与查找

Q.为什么我们要花大篇幅来证明一个程序是正确的?

A.为了防止错误的结果。二分查找就是一个例子。现在,你懂得了二分查找的原理,你就能把递归形式的二分查找改写成循环形式的二分查找。Knuth 教授在 1946年就发表了二分查找的论文,但是第一个正确的二分查找的程序在 1962年在出现。

◐◐◐◐●☛█▼▲豪仕知识网HT●☛█▼▲◐◐◐◐●☛█▼▲

Q.在JAVA内建库中有没有排序和查找的函数?

A.有的。在java.util.Arrays中包含了Arrays.sort()和Arrays.binarySearch()方法。对于Comparable 类型它使用了 归并排序,对于基本数据类型,它使用了快速排序。因为基本类型是值传递,快速排序比归并排序更快而且不需要额外的空间。

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

Q. 为什么JAVA库不用 随机pivot方式的快速排序?

A. 好问题。 因为某些程序员在调试代码时,可能需要确定性的代码实现。使用随机pivot违背了这个原则。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

4.3 栈和队列

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.在Java库中有对stacks 和 queues 的实现吗?

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

A.Java库中内建java.util.Stack,但是你应该避免使用它如果你需要一个真正的栈的话。因为它是实现了额外的功能,比如访问第N个元素。另外,它也支持从栈底部插入元素,所以它看上去更像是一个队列。尽管实现了这些额外的功能对编程人员是一个加分,可是我们使用数据结构并不只是想使用所有功能,而是需要我们正好需要的那种结构。JAVA对于栈的实现就是一个典型的宽接口的例子。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

Q.我想使用数组来表示一个包含通用结构的栈,但是以下代码编译报错。为什么?

privateItem[]a=newItem[max];oldfirst=first;

A.不错的尝试。不幸的是,创建一个包含通用结构的数组在 Java 1.5里已经不支持了。你可以使用cast,比如下面的写法:

privateItem[]a=(Item[])newObject[max];oldfirst=first;

根本的原因是JAVA中的数组是“协变的(covariant)”,但是通用结构并不是。比如,String[]是Object[]的一种子类型,但是Stack并不是Stack 的一种子类型。许多程序员认为“协变的”数组是JAVA在数据类型方面的一个缺点。但是,如果我们不考虑通用结构,“协变的”数组是有用的,比如实现Arrays.sort(Comparable[])方法,然后当参数是String[]时它也可以被正常调用。

豪仕知识网http://www.haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

Q.可不可以在数组上使用 foreach 方式?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

A.可以的(虽然 数组并没有实现Iterator接口)。请参考下面的代码:

publicstaticvoidmain(String[]args){for(Strings:args)StdOut.println(s);}

Q.在 linked list 上使用 iterator 是不是比循环或者递归更有效率?

A.编译器在翻译时,可能把那种“尾递归”形式翻译成等价的循环形式。所以可能并没有可以被观测到的性能提升。

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

尾部递归是一种编程技巧。如果在递归函数中,递归调用返回的结果总被直接返回,则称为尾部递归。尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。比如f(n, sum) = f(n-1) + value(n) + sum; 会保存n个函数调用堆栈,而使用尾递归f(n, sum) = f(n-1, sum+value(n)); 这样则只保留后一个函数堆栈即可,之前的可优化删去。

●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

Q.自动装箱机制会怎么处理下面的情况?

Integera=null;intb=a;

A.它将返回一个运行时错误。基础类型不允许它对应的装箱类型里的值是null。

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

Q.为什么第一组打印的是true,但是后面两组打印的是false?

Integera1=100;Integera2=100;System.out.println(a1==a2);//trueIntegerb1=newInteger(100);Integerb2=newInteger(100);System.out.println(b1==b2);//falseIntegerc1=150;Integerc2=150;System.out.println(c1==c2);//false

A.第二组代码打印false是因为b1和b2指向不同的 Integer 对象引用。第一组和第三组依赖于自动装箱机制。 令人意外的第一组打印了 true 是因为在 -128 和 127 之间的值会自动转换成同样的immutable型的Integer对象。对于超出那个范围的数,Java会对于每一个数创建一个新的Integer对象。

●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

本文翻译自《Introduction to Programming in Java》一书中部分章节的 Q&A 部分。作者为普林斯顿大学计算机系教授Robert Sedgewick 和 Kevin Wayne。

JAVA初学者常见的的30个不同于其他编程语言的问题文章到此结束,字数约18264字,希望可以帮助到大家。豪仕知识网往后会继续推荐JAVA初学者常见的的30个不同于其他编程语言的问题相关内容。

相关文章