题目
- 有没有可能两个不相等的对象有有相同的 hashcode?
- 两个相同的对象会有不同的的 hash code 吗?
- 我们可以在 hashcode() 中使用随机数字吗?
- Java 中,Comparator 与 Comparable 有什么不同?
- 为什么在重写 equals 方法的时候需要重写 hashCode 方法?
- 在Java 程序中,我有三个 socket,我需要多少个线程来处理?
- Java 中怎么创建 ByteBuffer?
- Java 中,怎么读写 ByteBuffer ?
- Java 采用的是大端还是小端?
- ByteBuffer 中的字节序是什么?
- Java 中,直接缓冲区与非直接缓冲器有什么区别?
- Java 中的内存映射缓存区是什么?
- BIO、NIO、AIO 区别有哪些?项目中有用到吗?Netty 了解吗?
- 说出 5 条 IO 的最佳实践
答案
-
有没有可能两个不相等的对象有有相同的 hashcode?
有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等,必须有相同的 hashcode 值,但是没有关于不相等对象的任何规定。 -
两个相同的对象会有不同的的 hash code 吗?
不能,根据 hash code 的规定,这是不可能的。 -
我们可以在 hashcode() 中使用随机数字吗?
不行,因为同一对象的 hashcode 值必须是相同的。
推荐阅读Java中hashCode的作用
-
Java 中,Comparator 与 Comparable 有什么不同?
Comparable 接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序。 -
为什么在重写 equals 方法的时候需要重写 hashCode 方法?
因为有强制的规范指定需要同时重写 hashcode 与 equal 是方法,许多容器类,如 HashMap、HashSet 都依赖于 hashcode 与 equals 的规定。 -
在Java 程序中,我有三个 socket,我需要多少个线程来处理?
这个需要看你是并行处理还是串行处理了。 -
Java 中怎么创建 ByteBuffer?
byte[] bytes = new byte[10];
ByteBuffer buf = ByteBuffer.wrap(bytes);
- Java 中,怎么读写 ByteBuffer ?
写是通过put()方法,读则通过get()方法
public static void main(String[] args) {
System.out.println("-------------指定缓冲区大小---------------");
//1. 指定缓冲区大小
ByteBuffer allocate = ByteBuffer.allocate(1024);
System.out.println(allocate.position());//0
System.out.println(allocate.limit());//1024
System.out.println(allocate.capacity());//1024
//2. 向缓冲区存放五个数据
allocate.put("abcd1".getBytes());
System.out.println("-------------向缓冲区存放5个数据---------------");
System.out.println(allocate.position());//5
System.out.println(allocate.limit());//1024
System.out.println(allocate.capacity());//1024
//3. 开启读模式
allocate.flip();
try {
System.out.println("-------------开启读模式---------------");
System.out.println(allocate.position());//0
System.out.println(allocate.limit());//5
System.out.println(allocate.capacity());//1024
byte[] bytes = new byte[allocate.limit()];
allocate.get(bytes);
System.out.println(new String(bytes,0,bytes.length));//abcd1
}catch (Exception e){
e.printStackTrace();
}
//4. 开启重复度模式
allocate.rewind();
System.out.println("-------------开启重复度读模式---------------");
System.out.println(allocate.position());//0
System.out.println(allocate.limit());//5
System.out.println(allocate.capacity());//1024
byte[] bytes2 = new byte[allocate.limit()];
allocate.get(bytes2);
System.out.println(new String(bytes2,0,bytes2.length));//abcd1
// 5.clean 清空缓冲区 数据依然存在,只不过数据被遗忘
System.out.println("-------------清空缓冲区---------------");
allocate.clear();
System.out.println(allocate.position());//0
System.out.println(allocate.limit());//1024
System.out.println(allocate.capacity());//1024
System.out.println((char)allocate.get());//a
}
- Java 采用的是大端还是小端?
大端,汇编,C语言和C++是小端,因为通用CPU和单片机都是按小端设计的。 JAVA默认是大端,需要重写串行化的算法才能实现小端存储。 大端方式更容易引发内存分配不足而产生的错误,使JAVA程序的BUG能更早被发现。但是JAVA和本地语言要共享文件的话,就比较麻烦了。
- ByteBuffer 中的字节序是什么?
指的是通过order()方法来设置字节序。
字节序分为两种:
BIG-ENDIAN—-大字节序:就是最低地址存放最高有效字节。
LITTLE-ENDIAN—-小字节序:是最低地址存放最低有效字节。
java字节序:JAVA虚拟机中多字节类型数据的存放顺序,JAVA字节序也是BIG-ENDIAN。
java中转换字节序
ByteBuffer类中的order(ByteOrder bo) 方法可以设置 ByteBuffer 的字节序。
其中的ByteOrder是枚举:
ByteOrder.BIG_ENDIAN// 代表大字节序的 ByteOrder 。
ByteOrder.LITTLE_ENDIAN //代表小字节序的 ByteOrder 。
ByteOrder.nativeOrder()// 返回当前硬件平台的字节序。
- Java 中,直接缓冲区与非直接缓冲器有什么区别?
非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中,程序要执行写操作需要将JVM中缓存区拷贝到物理内存中,然后再写到物理磁盘中,反过来就是读操作,由于存在一次拷贝过程所以效率较慢
直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中,程序和物理磁盘间做读写操作的时候将不会走物理内存和JVM内存,而是直接从物理内存映射文件进行读取,效率更高。直接缓冲区于非直接相比会更加占用内存空间,而且安全性不如后者。
注:IO使用的缓存区为非直接缓冲区。
字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。
直接字节缓冲区还可以通过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建。该方法返回MappedByteBuffer 。 Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。
字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。
总结:直接缓冲区是直接建立在物理内存中,非直接缓冲区则需要在jvm和物理内存之间来回拷贝,所以直接缓冲区效率更高,但安全性不如非直接缓冲区,内存一旦被清理数据则会丢失。
注:直接缓冲区的速度大概是非直接缓冲区速度的5倍左右,关于两种缓冲区的使用代码和区别请参考本人nio与netty专栏的第一篇文章。
-
Java 中的内存映射缓存区是什么?
内存映射缓存区 -
BIO、NIO、AIO 区别有哪些?项目中有用到吗?Netty 了解吗?
Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性,有了netty NIO编程更为简便。
分布式开源框架中dubbo、Zookeeper,RocketMQ底层rpc通讯使用就是netty。游戏开发中,底层使用netty通讯。
推荐阅读:本人的NIO和Netty专栏
- 说出 5 条 IO 的最佳实践
IO 对 Java 应用的性能非常重要。理想情况下,你不应该在你应用的关键路径上避免 IO 操作。下面是一些你应该遵循的 Java IO 最佳实践:
a)使用有缓冲区的 IO 类,而不要单独读取字节或字符。
b)使用 NIO 和 NIO2
c)在 finally 块中关闭流,或者使用 try-with-resource 语句。
d)使用内存映射文件获取更快的 IO。