点赞关注+收藏,万分感谢!!
1、JDK 和 JRE 有什么区别?
JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,Java运行环境,为 Java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。
简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需要安装 JDK。
2、== 和 equals 的区别是什么?
对于基本类型和引用类型 == 的作用效果是不同的
基本类型:比较的是值是否相同;
引用类型:比较的是引用(内存地址值)是否相同;
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。
String 重写了 Object 的 equals 方法,把引用比较改成了值比较。
总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;
而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
3、 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
不对,两个对象的 hashCode() 相同,equals() 不一定 true。
因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
4、 final 在 Java 中有什么作用?
final 修饰的类叫最终类,该类不能被继承。
final 修饰的方法不能被重写。
final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
final 修饰的常量名称,一般都有书写规范,所有字母都大写,每个单词间用下划线衔接。
基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。
引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改。
5、Java 中 Math 的常用方法?
public class Test { public static void main(String[] args) { //1.abs 取绝对值 System.out.println("-9.9的绝对值:" + Math.abs(-9.9)); //2.pow 求幂 System.out.println("2的3次方:" + Math.pow(2,3)); //3.ceil 向上取整 System.out.println("6.6向上取整:" + Math.ceil(6.6)); //4.floor 向下取整 System.out.println("6.6向下取整:" + Math.floor(6.6)); //5.round 四舍五入 System.out.println("7.5四舍五入:" + Math.round(7.5)); //6.sqrt 开平方 System.out.println("9开平方 :" + Math.sqrt(9)); //7.random 获取随机数,[0,1) System.out.println("获取随机数:" + Math.random()); /** * ps.怎么获取范围在[a,b)的随机数呢?设我们的随机数为x * a <= x < b * a + 0 <= x < a + b - a * so x = a + Math.random() * (b-a) 即 区间左端点 + random() * 区间长度 */ for(int i = 0; i < 5; i++){ //比如输出[4-9)之间的随机数 System.out.println((int)(4 + Math.random() * 5)); } //8.max 求两数最大值 System.out.println("求77和88中较大的一个:" + Math.max(77,88)); //9.min 求两数最小值 System.out.println("求77和88中较小的一个:" + Math.min(77,88)); } }
6、String 属于基础的数据类型吗?
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。
7、Java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的(synchronized),而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
8、String str="i"与 String str=new String("i")一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。
9、如何将字符串反转?
使用 StringBuilder 或者 StringBuffer 的 reverse() 方法。
10、String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
11、抽象类必须要有抽象方法吗?
不需要,抽象类不一定非要有抽象方法。
12、普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。
13、抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,编辑器也会提示错误信息:
14、接口和抽象类有什么区别?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
(1)public:可以被所有其他类所访问。
(2)private:只能被自己访问和修改。
(3)protected:自身,子类及同一个包中类可以访问。
(4)default(默认):同一包中的类可以访问,声明时没有加修饰符,认为是friendly。
15、Java 中 IO 流分为几种?
按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。
16、BIO、NIO、AIO 有什么区别?
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
传统的 java.io 包,它基于流模型实现,提供了我们最熟知的一些 IO 功能,比如 File 抽象、输入输出流等。交互方式是同步、阻塞的方式,也就是说,在读取输入流或者写入输出流时,在读、写动作完成之前,线程会一直阻塞在那里,它们之间的调用是可靠的线性顺序。java.io 包的好处是代码比较简单、直观,缺点则是 IO 效率和扩展性存在局限性,容易成为应用性能的瓶颈。很多时候,人们也把 java.net 下面提供的部分网络 API,比如 Socket、ServerSocket、HttpURLConnection 也归类到同步阻塞 IO 类库,因为网络通信同样是 IO 行为。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
在 Java 1.4 中引入了 NIO 框架(java.nio 包),提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层的高性能数据操作方式。
这里的核心就是非阻塞,selector一个线程就可以不停轮询channel,所有客户端请求都不会阻塞,最多就是等待下一轮的轮询。
NIO--优化BIO的核心
一个客户端并不是时时刻刻都有数据进行交互,所以更没有必要死耗着一个线程不放,所以客户端选择了让线程歇一歇,只有客户端有相应的操作的时候才发起通知,再创建一个线程来处理请求。
实现过程:
- 首先,通过 Selector.open() 创建一个 Selector,作为类似调度员的角色。
- 然后,创建一个 ServerSocketChannel,并且向 Selector 注册,通过指定 SelectionKey.OP_ACCEPT,告诉调度员,它关注的是新的连接请求。注意,为什么我们要明确配置非阻塞模式呢?这是因为阻塞模式下,注册操作是不允许的,会抛出 IllegalBlockingModeException 异常。
- Selector 阻塞在 select 操作,当有 Channel 发生接入请求,就会被唤醒。
- 在 sayHelloWorld 方法中,通过 SocketChannel 和 Buffer 进行数据操作,在本例中是发送了一段字符串。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
在 Java 7 中,NIO 有了进一步的改进,也就是 NIO 2,引入了异步非阻塞 IO 方式,也有很多人叫它 AIO(Asynchronous IO)。异步 IO 操作基于事件和回调机制,可以简单理解为,应用操作直接返回,而不会阻塞在那里,当后台处理完成,操作系统会通知相应线程进行后续工作。
JDK7中的Java AIO新增的类和接口主要有:
AsynchronousServerSocketChannel ,对应于BIO中的 ServerSocket和NIO中的ServerSocketChannel,用于server端的网络程序。
AsynchronousSocketChannel,对应于BIO中的Socket和NIO中的SocketChannel,用于client端的网络程序。
CompletionHandler,回调接口,在socket进行accept/connect/read/write等操作时,可以传入一个CompletionHandler的实现,操作执行完毕后,会调用注册的CompletionHandler。
void completed(V result, A attachment); //成功回调
void failed(Throwable exc, A attachment); //失败回调
除了CompletionHandler这种回调方式,AIO中还支持返回Future对象,使用Future来设定回调操作。
AIO基于Proactor模型实现,分为发送请求和读取数据两个步骤:
发送请求:处理每个连接发送过来的请求。
- 每个请求都会绑定一个Buffer;
- 通知操作系统去完成异步的读(这个时间你就可以去做其他的事情);
- 调用你的接口;
- 返回异步读完的数据。
读取数据:将数据往回写。
- 一个Buffer,让操作系统去完成写。
发送请求和读取数据的主要区别在于:
- 将数据写入的缓冲区后,剩下的交给操作系统去完成;
- 操作系统写回数据也是一样,写到Buffer里面,完成后再通知客户端来进行读取数据。
3个模型的一些问题
同步阻塞--为什么说BIO是同步阻塞的呢?
针对磁盘文件读写IO操作来说,因为用BIO的流读写文件,例如FileInputStrem,必须等着完成了这次IO才能返回。
同步非阻塞--为什么说NIO为啥是同步非阻塞?
因为无论多少客户端都可以接入服务端,客户端接入并不会耗费一个线程,只会创建一个连接,然后注册到selector上去,一个selector线程不断的轮询所有的socket连接,发现有事件了就通知你,然后你就启动一个线程处理一个请求即可,这个过程的话就是非阻塞的。
但是这个处理的过程中,你还是要先读取数据,处理,再返回的,这是个同步的过程。
异步非阻塞--为什么说AIO是异步非阻塞?
当基于AIO的api去读写文件时,发起一个请求之后,等读写完成后, 操作系统会来回调你的接口, 告诉你操作完成。在这期间不需要等待, 也不需要去轮询判断操作系统完成的状态,你可以去干其他的事情。
同步还得主动去轮询操作系统,异步就是操作系统反过来通知你,所以说 AIO就是异步非阻塞的。
17、Files的常用方法都有哪些?
Files. exists():检测文件路径是否存在。
Files. createFile():创建文件。
Files. createDirectory():创建文件夹。
Files. delete():删除一个文件或目录。
Files. copy():复制文件。
Files. move():移动文件。
Files. size():查看文件个数。
Files. read():读取文件。
Files. write():写入文件。