Java中的经典问题

发布于 2024年07月15日

1. 高效的方式计算2 * 8的值

2 << 3

2. &和&&的区别?

  • 相同点:当左侧为True时,都会执行右侧的条件语句

  • 不同点:&当左侧为False时,会执行右侧的条件语句;&&当左侧为False时,则不再执行右侧条件语句

同理 | 和 || 的区别:

  • 相同点:当左侧为False时,都会执行右侧的条件语句

  • 不同点:| 当左侧为True时,会执行右侧的条件语句;|| 当左侧为True时,则不再执行右侧条件语句

3. Java开发中计算金额时使用什么数据类型?

不可以使用float和double类型,因为精度不高

可以使用BigDicimal进行替换,可以实现任意精度数据的计算

4. char型变量中能不能存储一个中文汉字,为什么?

可以,char类型使用了unicode字符集,几乎包含了世界范围所有的字符

5. 代码分析:下面代码存在问题么

short s = 1;
s = s + 1;

存在,需要强制类型转换,正确写法:

short s = 1;
s = (short)(s + 1);

6. int i=0; i=i++执行这两句化后变量 i 的值为

0

7. 如何将两个变量的值互换

//方法1:借助第三个变量
String s1 = "xzro";
String s2 = "xxxx";
String tmp = "";

tmp = s1;
s1 = s2;
s2 = tmp;

//方法二:数值运算交换
int m = 10;
int n = 20;

m = m + n;
n = m - n;
m = m - n;

//方法三:boolean
m = m ^ n;
n = m ^ n;
m = m ^ n;

8. boolean 占几个字节

编译时不谈占几个字节。

但是JVM在给boolean类型分配内存空间时,boolean类型的变量占据一个槽位(slot,等于4个字节)。

细节:true:1 false:0

拓展:在内存中,byte\short\char\boolean\int\float : 占用1个slotd

double\long :占用2个slot

9.为什么Java中0.1 + 0.2结果不是0.3?

在代码中测试0.1 + 0.2,你会惊讶的发现,结果不是0.3,而是0.3000……4。这是为什么?

几乎所有现代的编程语言都会遇到上述问题,包括 JavaScript、Ruby、Python、Swift 和 Go 等。引发这个问题的原因是,它们都采用了IEEE 754标准

IEEE是指“电气与电子工程师协会”,其在1985年发布了一个IEEE 754计算标准,根据这个标准,小数的二进制表达能够有最大的精度上限提升。但无论如何,物理边界是突破不了的,它仍然不能实现“每一个十进制小数,都对应一个二进制小数”。正因如此,产生了0.1 + 0.2不等于0.3的问题。

具体的:

整数变为二进制,能够做到“每个十进制整数都有对应的二进制数”,比如数字3,二进制就是11;再比如,数字43就是二进制101011,这个毫无争议。

对于小数,并不能做到“每个小数都有对应的二进制数字”。举例来说,二进制小数0.0001表示十进制数0.0625 (至于它是如何计算的,不用深究);二进制小数0.0010表示十进制数0.125;二进制小数0.0011表示十进制数0.1875。看,对于四位的二进制小数,二进制小数虽然是连贯的,但是十进制小数却不是连贯的。比如,你无法用四位二进制小数的形式表示0.125 ~ 0.1875之间的十进制小数。

所以在编程中,遇见小数判断相等情况,比如开发银行、交易等系统,可以采用四舍五入或者“同乘同除”等方式进行验证,避免上述问题。

10.抽象类和接口的区别

相同点:

  • 都不可以直接实例化

  • 都可以声明abstract方法

不同点:

  • 抽象类一定有构造器,但是接口没有构造器

  • 类与类之间是继承关系,类与接口是实现关系,接口与接口是多继承关系

11.HashMap和Hashtable的区别

区别

Hashtable

HashMap

数据结构

数组+链表

数组+链表+红黑树

是否可以为null

不可以为null

可以为null

hash算法

key的hashCode()

二次hash

扩容方式

容量翻倍+1

容量翻倍

线程安全

线程安全

线程不安全

12.HashSet和HashMap的区别

  1. HashSet实现的是Set接口,仅存储对象,HashMap实现的是Map接口,存储key-value值

  2. HashSet是依靠HashMap进行存储的,HashSet封装了HashMap一系列的方法,用HashMap的key存储数据,value值默认是Object,所以HashSet不允许出现重复值,判断标准与HashMap标准一样,两个元素的hashCode相等,并且equals返回值为true。

12.HashMap的在JDK1.7和JDK1.8的区别

  1. 在JDK 1.8之前,HashMap使用拉链法存储,拉链法:将数组与链接结合,如果遇到哈希冲突,直接加入链表

  2. 在JDK 1.8之后,HashMap在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为0),数组长度大于64时,将链表转换为红黑树。扩容时红黑树拆分的树节点,节点数如果小于6,将转化为链表。

13.Runnable和Callable的区别

  1. Runnable的run方法没有返回值,Callable的call方法有返回值,是个泛型,和Future、FutureTask配合可以用来异步获取执行结果

  2. Callable的call方法可以返回执行结果,需要配合FutureTask.get()获取,获取时会阻塞主进程向下执行,若不获取则不会阻塞

  3. Callable的call可以抛出异常,而Runnable的run方法只能在内部使用try-catch-finally进行处理

14.wait和sleep的区别

  • 相同点

    • wait和sleep方法都会使线程放弃CPU的使用权,进入阻塞状态

  • 不同点

    • 方法归属不同

      • sleep是Thread的方法

      • 而wait是Object的成员方法,每个对象都有

    • 醒来时机不同

      • sleep(long)和wait(long)在时间到达后都会醒来

      • wait()和wait(long)都可以使用notify进行唤醒,wait()如果不被唤醒就会一直阻塞下去

    • 锁机制不同

      • wait使用时必须先获取对象wait的锁,sleep无限制

      • wait方法执行后会释放wait的对象的锁,使其他线程可以获取CPU的执行权

      • 而sleep在synchronized中执行后不会释放对象锁,其他线程无法获取执行权



评论