Java面试题总结

这里写自定义目录标题

序言

你好! 这是我这几天面试以来的总结,希望对你们有所帮助。

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 的区别是什么?

== 解读
对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

  • 基础类型:比较的是值是否相同
  • 引用类型:比较的是引用是否相同

代码:

String x= "string";
       String y= "string";
       String z = new String("string");
        System.out.println(x==y); //true
        System.out.println(x==z); //false
        System.out.println(x.equals(y)); //true
        System.out.println(x.equals(z)); //true

代码解读:因为x和y指向的是同一个引用,所以 == 也是true,而new String()方法则重写开辟了内存空间,所以 == 结果为false,而equals 比较的一直是值,所以结果都是true。

equals 解读
equals本质上就是 == ,只不过String 和 Integer 等重写了equals方法,把它变成了值比较。来看下代码就明白了。

首先来看默认情况下 equals 比较一个有相同值的对象,代码如下

public class Cat {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Cat(String name){
        this.name=name;
    }
    public static void main(String[] args) {
        Cat c1 = new Cat("王磊");
        Cat c2 = new Cat("王磊");
        System.out.println(c1.equals(c2)); //false
    }
}

输出结果出乎我们的意料,竟然是false? 这是咋回事,看下equals源码就知道了,源码如下:

 public boolean equals(Object obj) {
        return (this == obj);
    }

从代码中了解到 equals 本质上就是 == 。

那么问题来了,两个相同值的String对象,为什么返回的是true?代码如下:

        String s1 = new String("老王");
        String s2 = new String("老王");
        System.out.println(s1.equals(s2)); //true

同样的,当我们进入String的equals方法,找到了答案,代码如下:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

原来是String重写了Object的equals方法,把引用比较成了值比较。

总结: == 对基本类型来说是值比较,对于引用类型来说是比较的是引用;而equals默认情况下是引用比较,只是很多类重新了equals方法,比如String、integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等

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

不对,两个对象的hashCode()相同 ,equals()不一定是true。

代码示例:

    String str1 = "通话";
        String str2 = "重地";
        System.out.println(String.format("str1:%d | str2:%d",str1.hashCode(),str2.hashCode()));
        System.out.println(str1.equals(str2));

执行结果:

str1:1179395 | str2:1179395
false

解读:很显然"通话"和"重地"的hashCode()相同,然而equals()则为false,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等

4. final在java中有什么作用?

  • final修饰的类叫最终类,该类不能被继承。
  • final修饰的方法不能被重写。
  • final修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

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

等于-1,因为在数轴上取值时,中间值(0.5)向右取整,所以正0.5是往上取整,负0.5是直接舍弃。

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

String不属于基础的数据类型,基础的数据类型有8种:byte short int long boolean char float double,而String属于对象。

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

操作字符串的类有:String、StringBuffer、StringBuilder。

String和StringBuffer、StringBuilder的区别在于String声明的是不可变的对象,每次操作都会生成新的String对象,然后将指针指向新的String对象,而StringBuffer、StringBuilder可以在原来的对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用String。

StringBuffer和StringBuilder最大的区别在于,StringBuffer是线程安全的,而StringBuilder是非线程安全的,但是StringBuilder的性能却高于StringBuffer,所以在单线程环境下推荐使用StringBuilder,多线程环境下推荐使用StringBuffer。

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

不一样,因为内存的分配方式不一样 String str="i"的方式,java虚拟机会将其分配到常量池中;而String str = new String(“i”)则会被分到堆内存中。

9. 如何将字符串反转?

使用StringBuffer或者StringBuilder的reverse()方法。
示例代码:

        //StringBuffer reverse
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("abcdefg");
        System.out.println(stringBuffer+":"+stringBuffer.reverse());
        //StringBuilder reverse
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("abcdefg");
        System.out.println(stringBuilder+":"+stringBuilder.reverse());

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

indexOf(): 返回指定字符的索引
charAt(): 返回指定索引处的字符
replace(): 字符串替换
trim(): 去除字符串两端空白
split(): 分割字符串,返回一个分割后的字符串数组
getBytes(): 返回一个字符串的byte类型的数字。
length(): 返回字符串长度
toLowerCase(): 将字符串转换成小写
toUpperCase(): 将字符串转换成大写
substring(): 截取字符串。
equals(): 字符串比较

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

不需要,抽象类不一定非要有抽象方法。
示例代码:

public abstract class cat {
    
    public static void sayHi(){
        System.out.println("hi~");
    }
    
}

上面代码,抽象类并没有抽象方法但完全可以正常运行

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

  • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
  • 抽象类不能直接实例化,不同类可以直接实例化

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

不能,定义抽象类就是让其他类继承的,如果定义为final该类就不能被继承了,这样彼此就会产生矛盾,所以final不能修饰抽象类

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

  • 实现:抽象类的子类使用extends来继承;接口必须使用implement来实现接口
  • 构造函数:抽象类可以有构造函数;接口不能有。
  • 实现数量:类可以实现很多接口;但是只能继承一个抽象类
  • 访问修饰符:接口中的方法默认使用public修饰;抽象类的方法可以是任意访问修饰符。

15. java中Io流分为几种?

按功能来分:输入流(input)和输出流(output)。
按类型类分:字节流和字符流。

字符流和字节流的区别是:字节流按8位传输以字节为单位输入输出数据,字节流按16位传输以字符为单位输入输出数据。

16. BIO、NIO、AIO有什么区别?

  • BIO:Block IO同步阻塞式IO,就是我们平常使用的传统IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:Non IO同步非阻塞IO,是传统IO的升级,客户端和服务器端通过Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO是NIO的升级,也叫NIO2,实现了异步非堵塞IO,异步IO的操作基于事件和回调机制。

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

  • Files.exists(): 检测文件路径是否存在。
  • Files.createFile():创建文件。
  • Files.createDirectory():创建文件夹。
  • Files.delete():删除一个文件或目录。
  • Files.copy():复制文件。
  • Files.move():移动文件。
  • Files.size():查看文件个数。
  • Files.read():读取文件。
  • Files.write():写入文件。

容器

18. java容器都有哪些?

java容器分为Collection 和 Map 两大类,其下又有很多子类,如下所示:

  • Collection
  • List
    • ArrayList
    • LinkeList
    • Vector
    • stack
  • set
    • HashSet
    • LinkeHashSet
    • treeSet
  • Map
  • HashMap
    • LinkedHashMap
  • TreeMap
  • ConcurrentHashMap
  • Hashtable

19. Collection和Collections有什么区别?

  • Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用方法,所有集合都是它的子类,比如LIst set 等。
  • Collections是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序的方法:Collections.sort(list)。

20. List、Set、Map之间的区别是?

list、set、map的区别主要体现在两个方面:元素是否有序、是否允许元素重复。
三者之间的区别:

  • list是有序的 是允许元素重复的
  • set的子接口abstractSet和HashSet是无序的 不允许元素重复 ,而TreeSet是有序的(用的是二叉数排序),也是不允许元素重复的
  • map的子接口key值是唯一的value是可重复的,其中abstractMap和HashMap是无序的,而treeMap是有序的(用二叉树排序)

21. HashMap和Hashtable 有什么区别?

  • 储存:HashMap运行key和value为null而Hashtable不允许。
  • 线程安全:HashMap是非线程安全的,而Hashtable是线程安全的。
  • 推荐使用:Hashtable是推荐使用的,如果单线程使用HashMap,多线程使用ConcurrentHashMap代替。

22. 如何决定使用HashMap还是TreeMap?

对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的选择,因为相对而言HashMap的插入会更快,但如果你要对一个Key集合进行有序的遍历,那TreeMap是更好的选择。

23. 说下HashMap的实现原理?

HashMap基于Hash算法实现的,我们通过put(key value)储存,get(key)来获取。当传入key时,HashMap会根据key.hashCode()计算出hash值,根据hash值将value保存在 bucket里。当计算出的hash值相同时,我们称之为hash冲突,HashMap的做法是用链表和红黑树存储相同hash值的value。当hash冲突的个数比较少时,使用链表否则使用红黑树。

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

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

25. ArrayList和 LinkedList的区别 是什么 ?

  • 数据结构实现:ArrayList是动态数组的数据结构实现,而LinkedList是双向链表的数据结构实现。
  • 随机访问效率:arrayList比LinkedList在随机访问的时候效率要高,因为LinkedList是线性的数据储存方式,所以需要移动指针从前往后依次查找
  • 增加和删除效率: 在非首尾的增加和删除操作,LinkedList要比ArrayList 效率要高,因为ArrayList增删操作要影响数组内的其他数据的下标

综合来说,在需要频繁读取集合的元素时,更推荐使用ArrayLsit,而在插入和删除操作较多时,更推荐使用LinkedList

26.如何实现数组和List之间的转换?

  • 数组转换List: 使用Arrays.asList(array)进行转换
  • List转换数组: 使用List自带的toArray()方法

代码示例:

        // lsit to array
        List<String> list = new ArrayList<>();
        list.add("张家明");
        list.add("的博客");
        Object[] objects = list.toArray();
        //array to lsit
        String[] array = new String[]{"张家明","的博客"};
        List<String> listArrays = Arrays.asList(array);

27. ArrayList和Vector的区别是什么?

  • 线程安全:Vector使用了Synchronized来实现线程同步,是线程安全的,而ArrayList是非线程安全的
  • 性能: ArrayList的性能方面要优于Vector
  • 扩容: ArrayList和Vector都会根据实际的需求动态的调整容量,只不过在Vector扩容每次会增加1倍,而ArrayLsit只会增加50%

28. Array he ArrayList有何区别?

  • Array可以存储基础类型和对象,ArrayList只能存储对象
  • Array是指定固定大小的,而ArrayList大小是自动扩展的
  • Array内置方法没有ArrayList多,比如addAll、removeAll、iteration等方法只有ArrayList有

29. 在Queue中 poll()和 remove()有什么区别?

  • 相同点:都是返回第一个元素,并在队列中删除返回的对象
  • 不同点:如果没有元素 poll()会放回null,而remove()会直接抛出NoSuchElementException异常

代码示例:

        Queue<String> queue = new LinkedList<>();
        queue.offer("String");//类似add   带有返回值   添加一个元素并返回true       如果队列已满,则返回false
        System.out.println(queue.poll());
        System.out.println(queue.remove());
        System.out.println(queue.size());

30. 那些集合是线程安全的?

Vector、Hashtable、Stack都是线程安全的,而像HashMap则是非线程安全的,不过在JDK1.5之后随着Java.util.concurrent并发包的出现,它们也有了自己对应的线程安全类,比如HashMap对应的线程安全类就是ConcurrentHashMap

31. 迭代器 iterator 是什么?

Iterator 接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器的实例。迭代器取代了Java集合框架中的Enumeration,迭代器允许调用者在迭代过程中移除元素。

32. Iterator怎么使用?有什么特点?

Iterator使用代码如下:

        List<String> list = new ArrayList<>();
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String obj = it.next();
            System.out.println(obj);
        }

Iterator的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出ConcurrntModifIcationException异常

33. Iterator和Listlterator有什么区别?

  • Iterator 可以遍历Set和List集合,而ListIterator只能遍历List
  • Iterator只能单向遍历,而ListIterator可以双向遍历(向前/后遍历)
  • ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或者后面元素的索引位置。

34. 怎么确保一个集合不能被修改?

可以使用Collections.unmodiflableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出Java.lang.U…异常

示例代码如下:

       List<String > list = new ArrayList<>();
       list.add("x");
        System.out.println("1111111111111");
        Collection<String> clist = Collections.unmodifiableCollection(list);
        clist.add("y");
        System.out.println("22222222222222");

多线程

35. 并行和并发有什么区别

  • 并行:多个处理器或多核处理器同时处理多个任务。
  • 并发:多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行

并发:两个列队一台咖啡机
并行:两个列队两个咖啡机

36. 线程和进程的区别

一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。

37. 守护线程是什么?

守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在java中垃圾回收线程就是特殊的守护线程

38. 创建线程有哪几种方式?

创建线程有三种方式:

  • 继承Thread重写run方法
  • 实现Runnable接口
  • 实现Callable接口

39. 说一下runnable和callable有什么区别?

runnable没有返回值,callable可以拿到有返回值,callable可以看作是runnable的补充。

40. 线程有哪些状态?

线程的状态:

  • new 尚未启动
  • runnable 正在执行中
  • blocked 阻塞的(被同步锁或者Io锁阻塞)
  • waiting 永久等待状态
  • timed_waiting 等待指定的时间重新被唤醒的状态
  • terminated执行完成

41. sleep()和 wait() 有什么区别?

  • 类的不同:sleep()来自Thread,wait()来自Object.
  • 释放锁:sleep()不释放锁;wait()释放锁
  • 用法不同:sleep()时间到会自动恢复;wait()可以使用notify()/notifyAll()直接唤醒

42. notify()和notifyAll()有什么区别?

notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。notifyAll()调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。

43. 线程的run()和start()有什么区别?

start()方法用于启动线程,run()方法用于执行线程的运行时代码。run()可以重复调用,而start()只能调用一次。

44. 创建线程池有哪几种方式?

线程池创建有七种方式,最核心的是最后一种:

  • newSingleThreadExecutor():它的特点在于工作线程数目被限制为1,操作一个无界的工作对列,所以它保证了所有任务的都能被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
  • newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超出60秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作对列;
  • newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作对列,任何时候最多有nThreads个工作线程活动的。这意味着,如果任务数量超过了活动对列数目,将在工作对列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目nThreads;
  • newSingleThreadScheduledExecutor():创建单线程池,返回ScheduledExecutorService,可以进行定时或者周期性的工作调度;
  • newScheduledThreadPool(int corePoolSice):和newSingleThreadScheduledExecutor()类似,创建的是个ScheduledExecutorService,可以进行定时或周期性地工作调度,区别在于单一工作线程还是多个工作线程;
  • newWorkStealingPool( int parallelism):这是一个经常被人忽略的线程池,java8才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并进行地处理任务,不保证处理顺序;
  • ThreadPoolExecutor():是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor()的封装。

45. 线程池都有哪些状态

  • RUNNING:这是最正常的状态,接受新的任务,处理等待对列中的任务
  • SHUTDOWN: 不接受新的任务提交,但是会继续处理等待对列的任务
  • STOP: 不接受新的任务提交,不再处理等待对列中的任务,中断正在执行的线程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值