Java中看似简单实际很坑的题目

第一题(貌似是考察方法的参数传递)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test{
public static void main(String[] args){
int a = 10;
int b = 20;
method(a,b);//在调用method()方法之后输出a = 100,b = 200
System.out.println("a = " + a);
System.out.println("b = " + b);
}
static void method(int a,int b){
//代码编写处

}
}

如果在method中直接写

1
2
a = 100;
b = 200;

这个样子会直接被别人鄙视

其实这是一个脑筋急转弯的题目,直接像上面这样把一个基本数据类型的变量,作为形参传入函数,等于是直接把值赋给了函数中的实参,改变函数中的实参并不会影响主函数中a和b的值,在method()方法调用完之后,方法中的实参a和b就出栈了,此时在主函数输出的仍然是10和20。

方法一:

机智的方法,调用完method()方法之后就直接退出程序,不让他执行主函数中的print方法。

1
2
3
4
5
6
7
static void method(int a,int b){
a = 100;
b = 200;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.exit(0);
}

方法二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void method(int a,int b){
PrintStream ps = new PrintStream(System.out){
@Override
public void println(String x){
if("a = 10".equals(x)){
x = "a = 100";
}else if("b = 10".equals(x)){
x = "b = 200";
}
super.println(x);
}
};
System.setOut(ps);
}

这种方法用的是重写,当要调用println()这个方法分时候不是调用Java库中的println()方法,而是调用这里自己写的这个,就把要输出的“a = 10”替换成了”a = 100”。

第二题(微软面试题)

定义一个int型的数组: int[] arr = new int]{12,3,3,34,56,77,432};让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值。遍历新的数组。

这个题其实很简单,但是一不小心就会出错,比如:

1
2
for(int i = 0;i < arr.length;i++)
arr[i] = arr[i]/arr[0];

自己一顿操作之后以为稳了,实际上结果和原数组是一样的。这样从前面向后面遍历,数组第一个值在第一次就变成1了,之后每次除的arr[0]都是1,所以后面的值都没有发生变化。

所以简单的题不要掉以轻心。

正确的写法很简单也不止一种方法,可以从后向前遍历数组,也可以把数组的第一个值赋给一个临时变量,后面的数都除以这个临时变量。

第三题

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {

int[] arr1 = new int[]{1,2,3};
System.out.println(arr1);

char[] arr2 = new char[]{'a','b','c'};
System.out.println(arr2);
}
}

问输出的分别是什么?

正确答案是arr1输出的是地址值,arr2输出的是abc。

这其实考的是一个很细的知识点,了解过后就会感觉这个题很low,简直是在是在侮辱自己的智商,不了解的话可能就认为两个都是输出一个地址值。

这里涉及到了Java中方法的重载,同一个函数名,但是传的参数个数或者参数类型不同的话,他调的方法是不一样的。

第一个整型的数组,传入的是object类型,调用的是:

1
2
3
4
5
6
7
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}

第二个字符型的数组,传入的是char型的数组,调用的是:

1
2
3
4
5
6
public void println(char x[]) {
synchronized (this) {
print(x);
newLine();
}
}

第四题

如下两个题目输出结果相同吗?各是什么:

1
2
3
4
5
6
7
8
9
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);

Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);

正确答案:

o1输出的是1.0,o2输出的是1

这个题是看似在考Object类中的方法,但是实际上,这里的三元运算符涉及到一个自动类型提升的问题

(表达式1)?(表达式2):(表达式3)

三元运算的最后结果是这三个表达式中的类型“最高”的一种,在计算的过程个中会有自动类型提升

第五题

1
2
3
4
5
6
7
8
9
10
11
public void method1() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//
Integer x = 128;
Integer y = 128;
System.out.println(x == y);//
}

第一个输出为false,第二个输出为true,第三个输出为false。

Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在 -128127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率。

Integer类中的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;

cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);

// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}