char 变量能不能存贮一个中文汉字?为什么?
char 变量可以存贮一个汉字,因为 Java 中使用的默认编码是 Unicode ,一个 char 类型占 2 个字节(16 bit),一个汉字是2个字节,所以放一个中文是没问题的。
jdk与jre的区别是什么?
jdk是java开发包,提供了java的开发环境和运行环境。而jre仅是java的运行环境,jdk包含jre以及其他编译工具和分析调试工具
Comparable 和 Comparator 有哪些区别?
•Comparable 位于 java.lang 包下,而 Comparator 位于 java.util 包下;
•Comparable 在排序类的内部实现,而 Comparator 在排序类的外部实现;
•Comparable 需要重写 CompareTo() 方法,而 Comparator 需要重写 Compare() 方法;
== 和 equals 的区别是什么?
双等于号对于基本类型,两者比较的是值,而对于引用类型,对比的是,其引用是否相同
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较
final 在 java 中有什么作用??
final 修饰类,类不可以被继承。
final 修饰的方法不可以被重写
final 修饰的量是常量。必须初始化且不能被修改
String 属于基础的数据类型吗??
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而
String 属于对象
为什么 string 要设计成不可变??
(1) 节省空间:在 java 中,将字符串常量存储在字符串常量池中,这样这些字符串方便被共享,可以节省空间,同时防止其他线程修改该字符串,string 设计为不可变
(2) 提高效率,线程安全:正是由于 string 会被不同用户共享,在多线程编程时,在多线程共享string 时,因为 string 不可变所以 string 是线程安全且省略了同步的过程会显著提高效率。
String、StringBuffer、StringBuilder 的区别?
可变性: String 为字符串常量是不可变对象,StringBuffer 与 StringBuilder 为字符串变量是可变对象;
性能: String 它的底层是一个用 final 修饰的字符数组,每次修改相当于生成一个新对象,因此性能最低;StringBuffer 和 StringBuilder 底层使用的是没有用 final 修饰的字符数组 char[],所以在做字符串拼接的时候就在原来的内存上进行拼接,不会浪费内存空间。但是 StringBuffer 不同与StringBuilder 使用 synchronized 来保证线程安全,但两者性能均优于 String。;
java 中 IO 流分为几种?
主要分为输入输出流。字节流和字符流。字节流按八位传输。以字节为单位。进行输入输出。字符流按
16 位进行传输。以字符为单位进行输入输出。分别来看字符流(Reader、Writer)和字节流(InputStream、OutputStream)的使用。
① Writer 使用
Writer 可用来写入文件,请参考以下代码:
// 给指定目录下的文件追加信息
Writer writer = new FileWriter("d:\\io.txt",true);
writer.append("老王");
writer.close();
这几行简单的代码就可以实现把信息 老王 追加到 d:\\io.txt 的文件下,参数二表示的是覆盖文字还是追加文字。
② Reader 使用
Reader 可用来读取文件,请参考以下代码:
Reader reader = new FileReader("d:\\io.txt");
BufferedReader bufferedReader = new BufferedReader(reader);
String str = null;
// 逐行读取信息
while (null != (str = bufferedReader.readLine())) {
System.out.println(str);
}
bufferedReader.close();
reader.close();
③ InputStream 使用
InputStream 可用来读取文件,请参考以下代码:
InputStream inputStream = new FileInputStream(new File("d:\\io.txt"));
byte[] bytes = new byte[inputStream.available()];
// 读取到 byte 数组
inputStream.read(bytes);
// 内容转换为字符串
String content = new String(bytes, "UTF-8");
inputStream.close();
④ OutputStream 使用
OutputStream 可用来写入文件,请参考以下代码:
OutputStream outputStream = new FileOutputStream(new File("d:\\io.txt"),true);
outputStream.write("老王".getBytes());
outputStream.close();
同步与异步,阻塞与非阻塞
- 同步和异步指的是:当前线程是否需要等待方法调用执行完毕。
比如你调用一个搬运一百块石头的方法:
同步指的是调用这个方法,你的线程需要等待这一百块石头搬完,然后得到搬完了的结果,接着
再继续执行剩下的代码逻辑。
异步指的是调用这个方法,立马就直接返回,不必等候这一百块石头还未搬完,可以立马执行后
面的代码逻辑,然后利用回调(这里也能体现了回调函数的应用场景)或者事件通知的方式得到
石头已经搬完的结果 - 阻塞和非阻塞指的是:当前接口数据还未准备就绪时,线程是否被阻塞挂起。
何为阻塞挂起?就是当前线程还处于 CPU 时间片当中,调用了阻塞的方法,由于数据未准备就
绪,则时间片还未到就让出 CPU。
所以阻塞和同步看起来都是等,但是本质上它们不一样,同步的时候可没有让出 CPU。
而非阻塞就是当前接口数据还未准备就绪时,线程不会被阻塞挂起,可以不断轮询请求接口,看
看数据是否已经准备就绪。 - 至此我们可以得到一个结论:
同步, 异步指:当数据还未处理完成时,代码的逻辑处理方式不同。
阻塞, 非阻塞指:当数据还未处理完成时 (未就绪),线程的状态。所以同步, 异步其实是处于框架
这种高层次维度来看待的,而阻塞与非阻塞往往针对底层的系统调用方面来抉择,也就是说两者
是从不同维度来考虑的。
同步与异步,阻塞与非阻塞 IO
-
前提:程序和硬件之间隔了个操作系统,而为了安全考虑,Linux 系统分了:用户态和内核态
在这个前提下,我们再明确 I/O 操作有两个步骤:1.发起 I/O 请求 2.实际 I/O 读写(即数据从内核缓存拷贝到用户空间). -
阻塞 I/O 和非阻塞 I/O。按照上文,其实指的就是用户线程是否被阻塞,这里指代的步骤 1
(发起 I/O 请求)。 -
阻塞 I/O,指用户线程发起 I/O 请求的时候,如果数据还未准备就绪(例如暂无网络数据接 收),就会阻塞当前线程,让出 CPU。
-
非阻塞 I/O,指用户线程发起 I/O 请求的时候,如果数据还未准备就绪(例如暂无网络数据
接收),也不会阻塞当前线程,可以继续执行后续的任务。可以发现,这里的阻塞和非阻塞其实 是指用户线程是否会被阻塞。 -
同步 I/O 和异步 I/O。按照上文,我们可以得知这就是根据 I/O 响应方式不同而划分的。
-
同步 I/O,指用户线程发起 I/O 请求的时候,数据是有的,那么将进行步骤 2(实际 I/O 读
写,即数据从内核缓存拷贝到用户空间),这个过程用户线程是要等待着拷贝完成。 -
异步 I/O,指用户线程发起 I/O 请求的时候,数据是有的,那么将进行步骤 2(实际 I/O 读
写,即数据从内核缓存拷贝到用户空间),拷贝的过程中不需要用户线程等待,用户线程可以去
执行其它逻辑,等内核将数据从内核空间拷贝到用户空间后,用户线程会得到一个“通知”。再 仔细思考下,在 I/O场景下同步和异步说的其实是内核的实现,因为拷贝的执行者是内核,一种是同步将数据拷贝到用户空间,用户线程是需要等着的。一个是通过异步的方式,用户线程不 用等,在拷贝完之后,内核会调用指定的回调函数。
我再简单的总结一下,关于 I/O 的阻塞、非阻塞、同步、异步:
阻塞和非阻塞指的是发起 I/O 请求后,用户线程状态的不同,阻塞 I/O 在数据未准备就绪的
时候会阻塞当前用户线程,而非阻塞 I/O 会立马返回一个错误,不会阻塞当前用户线程。同步和
异步是指,内核的 I/O 拷贝实现,当数据准备就绪后,需要将内核空间的数据拷贝至用户空间,
如果是同步 I/O 那么用户线程会等待拷贝的完成,而异步 I/O 则这个拷贝过程用户线程该干嘛可
以去干吗,当内核拷贝完毕之后会“通知”用户线程。
BIO,NIO,AIO
BIO: 同步阻塞
NIO:同步非阻塞
AIO:异步非阻塞
异常处理
throw 和 throws 的区别?
throws 用来声明一个方法可能抛出的所有异常,表示谁调用都要使用 try-catch 进行异常处理而
throw 则是直接抛出一个具体异常
final、finally、finalize 有什么区别?
final 可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被
重写、修饰变量表示该变量是一个常量不能被重新赋值。
在 try-catch 中不管有没有异常都要执行 finally 中的内容
finalize 属于所有类父类 Object 类的方法,该方法一般由垃圾回收器执行,当调用 system.gc()
时由垃圾回收器调用 finalize 执行
try-catch-finally 中哪个部分可以省略??
可以省略 catch 或者 finally。catch 和 finally 不可以同时省略。
原因:try 可以自己处理运行异常,try+catch 可以处理运行时 + 普通异常,当我们处理普通异常
省略 catch 编译不通过会报错但是当我们处理运行时异常则可以直接使用 try.
注:如果 catch 中 return 了,finally 会在 return 前执行
java 泛型
使用了迭代器就可以不用关注容器的内部细节,用同样的方式遍历不同类型的容器。(泛型可以修饰
类、方法、接口、变量。)
List<Object> 和 List<?> 有什么区别?
答:List<?> 可以容纳任意类型,只不过 List<?> 被赋值之后,就不允许添加和修改操作了;而
List<Object> 和 List<?> 不同的是它在赋值之后,可以进行添加和修改操作
List 和 List<Object> 的区别是什么?
答:List 和 List<Object> 都能存储任意类型的数据,但 List 和 List<Object> 的唯一区别就是,List不会触发编译器的类型安全检查,比如把 List<String> 赋值给 List 是没有任何问题的,但赋值给List<Object> 就不行
泛型的工作原理是什么?为什么要有类型擦除??
答:泛型是通过类型擦除来实现的,类型擦除指的是编译器在编译时,会擦除了所有类型相关的信息,比如 List 在编译后就会变成 List 类型,这样做的目的就是确保能和 Java 5 之前的版本(二进制类库)进行兼容。