> Java > java지도 시간 > Java 초보자를 위한 30가지 자주 묻는 질문 분석

Java 초보자를 위한 30가지 자주 묻는 질문 분석

怪我咯
풀어 주다: 2017-06-25 10:03:08
원래의
1518명이 탐색했습니다.

이 문서에는 Java 초보자를 위한 30가지 일반적인 질문에 대한 답변이 나와 있습니다. %를 소수로 나눌 수 있나요? a += b와 a = a + b의 효과에 차이가 있나요? 배열을 선언하는 데 시간이 많이 걸리는 이유는 무엇입니까? JAVA 라이브러리가 무작위 피벗 빠른 정렬을 사용하지 않는 이유는 무엇입니까?

1.2 기본 데이터 유형

Q. -0/3의 결과는 0이고, -0.0/3.0의 결과는 -0.0인 이유는 무엇입니까? (다음 결과 0에는 음수 부호가 있음을 참고하세요.)

A. Java에서 정수는 2의 보수로 표현됩니다. 2의 보수로 0을 표현하는 방법은 한 가지뿐입니다. 반면, 부동소수점 숫자는 IEEE 표준을 사용하여 표현하는데, 0, 0, -0을 표현하는 방법에는 두 가지가 있습니다.

Q. %를 소수로 나눌 수 있나요?

물론이죠. 예를 들어, angle이 음수가 아닌 경우 angle % (2 * Math.PI)는 각도를 0과 2 π 사이로 변환합니다.

Q. a와 b가 모두 기본 유형 변수인 경우 a += ba = a + b의 효과에 차이가 있나요?

A. a와 b의 유형이 다른 경우 두 문의 효과가 다를 수 있습니다. a += ba = (int) (a + b)와 동일합니다. 이 경우 a는 int 유형일 수 있고 b는 float 유형일 수 있습니다. 그러나 동일한 상황에서 a = a + b는 컴파일되고 오류를 보고합니다.

1.3 조건문 및 루프문

Q. 왜 ==을 사용하여 문자열 동등성을 판단할 수 없나요?

A 이는 기본 유형(int, double, boolean)과 참조 유형(String)의 차이를 반영합니다.

Q. 문장 블록의 중괄호를 생략할 수 없는 상황이 있나요?

A. 아래 예에서 첫 번째 코드는 유효하지만 두 번째 코드는 컴파일 오류를 발생시킵니다. 기술적인 관점에서 볼 때 해당 문은 문이 아닌 변수 선언이므로 오류가 보고됩니다.

Java 초보자를 위한 30가지 자주 묻는 질문 분석
// legal
for (int i = 0; i <div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://img.php.cn/upload/article/000/000/001/00193eabe270982797aba73cdd73470b-1.gif" alt="Java 초보자를 위한 30가지 자주 묻는 질문 분석"></span></div>
로그인 후 복사

Q. 다음 두 코드에서 효과가 다른 상황이 있나요?

Java 초보자를 위한 30가지 자주 묻는 질문 분석
for (<init> <boolean>; <incr>) {
   
}

<init>;
while (<boolean>) {
   
   <incr>
}</incr></boolean></init></incr></boolean></init>
로그인 후 복사
Java 초보자를 위한 30가지 자주 묻는 질문 분석

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

 

1.4  数组

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

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

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

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

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

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

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

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

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

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

 

1.5 输入输出语句

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

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

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

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

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

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

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

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

String NEWLINE = System.getProperty("line.separator");
로그인 후 복사

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

String s;                         
while (!StdIn.isEmpty()) {        while (!StdIn.isEmpty()) {
    s = StdIn.readString();           String s = StdIn.readString();
    ...                               ...
}                                 }
로그인 후 복사

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

 

2.1 函数调用

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

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

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

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

 

2.3 递归调用

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

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

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

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

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

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

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

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

 

4.2 排序与查找

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

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

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

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

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

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

 

4.3 栈和队列

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

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

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

private Item[] a = new Item[max]; 
oldfirst = first;
로그인 후 복사

A. 不错的尝试。不幸的是,创建一个泛型数组在 Java 1.5里不支持。你可以使用cast,比如下面的写法:

private Item[] a = (Item[]) new Object[max]; 
oldfirst = first;
로그인 후 복사

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

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

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

public static void main(String[] args) {
   for (String s : args)
      StdOut.println(s);
}
로그인 후 복사

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

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

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

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

Integer a = null;
int b = a;
로그인 후 복사

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

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

Integer a1 = 100;
Integer a2 = 100;
System.out.println(a1 == a2);   // true

Integer b1 = new Integer(100);
Integer b2 = new Integer(100);
System.out.println(b1 == b2);   // false

Integer c1 = 150;
Integer c2 = 150;
System.out.println(c1 == c2);   // false
로그인 후 복사

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

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群:159610322   我们一起学Java!

위 내용은 Java 초보자를 위한 30가지 자주 묻는 질문 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿