32. int和Integer的区别
Integer是int的包装类型,在拆箱和装箱中,二者自动转换。int是基本类型,直接存数值;而integer是对象,用一个引用指向这个对象。
由于Integer是一个对象,在JVM中对象需要一定的数据结构进行描述,相比int而言,其占用的内存更大一些。
33. String s = new String("abc") 创建了几个String对象
一个或者两个,如果常量池中已经存在"abc",则只创建一个,否则创建两个
34. 你对String对象的intern()熟悉嘛?
String中的intern()是个Native方法,他会首先从常量池中查找是否存在该常量的字符串,若不存在则在常量池中创建,否则直接返回常量池中已经的字符串的引用。比如:
String s1="aa"; String s2=s1.intern(); System.out.print(s1==s2); 复制代码
上述代码将返回true。因为在"aa"会在编译阶段确定下来,并放置在JVM的字符串常量池中,因此最终s1和s2引用的是同一个字符串常量对象。请看String中intern方法的注释。
35. String类的常用方法都有哪些
- indexOf() : 返回指定字符的索引。
- charAt() : 返回指定索引处的字符。
- replace() : 字符串替换。
- trim() : 去除字符串两端空白。
- split() : 分割字符串,返回一个分割的字符串数组。
- getBytes() : 返回字符串的byte类型数组。
- length() : 返回字符串长度。
- toLowerCase() : 将字符串转成小写字母。
- toUpperCase() : 将字符串转成大写字母。
- substring() : 截取字符转。
- equals() : 字符串比较。
36. Files的常用方法有哪些
- Files.exists():检测文件路径是否存在。
- Files.createFile():创建文件。Files.createDirectory():创建文件夹。
- Files.delete():删除一个文件或目录。
- Files.copy():复制文件。
- Files.move():移动文件。
- Files.size():查看文件个数。
- Files.read():读取文件。
- Files.write():写入文件。
37. Java IO与NIO的区别
NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
38. 说说Java中IO流
Java中IO流分为几种
- 按照流的流向分,可以分为输入流和输出流;
- 按照操作单元划分,可以划分为字节流和字符流;
- 按照流的角色划分为节点流和处理流。
Java Io 流共涉及 40 多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java IO流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
- InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
- OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
39. Java反射的作用原理
1.定义
反射机制是在运行时,对于任意一个类,都能都知道这个类的所有属性和方法;对于任意一个对象,都能够在调用它的任意一个方法。在Java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
这种动态获取的信息以及动态调用对象的方法的功能成为Java语言的反射机制
2. 哪里会用到反射机制
JDBC就是典型的反射机制。
40. 奇葩面试题
1. 第一道
以下Java程序打印了什么?
public class Test { public static void main(String[] args){ System.out.println(Math.min(Double.MIN_VALUE, 0.0d)); } } 复制代码
不像整数,其中 MINVALUE 为负, Double 的 MAXVALUE 和 MIN_VALUE 都是正数。Double.MINVALUE 是 2 ^( - 1074) , Double 常数,其大小是所有的 Double 值当中最小。因此,与明显的答案不同,此程序将打印 0.0 ,因为 Double.MINVALUE 大于0。
public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324 复制代码
向Java开发人员提出了这个问题,他们有3至5年的经验,令人惊讶的是,近70%的候选人错了。
2. 第二道
如果在try或catch块上放置return语句或System.exit()会发生什么?最后会阻止执行嘛?
这是一个非常流行的棘手的 Java 问题,它很棘手,因为许多程序员认为无论如何,但fifinally块将始终执行。这个问题通过在try或catch块中放置一个 return 语句或从 try 或 catch 块调用System.exit() 来挑战该概念。在Java中回答这个棘手的问题是,即使你在try块或catch块中放入一个 return 语句, finally 块也会执行,但是如果你从 try 或 catch 块调用 System.exit() ,最后块将无法运行。
3. 第三道
你可以在Java中覆盖私有活静态方法?
如果要在Java中提出技巧问题,方法覆盖是一个很好的主题。无论如何,你不能在Java中覆盖私有或静态方法,如果你在子类中创建一个具有相同返回类型和相同方法参数的类似方法,那么它将隐藏超类方法,这称为方法隐藏。类似地,您不能覆盖子类中的私有方法,因为它在那里不可访问,您要做的是在子类中创建另一个具有相同名称的私有方法。
4. 第四道
表达式1.0/0.0将返回什么?他会抛出异常吗?任何编译时错误?
虽然 Java 开发人员知道双原语类型和 Double 类,但在进行浮点运算时,他们没有足够重视Double.INFINITY , NaN 和 -0.0 以及其他规则来控制涉及它们的算术计算。这个问题的简单答案是它不会抛出ArithmeticExcpetion 并返回 Double.INFINITY 。
另外,请注意,即使x本身是NaN,比较 x == Double.NaN 也始终求值为false。要测试x是否为NaN ,应该使用方法调用 Double.isNaN(x) 检查给定的数字是否为 NaN 。如果您了解 SQL ,那么非常接近`NULL。
5. 第五道
Java是否支持多重继承嘛?
如果C ++可以支持直接的多重继承,那么为什么Java不是 Interviewer 经常给出的参数。这个问题的答案比它看起来更加微妙,因为Java通过允许接口扩展其他接口来支持Type的多个继承,Java不支持的是多个实现继承。由于现在Java 8的默认方法提供了Java也存在多种行为继承,因此这种区别也变得模糊。
6. 第六道
以下Java程序打印了什么
public class Test { public static void main(String[] args) throws Exception { char[] chars = new char[] {'\u0097'}; String str = new String(chars); byte[] bytes = str.getBytes(); System.out.println(Arrays.toString(bytes)); } } 复制代码
这个问题的要点在于字符编码以及字符串到字节数组转换的工作原理。在这个程序中,我们首先从一个字符数组创建一个String,它只有一个字符 '\ u0097' ,之后我们从该String获取字节数组并打印该字节。由于 \ u0097 在字节基本类型的8位范围内,因此猜测 str.getBytes() 调用将返回包含一个值为 -105 ((byte)0x97 )的元素的字节数组是合理的。
然而,这不是程序打印的,这就是为什么这个问题很棘手。事实上,程序的输出是依赖于操作系统和语言环的。在具有美国语言环境的 Windows XP 上,上述程序打印[63],如果在Linux或Solaris 上运行此程序,则会得到不同的值。
要正确回答这个问题,您需要了解Unicode字符在Java字符串值和Java字符串中的表示方式,以及字符编码在 String.getBytes() 中的作用。
简单来说,将字符串转换为字节数组,Java遍历字符串表示的所有字符,并将每个字符转换为多个字节,最后将字节放在一起。将每个Unicode字符映射到字节数组的规则称为字符编码。因此,如果在编码和解码期间不使用相同的字符编码,则检索到的值可能不正确。当我们调用str.getBytes() 而不指定字符编码方案时,JVM使用平台的默认字符编码来完成工作。
默认编码方案是操作系统和区域设置相关。在Linux上,它是 UTF-8 ,在Windows上具有美国语言环境,默认编码为 Cp1252 。这解释了我们在具有美国语言环境的Windows机器上运行此程序所获得的输出。无论使用哪种字符编码方案,Java总是将编码未识别的 Unicode 字符转换为63,这表示所有编码中的字符 U + 003F 。
7. 第七道
以下在Java中实现compareTo()方法有什么问题
public int compareTo(Object o){ Employee emp = (Employee) o; //id为int类型 return this.id - emp.id; } 复制代码
其中id是整数。 好吧,在你保证id总是正面之前,这个Java问题中的三个没有错。当你无法保证id为正或负时,这个Java问题变得棘手。棘手的部分是,如果id变为负数,则减法可能会溢出并产生不正确的结果。
8. 第八道
你如何确保N线程可以在没有死锁的情况下访问N个资源?
如果您不熟悉编写多线程代码,那么这对您来说是一个非常棘手的问题。即使对于没有真正面临死锁和竞争条件的经验丰富的高级程序员来说,这个Java问题也很棘手。这里的关键点是排序,如果您按特定顺序获取资源并以相反的顺序释放资源,则可以防止死锁。
考虑以下Java代码片段,它初始化两个变量并且两者都不是易失性的,并且两个线程T1和T2正在修改这些值,如下所示,两者都不同步
int x = 0; boolean bExit = false; Thread 1 (not synchronized) x = 1; bExit = true; Thread 2 (not synchronized) if (bExit == true) System.out.println("x=" + x); 复制代码
这个问题的答案是肯定的,线程T2可能会打印 x = 0 。为什么?因为没有对编译器的任何指令,例如synchronized或volatile, bExit = true 可能在编译器重新排序中在 x = 1 之前出现。此外, x =1 可能在线程2中不可见,因此线程2将加载x = 0。现在,你如何解决它?
向几个程序员提出这个问题时,他们的回答不同,一个人建议让两个线程在一个共同的互斥锁上同步,另一个人说这两个变量都是易变的。两者都是正确的,因为它会阻止重新排序并保证可见性。但最好的答案是你只需要使 bExit 成为易失性,然后线程2只能打印“ x = 1 ”。x不需要是volatile ,因为 当 bExit 是volatile 时, 不能在 bExit = true 之后重新排序x。