Java面试题01(每次10道)

310 阅读5分钟

1、面向对象三大特征

关键字:封装、继承、多态

面向对象的三大特征分别是封装、继承和多态。那么怎么理解呢?

我们知道java中万物皆对象,既然是对象,那么肯定有属性和行为。有的属性和行为我们不希望外部调用,比如一个电脑要用主机机箱包起来,因为内部的其他部分是使用者用不到的。所以Java提供了封装机制,可以把对象封装起来,我们可以控制访问权限来指定谁可以访问和操作。

继承相当于使用了对象的公共部分。如果每次都创建类似的新类,一来太麻烦,二来耦合度太高了。Java提供了继承机制,让我们可以创建新的类来继承以前的类、抽象类和接口。

多态相当于使用了对象的特点,不同于父类的地方。任何对象都不可能一模一样,肯定会有它的差异,Java提供了父类型引用指向子类型对象的多态机制,这让我们调用代码更加灵活。编译阶段JVM只会看这个调用到的父类型是否满足要求,执行的时候才会看子类型。这样耦合度就非常小了。

2、HashMap的加载因子

关键字:0.75、泊松分布

先看源码(截取):

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    	static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    	static final float DEFAULT_LOAD_FACTOR = 0.75f;
}

这里面说明了HashMap的初始容量为16,而它的默认加载因子是0.75。

为什么 HashMap 的加载因子是0.75?_Java技术栈,分享最主流的Java技术-CSDN博客

HashMap是一个数组 + 链表的数据结构,但是数组如果设置的太大,那么可能分布的太分散,导致占用率不高;如果分数组设置的太小,那么最后占满了发现没地方了。

占满了没地方怎么解决呢?可以有很多种办法,线性探测法、平方探测法、伪随机探测法、再哈希法、链地址法。HashMap很明显使用的链地址法。

看源码中的注释:

/*Ideally, under random hashCodes, the frequency of
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
     *
     * 0:    0.60653066
     * 1:    0.30326533
     * 2:    0.07581633
     * 3:    0.01263606
     * 4:    0.00157952
     * 5:    0.00015795
     * 6:    0.00001316
     * 7:    0.00000094
     * 8:    0.00000006
* more: less than 1 in ten million
*/

这里很难看懂,大概意思就是根据泊松分布原理,加载因子为0.75的话,当链表长度达到8的时候,可能性为0.00000006,机会就是不可能的了。

补:加载因子是0.75,每次扩容都是2的倍数,因为HashMap底层中,扩容时会调用一个resize方法,这个方法中可以看出他会创建一个新的数组,并且将旧数组的元素经过e.hash&(newCap-1)的计算方法添加到新数组中,这个&是位运算,效率非常高,按位与的计算过程就是一假则假,当HashMap的容量为2的幂时,newCap-1的二进制就是全1的这种形式,这样与添加的元素的hash值进行位运算能够充分散列,让添加的元素均匀分布在HashMap的每个位置上,减少hash碰撞。

3、集合:List、Set、Map谁是有序的,谁是无序的,各自的方法有哪些,继承结构是怎样的,扩容、线程安全、初始数组

关键字:数据结构为Array和Queue有序,Linked、Set、Map的无序

扩容:数组相关为10,因子为1,扩容1倍;Hash相关的16,因子0.75,扩容1倍

3.1 各种集合的特性和继承结构

这里写图片描述

先看看各种集合类型的特点:

Set和数组差不多,但是无序。

List是个链表,与位置有关与数组相不相等无关,List有序。

Queue是队列,先进先出,后进后出。

Hash是根据key计算hash值,也就意味着存入是没有顺序的。

这里要先看看各自的数据结构才能更清晰的理解。

Collection(顶级接口):

|——Set:无序(存取顺序不对等)

​ |——HashSet:底层是HashMap,无序

​ |——LinkedHashSet:一看是链表必然有序,但是不可重复

​ |——TreeSet:无序,但是树会根据值进行排序

|——List:有序,可重复

​ |——ArrayList:数组,查询方便,存取麻烦

​ |——LinkedList:链表:存取方便,查找麻烦

​ |——Vector:线程安全的,底层和ArrayList类似

|——Queue:队列,有序,可重复

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28Vd7tUh-1598173707701)(D31A9FFA8E6242219451CB6B03B27A99)]

Map:(子类全部都是无序不可重复的)

方法

那直接看Collection接口和Map接口

public interface Collection<E> extends Iterable<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    boolean containsAll(Collection<?> c);
    Iterator<E> iterator();
    Object[] toArray();
    boolean add(E e);
    boolean addAll(Collection<? extends E> c);
    boolean remove(Object o);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    void clear();
    boolean equals(Object o);
    int hashCode();
    ......
}

那么根据增删改查操作分析一下:

  • 增:add、addAll

  • 删:remove、removeAll、clear

  • 改:就是直接直接赋值、还有变成数组toArray

  • 查:查是否空isEmpty、查是否有contains、containsAll、retainAll、查是否等equals、查有多少size

Map接口:

public interface Map<K,V> {
	int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);
    V put(K key, V value);
    V remove(Object key);
    void putAll(Map<? extends K, ? extends V> m);
    void clear();
    ......

和上面类似,只是有获取key和value的方法。

初始容量和扩容

Vector和ArrayList初始容量是10,加载因子是1,扩容1倍

HashSet初始容量16,加载因子0.75,扩容1倍

HashMap初始容量16,加载因子0.75,扩容1倍

4、Comparable和Comparator的区别

关键字:Comparable在java.lang;Comparator在java.util;Comparable不如Comparator灵活

首先二者所在的包不同:Comparable在java.lang包下,Comparator在java.util包下。

Comparable接口的比较方法:

public int compareTo(T o);

某个对象调用它的话,在我们写这个compareTo方法时系统是不知道的,所以我们就无法拿两者的属性进行比较,但是Comparator不一样。Comparator的方法是这样的。

int compare(T o1, T o2);

我们可以传两个对象,生成它们的比较策略。Comparator更像是设计模式中的策略模式。提供很多种计算方法、然后可以让它们相互之间替换。

5、IO流有哪几类,它们有哪些方法?

FileInputStream、FileOutPutStream、FileReader、FileWriter、BufferReader、BufferWriter、InputStreamReader、OutputStreamWriter、ObjectInputStream、ObjectOutputStream

reader、writer、flush、close方法;

6、String、StringBuffer和StringBuilder的区别?

String是不可变的类型,它的底层是用final修饰的,所以每次给String字符串追加的时候,都要生成新的字符串,很占内存。

StringBuffer和StringBuilder更适合对字符串进行操作,它们有append方法、insert方法、reverse方法等等。

StringBuffer是线程安全的,StringBuilder是非线程安全的,它里面没有synchroized方法。

insert方法不常用,记录一下。

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();
    sb.append("sss");
    System.out.println(sb);
    sb.insert(1,"sas");
    System.out.println(sb);
}

-------------------------------------------------
sss
ssasss    

7、Object类是所有类的父类,说说他的几个常用方法,并且介绍一下

Object类是所有类的父类,它里面有几个方法,equals、hashcode、clone、finalize、wait、notify、notifyAll、toString、getClass方法和native本地方法。

8、接口和抽象类的区别

关键字:构造方法、名称、继承方式、修饰符、变量常量

(1)接口没有构造方法,抽象类可以有

(2)抽象类是class、接口时interface

(3)接口是implements、抽象类是extends

(4)接口支持多继承、抽象类是单继承

(5)接口的方法一般就是public、抽象类则都可以(jdk8以后接口的方法可以有实现,抽象类也是可有可无的)

(6)接口为static修饰的、实现类的不一定

9、你对IO流了解?你说说BIO、NIO和AIO 有什么区别?

关键字:同步阻塞、同步非阻、异步阻塞

BIO(Blocking IO)是同步阻塞是IO,使用socket创建连接。

NIO(Non-Blocking IO)是同步非阻塞式IO,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。

AIO(Asynchronous IO)是异步非阻塞式IO,基于事件和回调机制。

10、HashMap中去重问题

因为hashMap的key不能相同,所以可以使用HashMap去重。