java面试题总结200道(一)

一边盘点之前的知识点,一边总结一些常见的面试题吧... ...

        1、JDK 和 JRE 有什么区别?

        JDK(Java SE Development Kit),Java标准的开发包,提供了编译、运行Java程序所需要的各种工具和资源,包括了Java编译器、Java运行时环境、以及常用的Java类库等。

        JRE(Java Runtime Environment),Java运行时环境,用于解释执行Java的字节码文件。普通用户只需要安装JRE来运行Java程序即可,JDk包含JRE,JDK 和 JRE 中都包含 JVM。

2.== equals 的区别是什么?

==:比较两个对象的堆内存地址,如果相等,则说明指向的是同一个对象地址的。

对于基本数据类型(byte,short,char,int,float,double,long,boolean)来说,他们是作为常量在方法区中的常量池里面以HashSet策略存储起来的,在常量池中,一个常量只会对应一个地址。

另外,对于基本数据的包装类型(Byte, Short, Character,Integer,Float, Double,Long,  Boolean)除了Float和Double之外,其他的六种都是实现了常量池的。

equals:用来比较字符串和对象数据类型(在Object类下),我们也可以重写equals方法进行对象值的比较。

3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

1.hashCode()相等的两个对象他们的equal()不一定相等。

因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠。

2.equal()相等的两个对象他们的hashCode()肯定相等。

所有对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低。所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性。

4.final java 中有什么作用?

Final修饰类

   Final修饰一个类时表示这个类不能被继承,此时类中的所有方法都被隐式的指定为final方法。所以修饰类要谨慎使用。

Final修饰方法

   使用final修饰方法的作用有两个:一是把方法锁定,防止任何子类继承它以后修改方法的内容;二是效率,早期的java会把final方法转为内嵌使用,但如果方法过于庞大的话,效率提升的效果也不是很明显。

Final修饰变量

        当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。

final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值

5.java 中的 Math.round(-1.5) 等于多少?

Round()方法是向下取整,也就是+0.5再四舍五入,-1.5+0.5=-1

6.String 属于基础的数据类型吗?

String属于引用数据类型

7.java 中操作字符串都有哪些类?它们之间有什么区别?

String、StringBuffer、StringBuilder:

①这三种都是以char[ ]形式保存字符串的;

②String类型的字符串是不可变的,如果想要修改,只能new的方式新创建一个字符串;

③StringBuffer和StringBuilder是可变的字符串,可进行增删操作;

④StringBuffer中的大部分方法用synchronized修饰,是线程安全的;

⑤StringBuilder是线程不安全的,但是效率高。如果是单线程,使用StringBuilder,多线程使用StringBuffer。

8.String str="i" String str=new String(“i”)一样吗?

不一样。String str=”i”,意思是将i这个值在内存中的地址附给str,而String str1=new String(“i”)的意思是新建一个对象,将这个对象的地址附给str,因为String 是final的,所以”i”应该是放在常量池中。但是此时str1.equals(str)的结果是true。

9.如何将字符串反转?(假设我们给定的字符串为str

①利用StringBuffer或者StringBuilder中的reverse成员方法;

   Public static String reverse1(String str){

       Return new StringBuilder(str).reverse().toString();

}

②利用String的toCharArray()将字符串str先转换成char数组,然后将各个字符串拼接

Public static String reverse2(String str){

       Char[ ] chars=str.toCharArray();

       String reverses=” “;

       For(int i=chars.length-1;i>=0;i--){

       Reverses+=chars[i];

}

Return reverses;

}

③利用String的charAt()取出字符串的每一个字符;

Public static String reverse3(String str){

       String reverses=” “;

       For(int i=0;i<str.length;i++){

              Reverses=str.charAt(i)+reverses;

}

Return reverses;

}

10.String 类的常用方法都有那些?

1>length():得到一个字符串的字符个数/长度

   2>getByte():将一个字符串转换成字节数组

   3>toCharArray():将一个字符串转换成字符数组

   4>split(String): 将一个字符串按照指定内容劈开

   5>equals():判断两个字符串的内容是否一样

   6>equalslsIgnoreCase(String): 忽略太小写的比较两个字符串的内容是否一样

   7>contains(String): 判断一个字符串里面是否包含指定的内容

   8>startsWith(String): 判断一个字符串是否以指定的内容开头

   9>endsWith(String): 判断一个字符串是否以指定的内容结尾

   10>toUpperCase():将一个字符串全部转换成大写

   11>toLowerCase():将一个字符串全部转换成小写

   12>replace(String,String): 将某个内容全部替换成指定内容

   13>replaceAll(String,String): 将某个内容全部替换成指定内容,支持正则

   14>replaceFirst(String,String): 将第一次出现的某个内容替换成指定的内容

   15>substring(int): 从指定下标开始一直截取到字符串的最后

   16>substring(int,int): 从下标x截取到下标y-1对应的元素

   17>trim():去除一个字符串的前后空格

   18>charAt(int): 得到指定下标位置对应的字符

   19>indexOf(String): 得到指定内容第一次出现的下标

   20>laseIndexOf(String): 得到指定内容最后一次出现的下标

11.抽象类必须要有抽象方法吗?

不一定。用abstract关键字修饰的类是抽象类,抽象类可以没有抽象方法,但是如果一个类包含抽象方法,那么这个类一定是抽象类。抽象类是没有办法实例化的,只能通过其子类实例化。

12.普通类和抽象类有哪些区别?

①抽象类被关键字abstract修饰,不能被实例化;

②抽象类可以有抽象方法,可以不必实现,只需声明;

③含有抽象方法的类一定是抽象类;

④抽象类的子类必须实现抽象类的所有抽象方法,否则此子类也是抽象方法;

⑤抽象方法不能被private/final/static修饰;

13.抽象类能使用 final 修饰吗?

不能,用final修饰的类不能被继承和修改的,而抽象类的目的就是被继承然后重写其抽象方法。

14.接口和抽象类有什么区别?

①抽象类是被子类继承,接口是被类实现;

②抽象类里面可以声明方法,也可以实现方法,而接口只是声明方法;

③接口里面定义的变量只能是公共的静态的常量,抽象类里面的变量是普通的变量;

④接口是设计的结果,抽象类是重构的结果;

⑤抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高;

⑥抽象类主要用来抽象类别,而接口用来抽象功能;

15.java IO 流分为几种?

①按照流的流向分,可以分为输入流和输出流;

②按照操作单元分,可以分为字节流和字符流;

③按照角色可以分为节点流和处理流

Reader:字符读取

Writer:字符写入

InputStream:字节流写入

OutputStream:字节流写出

16.BIONIOAIO 有什么区别?

BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发

AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

17.Files的常用方法都有哪些?

Files.exists():检测文件路径是否存在。

Files.createFile():创建文件。

Files.createDirectory():创建文件夹。

Files.delete():删除一个文件或目录。

Files.copy():复制文件。

Files.move():移动文件。

Files.size():查看文件个数。

Files.read():读取文件。

Files.write():写入文件。

18.同步/异步,阻塞/非阻塞分别是什么?

说法一:

同步/异步关注的是消息通信机制 (synchronous communication/ asynchronous communication) 。

所谓同步,就是在发出一个调用时,在没有得到结果之前, 该调用就不返回。

异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果

阻塞/非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程

说法二:

进程间的通信是通过 send() 和 receive() 两种基本操作完成的。具体如何实现这两种基础操作,存在着不同的设计。

消息的传递有可能是**阻塞的**或**非阻塞的** -- 也被称为**同步**或**异步**的:

阻塞式发送(blocking send). 发送方进程会被一直阻塞, 直到消息被接受方进程收到。

非阻塞式发送(nonblocking send)。 发送方进程调用 send() 后, 立即就可以其他操作。

阻塞式接收(blocking receive) 接收方调用 receive() 后一直阻塞, 直到消息到达可用。

非阻塞式接受(nonblocking receive) 接收方调用 receive() 函数后, 要么得到一个有效的结果, 要么得到一个空值, 即不会被阻塞。

上述不同类型的发送方式和不同类型的接收方式,可以自由组合。

结合两种说法,自行理解同步/异步以及阻塞/非阻塞的区分。

19.java 容器都有哪些?

 

        20.Collection 和 Collections 有什么区别?

Java.util.Collection为集合接口,他提供了对集合对象进行操作的抽象的方法,为各种具体的集合提供了统一的操作。

Java.util.Collections是一个包装类,提供了大量的静态方法(对集合的搜索,排、线程安全化等),大多数方法用来处理线性表的。

        21.List、SetMap 之间的区别是什么?

HashSet基于哈希表实现,有以下特点:

     1.不允许重复

     2.允许值为null,但是只能有一个

     3.无序的。

     4.没有索引,所以不包含索引操作的方法

LinkedHashSet跟HashSet一样都是基于哈希表实现。只不过linkedHashSet在hashSet的基础上多了一个链表,这个链表就是用来维护容器中每个元素的顺序的。有以下特点:

       1.不允许重复

       2.允许值为null,但是只能有一个

       3.有序的。

       4.没有索引,所以不包含索引操作的方法

ArrayList是基于数组实现的,其特点是查询快,增删慢。查询快是因为数组的空间是连续的,查询时只要通过首地址和下标很快就能找到元素。增删慢是因为数组是不能扩容的,一旦增加或者删除元素,内部操作就是新开辟一个数组把元素copy到新的数组,老的数组等待被垃圾回收。

LinkedList是基于链表实现的。相比于ArrayList其特点是查询慢,增删快。

查询慢:因为链表在内存中开辟的空间不一定是连续的(基本上不可能是连续的)所以链表实现的方式是每个元素节点都会存放自己的地址,数据以及下一个节点的地址,这样把所有的元素连接起来。所以当要查询元素时只能一个一个的往下找,相比于数组的首地址加下标会慢上不少。

Map是双列集合的超类。也就是键值对形式。

22.HashMap Hashtable 有什么区别?

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。

另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

HashMap不能保证随着时间的推移Map中的元素次序是不变的。

23.如何决定使用 HashMap 还是 TreeMap

(1)HashMap:适用于在Map中插入、删除和定位元素。

(2)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。

(3)HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.

(4)HashMap 非线程安全 TreeMap 非线程安全

(5)HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。

24.说一下 HashMap 的实现原理?

简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

25.说一下 HashSet 的实现原理?

HashSet的实现原理总结如下:

①是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

②当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

③HashSet的其他操作都是基于HashMap的。

对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成。

  • 6
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值