Java 基础部分
1. JAVA 的基本数据类型有哪些 ? String 是不是基本数据类型 ?
Java 有 8 种基本数据类型: byte int short long double float Boolean char
byte int short long 都属于整数类型.
Double float 属于浮点类型.
Boolean 为布尔类型
Char 为字符型
String 不是基本数据类型.它定义的为对象
2. 一个".java"源文件中是否可以包括多个类(不是内部类) ? 有什么限制?
可以有多个类, 但只能有一个 public 的类, 并且 public 的类名必须与文件名相一致。
3. Java 有没有 goto?
java 中的保留字, 现在没有在 java 中使用。
4. 说说&和&&的区别.
&和&&都可以用作逻辑与的运算符, 表示逻辑与(and) , 当运算符两边的表达式的结果都为 true 时, 整个运算结果才为 true, 否则, 只要有一方为 false, 则结果为 false。
&&还具有短路的功能, 即如果第一个表达式为 false, 则不再计算第二个表达式, 例如, 对于 if(str != null && !str.equals(“”))
表达式, 当 str 为 null 时, 后面的表达式不会执行, 所以不会出现 NullPointerException 如果将&&改为&, 则会抛出 NullPointerException 异常。If(x==33 & ++y>0) y
会增长,If(x==33 && ++y>0)
不会增长
&还可以用作位运算符, 当&操作符两边的表达式不是 boolean 类型时, &表示按位与操作,我们通常使用 0x0f 来与一个整数进行&运算, 来获取该整数的最低 4 个 bit 位, 例如, 0x31 & 0x0f
的结果为 0x01。
备注: 这道题先说两者的共同点, 再说出&&和&的特殊之处, 并列举一些经典的例子来表明自己理解透彻深入、 实际经验丰富。
5. 在 JAVA 中如何跳出当前的多重嵌套循环?
在 Java 中, 要想跳出多重循环, 可以在外面的循环语句前定义一个标号, 然后在里层循环体的代码中使用带有标号的 break 语句, 即可跳出外层循环。 例如,
ok:
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
System.out.println(“i=” + i + “,j=” + j);
if(j == 5) break ok;
}
}
另外, 我个人通常并不使用标号这种方式, 而是让外层的循环条件表达式的结果可以受到里层循环体代码的控制, 例如, 要在二维数组中查找到某个数字。
int arr[][] = {{1,2,3},{4,5,6,7},{9}};
boolean found = false;
for(int i=0;i<arr.length && !found;i++){
for(int j=0;j<arr[i].length;j++){
System.out.println(“i=” + i + “,j=” + j);
if(arr[i][j] == 5) {
found = true;
break;
}
}
}
6. switch 语句能否作用在 byte 上, 能否作用在 long 上, 能否作用在 String 上?
在 switch(expr1) 中, expr1 只能是一个整数表达式或者枚举常量(更大字体) , 整数表达式可以是 int 基本类型或 Integer 包装类型, 由于, byte,short,char 都可以隐含转换为 int, 所以, 这些类型以及这些类型的包装类型也是可以的。显然, long 和 String 类型都不符合 switch
的语法规定, 并且不能被隐式转换成 int 类型, 所以, 它们不能作用于 swtich 语句中。
7.short s1 = 1; s1 = s1 + 1;
有什么错? short s1 = 1; s1 += 1;
有什么错?
对于 short s1 = 1; s1 = s1 + 1;
由于s1+1
运算时会自动提升表达式的类型,所以结果是 int 型,再赋值给 short 类型 s1 时, 编译器将报告需要强制转换类型的错误。
对于short s1 = 1; s1 += 1;
由于 += 是 java 语言规定的运算符, java 编译器会对它进行特殊处理, 因此可以正确编译。
8. char 型变量中能不能存贮一个中文汉字?为什么?
char 型变量是用来存储 Unicode 编码的字符的, unicode 编码字符集中包含了汉字, 所以,char 型变量中当然可以存储汉字啦。 不过, 如果某个特殊的汉字没有被包含在 unicode 编码字符集中, 那么, 这个 char 型变量中就不能存储这个特殊汉字。 补充说明: unicode 编码占用两个字节, 所以, char 类型的变量也是占用两个字节。
9. 用最有效率的方法算出 2 乘以 8 等於几?
2 << 3,
因为将一个数左移 n 位, 就相当于乘以了 2 的 n 次方, 那么, 一个数乘以 8 只要将其左移 3位即可, 而位运算 cpu 直接支持的, 效率最高, 所以, 2 乘以 8 等於几的最效率的方法是 2 <<3。
10. 请设计一个一百亿的计算器
首先要明白这道题目的考查点是什么, 一是大家首先要对计算机原理的底层细节要清楚、 要知道加减法的位运算原理和知道计算机中的算术运算会发生越界的情况, 二是要具备一定的面向对象的设计思想。
首先, 计算机中用固定数量的几个字节来存储的数值, 所以计算机中能够表示的数值是有一定的范围的, 为了便于讲解和理解, 我们先以 byte 类型的整数为例, 它用 1 个字节进行存储, 表示的最大数值范围为-128 到+127。 -1 在内存中对应的二进制数据为 11111111, 如果两个-1 相加, 不考虑 Java 运算时的类型提升, 运算后会产生进位, 二进制结果为 1,11111110,由于进位后超过了 byte 类型的存储空间, 所以进位部分被舍弃, 即最终的结果为 11111110,也就是-2, 这正好利用溢位的方式实现了负数的运算。 -128 在内存中对应的二进制数据为10000000, 如果两个-128 相加, 不考虑 Java 运算时的类型提升, 运算后会产生进位, 二进制结果为 1,00000000, 由于进位后超过了 byte 类型的存储空间, 所以进位部分被舍弃, 即最终的结果为 00000000, 也就是 0, 这样的结果显然不是我们期望的, 这说明计算机中的算术运算是会发生越界情况的, 两个数值的运算结果不能超过计算机中的该类型的数值范围。
由于 Java 中涉及表达式运算时的类型自动提升, 我们无法用 byte 类型来做演示这种问题和现象的实验, 大家可以用下面一个使用整数做实验的例子程序体验一下:
int a = Integer.MAX_VALUE;
int b = Integer.MAX_VALUE;
int sum = a + b;
System.out.println(“a=”+a+”,b=”+b+”,sum=”+sum);
先不考虑 long 类型, 由于 int 的正数范围为 2 的 31 次方, 表示的最大数值约等于2*1000*1000*1000
, 也就是 20 亿的大小, 所以, 要实现一个一百亿的计算器, 我们得自己设计一个类可以用于表示很大的整数, 并且提供了与另外一个整数进行加减乘除的功能, 大概功能如下:
(1) 这个类内部有两个成员变量, 一个表示符号, 另一个用字节数组表示数值的二进制数
(2) 有一个构造方法, 把一个包含有多位数值的字符串转换到内部的符号和字节数组中
(3) 提供加减乘除的功能
public class BigInteger{
int sign;
byte[] val;
public Biginteger(String val){
sign = ;
val = ;
} p
public BigInteger add(BigInteger other){
}
public BigInteger subtract(BigInteger other){
}
public BigInteger multiply(BigInteger other){
}
public BigInteger divide(BigInteger other){
}
}
备注: 要想写出这个类的完整代码, 是非常复杂的, 如果有兴趣的话, 可以参看 jdk 中自带的java.math.BigInteger
类的源码。面试的人也知道谁都不可能在短时间内写出这个类的完整代码的, 他要的是你是否有这方面的概念和意识, 他最重要的还是考查你的能力, 所以, 你不要因为自己无法写出完整的最终结果就放弃答这道题, 你要做的就是你比别人写得多, 证明你比别人强, 你有这方面的思想意识就可以了, 毕竟别人可能连题目的意思都看不懂, 什么都没写, 你要敢于答这道题, 即使只答了一部分, 那也与那些什么都不懂的人区别出来,拉开了距离, 算是矮子中的高个, 机会当然就属于你了。 另外, 答案中的框架代码也很重要,体现了一些面向对象设计的功底, 特别是其中的方法命名很专业, 用的英文单词很精准, 这也是能力、 经验、 专业性、 英语水平等多个方面的体现, 会给人留下很好的印象, 在编程能力和其他方面条件差不多的情况下, 英语好除了可以使你获得更多机会外, 薪水可以高出一千元。
11. 使用 final 关键字修饰一个变量时, 是引用不能变, 还是引用的对象不能变?
使用 final 关键字修饰一个变量时, 是指引用变量不能变, 引用变量所指向的对象中的内容还是可以改变的。 例如, 对于如下语句:
final StringBuffer a=new StringBuffer("immutable");
执行如下语句将报告编译期错误:
a=new StringBuffer("");
但是, 执行如下语句则可以通过编译:
a.append(" broken!");
有人在定义方法的参数时, 可能想采用如下形式来阻止方法内部修改传进来的参数对象:
public void method(final StringBuffer param){
}
实际上, 这是办不到的, 在该方法内部仍然可以增加如下代码来修改参数对象:
param.append("a");
12. "=="和 equals 方法究竟有什么区别?
==操作符专门用来比较两个变量的值是否相等, 也就是用于比较变量所对应的内存中所存储的数值是否相同, 要比较两个基本类型的数据或两个引用变量是否相等, 只能用==操作符。
如果一个变量指向的数据是对象类型的, 那么, 这时候涉及了两块内存, 对象本身占用一块内存(堆内存) , 变量也占用一块内存, 例如 Objet obj = new Object();
变量 obj 是一个内存,new Object()
是另一个内存, 此时, 变量 obj 所对应的内存中存储的值就是对象占用的那块
内存的首地址。 对于指向对象类型的变量, 如果要比较两个变量是否指向同一个对象, 即要看这两个变量所对应的内存中的数值是否相等, 这时候就需要用==操作符进行比较。equals 方法是用于比较两个独立对象的内容是否相同, 就好比去比较两个人的长相是否相同, 它比较的两个对象是独立的。 例如, 对于下面的代码:
String a=new String("foo");
String b=new String("foo");
两条 new 语句创建了两个对象, 然后用 a,b 这两个变量分别指向了其中一个对象, 这是两个不同的对象, 它们的首地址是不同的, 即 a 和 b 中存储的数值是不相同的, 所以, 表达式a==b 将返回 false, 而这两个对象中的内容是相同的, 所以, 表达式 a.equals(b)将返回 true。在实际开发中, 我们经常要比较传递进行来的字符串内容是否等, 例如,String input = …;input.equals(“quit”)
, 许多人稍不注意就使用==进行比较了, 这是错误的, 随便从网上找几个项目实战的教学视频看看, 里面就有大量这样的错误。 记住, 字符串的比较基本上都是使用 equals 方法。
如果一个类没有自己定义 equals 方法, 那么它将继承 Object 类的 equals 方法, Object 类的equals 方法的实现代码如下:
boolean equals(Object o){
return this==o;
}
这说明, 如果一个类没有自己定义 equals 方法, 它默认的 equals 方法(从 Object 类继承的)就是使用==操作符, 也是在比较两个变量指向的对象是否是同一对象, 这时候使用 equals和使用==会得到同样的结果, 如果比较的是两个独立的对象则总返回 false。 如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同, 那么你必须覆盖 equals 方法, 由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。
13. 静态变量和实例变量的区别?
语法定义上的区别: 静态变量前要加 static 关键字, 而实例变量前则不加。程序运行时的区别: 实例变量属于某个对象的属性, 必须创建了实例对象, 其中的实例变量才会被分配空间, 才能使用这个实例变量。 静态变量不属于某个实例对象, 而是属于类, 所以也称为类变量, 只要程序加载了类的字节码, 不用创建任何实例对象, 静态变量就会被分
配空间, 静态变量就可以被使用了。 总之, 实例变量必须创建对象后才可以通过这个对象来使用, 静态变量则可以直接使用类名来引用。
例如, 对于下面的程序, 无论创建多少个实例对象, 永远都只分配了一个 staticVar 变量, 并且每创建一个实例对象, 这个 staticVar 就会加 1; 但是, 每创建一个实例对象, 就会分配一个 instanceVar, 即可能分配多个 instanceVar, 并且每个 instanceVar 的值都只自加了 1 次。
public class VariantTest{
public static int staticVar = 0;
public int instanceVar = 0;
public VariantTest(){
staticVar++;
instanceVar++;
System.out.println(“staticVar=” + staticVar + ”,instanceVar=” + instanceVar);
}
}
备
注:这个解答除了说清楚两者的区别外,最后还用一个具体的应用例子来说明两者的差异,
体现了自己有很好的解说问题和设计案例的能力, 思维敏捷, 超过一般程序员, 有写作能力!
14. 是否可从一个 static 方法内发出对非 static 方法的调用?
不可以。 因为非 static 方法是要与对象关联在一起的, 必须创建一个对象后, 才可以在该对象上进行方法调用, 而 static 方法调用时不需要创建对象, 可以直接调用。 也就是说, 当一个 static 方法被调用时, 可能还没有创建任何实例对象, 如果从一个 static 方法中发出对非static 方法的调用, 那个非 static 方法是关联到哪个对象上的呢? 这个逻辑无法成立, 所以,一个 static 方法内部发出对非 static 方法的调用。
15. Integer 与 int 的区别
int 是 java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类, Integer 是 java为 int 提供的封装类。 int 的默认值为 0, 而 Integer 的默认值为 null, 即 Integer 可以区分出未赋值和值为 0 的区别, int 则无法表达出未赋值的情况, 例如, 要想表达出没有参加考试和考试成绩为 0 的区别, 则只能使用 Integer。 在 JSP 开发中, Integer 的默认为 null, 所以用el 表达式在文本框中显示时, 值为空白字符串, 而 int 默认的默认值为 0, 所以用 el 表达式在文本框中显示时, 结果为 0, 所以, int 不适合作为 web 层的表单数据的类型。在 Hibernate 中, 如果将 OID 定义为 Integer 类型, 那么 Hibernate 就可以根据其值是否为 null而判断一个对象是否是临时的, 如果将 OID 定义为了 int 类型, 还需要在 hbm 映射文件中设置其 unsaved-value 属性为 0。另外, Integer 提供了多个与整数相关的操作方法, 例如, 将一个字符串转换成整数, Integer中还定义了表示整数的最大值和最小值的常量。
网友评论