前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >阿里一面-给我挖了几个陷阱。。

阿里一面-给我挖了几个陷阱。。

作者头像
千羽
发布2024-04-17 15:34:07
620
发布2024-04-17 15:34:07
举报
文章被收录于专栏:程序员千羽程序员千羽

我有个师弟在面试阿里的暑期实习,被问了一道题:2.0减去1.1等于多少?他直接回答0.9,结果面试官脸都黑了。

这个经历让我意识到在面试中,细节和对基本语法的了解非常重要。

这次面试让我意识到了一些常见的陷阱。尤其是在数值计算方面,计算机处理浮点数时可能会出现精度问题,导致结果不完全符合预期。

同时,在面试过程中,对于基本的语法和概念的掌握也是至关重要的。

所以,我们在准备面试时,一定要注重细节,牢固掌握基础知识,以避免掉入这些陷阱。

浮点数相减:2.0 - 1.1

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        System.out.println(2.0 - 1.1);
    }
}

这个2.0 - 1.1,很多人以为结果是0.9的,结果一运行才发现0.8999999999999999

这种情况是由于浮点数在计算机中的存储和表示方式导致的精度限制。

计算机在内部以二进制形式存储浮点数,而不是以十进制形式。

由于有限的存储空间和表示精度,某些十进制数可能无法精确地表示为二进制浮点数,从而导致小的舍入误差。

所以,虽然数学上2.0减去1.1等于0.9,但在计算机中,由于浮点数的存储和处理方式,得到的结果可能是一个非常接近0.9的近似值,比如0.8999999999999999。

这是浮点数运算中常见的现象,称为浮点数精度问题。

BigDecimal修正:

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        System.out.println(2.0 - 1.1);

        System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.1")));
        System.out.printf("%.1f", 2.0 - 1.1);
    }
}

找奇数

想一下这个条件:i % 2 != 1;当把1、2、3输入进去时,结果好像也对哦,但是就是少了一方面。所以答案应该是:i % 2 != 0,正负数都是可以用的了

代码语言:javascript
复制
public class Main {
    public static boolean isOdd(int i) {
        return i % 2 != 1;
    }

    public static void main(String[] args) {
        System.out.println(isOdd(1));
        System.out.println(isOdd(2));
        System.out.println(isOdd(3));
    }
}
  • isOdd(1):1除以2的余数为1,不等于1,所以返回false,打印结果为false
  • isOdd(2):2除以2的余数为0,等于1,所以返回false,打印结果为false
  • isOdd(3):3除以2的余数为1,不等于1,所以返回false,打印结果为false

长整除

咋一看以为是1000,运行之后,没想到是5

代码语言:javascript
复制
public static void main(String[] args) {
    final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
    final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
    System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}

在Java中,整数乘法可能会导致溢出,因为表达式右侧的每个数值都是int类型,而不是long类型。因此,即使最终结果赋值给了long类型的变量,但是计算过程中仍然会使用int类型进行计算,这可能导致结果溢出。

让我们来具体分析:

代码语言:javascript
复制
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;

这里的计算结果是86,400,000,000,000,它超出了int类型的范围,因此会溢出,导致结果错误。

代码语言:javascript
复制
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;

这里的计算结果是86,400,000,它仍然在int类型的范围内,没有溢出。

因此,MICROS_PER_DAY / MILLIS_PER_DAY将会产生错误的结果,因为MICROS_PER_DAY已经溢出了。要修复这个问题,你可以确保至少有一个操作数是long类型,这样计算过程中就会使用long类型进行计算,而不会发生溢出。你可以通过在数值后面加上L来将其转换为long类型。

修正后的代码应该如下所示:

代码语言:javascript
复制
public static void main(String[] args) {
    final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
    final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
    System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}

这样做之后,MICROS_PER_DAY将被计算为86,400,000,000,000,而不会溢出,结果将打印为1000

互换内容

代码语言:javascript
复制
public static void main(String[] args) {
    int x = 1984;
    int y = 2001;
    x ^= y ^= x ^= y;
    System.out.println("x= " + x + "; y= " + y);
}

这段代码展示了一个有趣的编程技巧,使用异或运算符(^)来实现变量值的交换,但是它可能会让人感到困惑。让我们来逐步分析这段代码:

代码语言:javascript
复制
int x = 1984;
int y = 2001;
x ^= y ^= x ^= y;

这里的代码是在一行中执行的,但它等价于以下步骤:

  1. 计算 x ^= y,即 x = x ^ y,结果为 x = 1984 ^ 2001 = 193.
  2. 计算 y ^= x,即 y = y ^ x,此时 x 的值已经更新为 193,结果为 y = 2001 ^ 193 = 1976.
  3. 计算 x ^= y,即 x = x ^ y,此时 y 的值已经更新为 1976,结果为 x = 193 ^ 1976 = 2185.

因此,最终的结果是 x = 2185y = 1976

所以,打印的结果将是:

代码语言:javascript
复制
x= 2185; y= 1976

虽然这段代码展示了一种有趣的技巧,但它并不易读,而且可能会使代码的含义变得模糊。在实际的编码中,应该优先选择更易读和易理解的方式来实现变量值的交换。

字符串和字符

代码语言:javascript
复制
public static void main(String[] args) {
    System.out.println("H" + "a");  //Ha
    System.out.println('H' + 'a');  //169
}

这段代码展示了字符串连接和字符相加之间的区别。

  1. System.out.println("H" + "a");:这里使用的是字符串连接操作符+,它将两个字符串连接在一起。因此,结果是字符串 "Ha"。
  2. System.out.println('H' + 'a');:这里使用的是字符相加操作符+,它会将字符的Unicode值相加。字符'H'的Unicode值是 72,字符'a'的Unicode值是 97。所以,'H' + 'a' 实际上是 72 + 97,结果是 169。然后,这个结果被当做整数类型输出。

所以,这段代码的输出是:

代码语言:javascript
复制
Ha
169

需要注意的是,字符相加操作并不会直接拼接字符,而是对字符的Unicode值进行数值相加。

字符数组

代码语言:javascript
复制
public static void main(String[] args) {
    String letters = "ABC";
    char[] numbers = {'1', '2', '3'};
    System.out.println(letters + " easy as " + numbers);
}

在这段代码中,letters 是一个字符串,numbers 是一个字符数组。当你使用 + 运算符将它们连接成一个字符串时,Java 会调用 toString() 方法将字符数组转换为字符串。由于数组没有覆盖 toString() 方法,因此会使用默认的 Object 类的实现,它返回的是对象的哈希码的十六进制表示。

所以,在执行 System.out.println(letters + " easy as " + numbers); 时,实际上发生了以下转换过程:

  1. letters 是一个字符串 "ABC"。
  2. " easy as " 是一个字符串。
  3. numbers 是一个字符数组,由于它没有覆盖 toString() 方法,所以会调用默认的 Object 类的 toString() 方法,返回的是对象的哈希码的十六进制表示。

因此,结果是 "ABC easy as [C@7852e922",其中 [C@7852e922 是字符数组的哈希码的十六进制表示。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 千羽的编程时光 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 浮点数相减:2.0 - 1.1
  • 找奇数
  • 长整除
  • 互换内容
  • 字符串和字符
  • 字符数组
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档