每一秒钟的时间都值得铭记

0%

Java位运算,Int类型存储用户的登录足迹

今天接到一家公司的面试邀请,于是我来到了这家公司,前台的小姐姐面带微笑地把我请进会议室,等待了一会,一位面试官走了进来……

在进行了简单的自我介绍之后,面试官开始发问了……

面试官:你好,请你使用最少的存储空间,记录一个用户在一个月内的登录记录,只需要知道用户在某一日是否登录即可。

我(略作沉思):好的,我们可以建立一张登录日志表,在用户登录的时候,记录一条登录日志数据,这张表和用户表是一对多的关系,有用户主键、登录类型、登录时间等等,如果有需要,我们还可以记录用户的登录 IP、登录国家、城市等等信息……

面试官(面无表情):……好的,请你回去等我们的通知吧……

我:……开玩笑的,既然要使用最少的存储空间来实现这个需求,使用传统的数据库记录登录日志的方式自然是难以达到这个条件的,所以我们需要打破传统的存储方式来实现这个需求。

面试官(略有兴趣):哦,那你要怎么实现呢?

我:总所周知,在 Java 中,一个 int 类型所占的内存空间是 4 个字节,而一个字节是 8 个 bit,所以一个 int 类型的数据,所占用的内存空间是 32 个 bit 位,而我的想法就是,使用一个 int 类型的数据,也就是 32 个 bit 位记录用户在一个月内的登录记录。

面试官(点了点头):32 个 bit 位,这个存储空间确实非常少,但是具体要怎么实现呢?你详细说说。

我:我之前也说了,一个 int 类型的数据,占用的内存空间是 32 个 bit 位,而 Java 中的 int 是一个有符号位的数据,除去最高位的符号位之外,在 Java 中一个 int 类型的数据,能够表达状态的一共有 31 个 bit 位。例如,一个值为 0 的 int 类型数据,转换为二进制的 bit 位,显示为 00000000 00000000 00000000 00000000

面试官满意地点了点头……

我:一个 int 类型的 bit 为可以有 0 和 1 两个状态,而且恰好有 31 个 bit 位可用,我们完全可以使用这 31 个 bit 位来记录用户当日是否登录。比如一个用户在 3 号登录了,使用 bit 位表示为: 00000000 00000000 00000000 00000100 。而后这个用户在 5 号也登录,使用 bit 位可以表示为: 00000000 00000000 00000000 00010100 。依次类推,一个月最多也就 31 天,假如一个用户在一个大月中每天都登录,使用 bit 位可以表示为: 01111111 11111111 11111111 11111111 。最后,我们将这个二进制的 bit 数据转换为 int 类型即可。

面试官:思路不错,但是具体要怎么实现呢?如果将一个 int 类型的数据转换为二进制的 bit 位数据,具体的算法实现会不会非常麻烦呢?程序的执行效率会不会很慢呢?

我(面带自信):我的实现很简单,而且程序的执行效率也非常快,甚至要比 Java 中的其他运算都要快!

面试官:哦……

我:我的实现方式,就是使用 Java 中的位运算来实现,使用位运算,不仅实现简单,而且运行效率远比其他符号运算快!

面试官(递过来一张纸):请你在草稿纸上简单实现一下吧。

我:……

我:首先定义一个私有的 int 类型的数据。

1
private static int login = 0;

我:其次,我们需要两个公有的方法,用来操作这个 int 类型的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void setBit(int bitIndex) {
if (bitIndex < 0 || bitIndex > 30) {
throw new IndexOutOfBoundsException("超过 int 类型 bit 位的有效范围");
}
login |= 1 << bitIndex;
}

public static boolean getBit(int bitIndex) {
if (bitIndex < 0 || bitIndex > 30) {
throw new IndexOutOfBoundsException("超过 int 类型 bit 位的有效范围");
}
return (login & 1 << bitIndex) != 0;
}

我:最后,我们可以测试一下这个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
setBit(0);
setBit(3);
setBit(4);
setBit(16);
setBit(30);
System.out.println(Integer.toBinaryString(login)); // 1000000 00000001 00000000 00011001
System.out.println(getBit(0)); // true
System.out.println(getBit(1)); // false
System.out.println(getBit(2)); // false
System.out.println(getBit(3)); // true
System.out.println(getBit(30)); // true
}

我:在这段代码中,我没有对日期进行一个真实数据的维护,比如 1 号对应的是 0 位的 bit 位,31 号对应的是 30 位的 bit 位,所以在正式使用的时候,需要手动对真实的日期数据进行 -1 维护。

面试官(面露微笑):精彩!精彩啊!很好,我们公司就需要你这也的人才,明天来我们公司报道吧!

我(激动):好的,请问我的薪资是……

面试官(沉吟片刻):就 3k 吧。

我:……&#¥$@@*&^%……

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------这是我的底线^_^-------------