java面试题(基础)

点赞关注+收藏,万分感谢!!

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():写入文件。

  • 21
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值