Java常见面试题(一)

JavaSE部分

  1. 抽象类(abstract class)和接口(interface)的区别?
    ☆接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。
    ☆抽象类在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个接口,实现多重继承接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。
    ☆在抽象类中可以有自己的数据成员,也可以有非抽象的成员方法,而在接口中只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在接口中一般不定义数据成员)所有的成员方法,默认都是public abstract类型的。
    ☆抽象类和接口所反映出的设计理念不同,其实抽象类表示的是"is-a"关系,接口表示的是"has-a"关系。
    ☆实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。抽象类中可以有非抽象方法,接口中则不能有实现方法。
    ☆接口中定义的变量默认是public static final型,且必须给其初始值,所以实现类中不能重新定义,也不能改变其值。抽象类中的变量默认是friendly型,其值可以在子类中重新定义也可以在子类中在重新赋值。

  2. Java重载和重写的区别?
    ☆重载是指在一个类中有多个方法名称相同的方法存在,方法的参数个数/类型不同。重载是一个类中多态的表现。
    ☆重载的时候返回值的类型可以相同也可以不同,无法通过返回值的不同来区分方法的重载。
    ☆重写是指子类和父类之间的一种方法关系,子类对父类的方法进行重写,子类中的方法名称,返回类型,参数列表都必须与父类中方法相同。
    ☆重写时子类函数的访问权限修饰符不能小于父类的。
    ☆重写后调用父类中的方法使用super关键字。

  3. List,Map,Set三个接口,存取元素时,各有什么特点?
    List与Set都是单列元素的集合,它们有一个功共同的父接口Collection。
    Set里面不允许有重复的元素,
    存元素:add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true;当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。
    取元素:没法说取第几个,只能以Iterator接口取得所有的元素,再逐一遍历各个元素。
    List表示有先后顺序的集合,
    存元素:多次调用add(Object)方法时,每次加入的对象按先来后到的顺序排序,也可以插队,即调用add(int index,Object)方法,就可以指定当前对象在集合中的存放位置。
    取元素:方法1:Iterator接口取得所有,逐一遍历各个元素
    方法2:调用get(index i)来明确说明取第几个。
    Map是双列的集合,存放用put方法:put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。
    取元素:用get(Object key)方法根据key获得相应的value,也可以获得所有的key的集合,还可以获得所有的value的集合,还可以获得key和value组合成的Map.Entry对象的集合。

    List以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。

  4. ArrayList和Vector的区别?
    相同处:第一个:Vector和ArrayList底层都是数组实现的。
        第二个就是若开始都是用空构造则默认的数组长度都为10
    不同处:第一个:最明显的一个是Vector是线程安全的(通过实现synchronize方法)而ArrayList是线程不安全的
        第二个:ArrayList如果需要扩容新数组的长度是原来数组的1.5倍。而Vector是原来的两倍
    在这里插入图片描述

  5. HashSet和TreeSet有什么区别?
    HashSet:
    不能保证元素的排列顺序,顺序有可能发生变化
    集合元素可以是null,但只能放入一个null
    HashSet底层是采用HashMap实现的
    HashSet底层是哈希表实现的
    TreeSet:
    Treeset中的数据是排好序的,不允许放入null值。
    TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key。
    TreeSet的底层实现是采用二叉树(红-黑树)的数据结构。

  6. 数组和列表(ArrayList)有什么区别?有什么时候应该使用Array而不是Array List?
    存储内容比较: Array 数组可以包含基本类型和对象类型,ArrayList 却只能包含对象类型。Array 数组在存放的时候一定是同种类型的元素。ArrayList就不一定了 。
    空间大小比较: Array 数组的空间大小是固定的,所以需要事前确定合适的空间大小。ArrayList的空间是动态增长的,而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。
    方法上的比较: ArrayList 方法上比 Array 更多样化,比如添加全部 addAll()、删除全部 removeAll()、返回迭代器 iterator() 等。
    适用场景: 如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里, 但是如果我们单纯只是想要以数组的形式保存数据,而不对数据进行增加等操作,只是方便我们进行查找的话,那么,我们就选择ArrayList。如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,那么,使用ArrayList 就真的不是一个好的选择,因为它的效率很低,使用数组进行这样的动作就很麻烦,那么,我们可以考虑选择LinkedList。

  7. 为什么集合类没有实现Cloneable和Serializable接口?
    克隆(cloning)或者序列化(serialization)的语义和含义是跟具体的实现相关的。因此应该由集合类的具体实现类来决定如何被克隆或者序列化
    (1)什么是克隆?
    克隆是把一个对象里面的属性值,复制给另一个对象。而不是对象引用的复制
    (2)实现Serializable序列化的作用
    1.将对象的状态保存在存储媒体中一边可以在以后重写创建出完全相同的副本
    2.按值将对象从一个应用程序域法相另一个应用程序域
    实现Serializable接口的作用就是可以把对象存到字节流,然后可以恢复。所以你想你的对象没有序列化,怎么才能在网络传输呢?要网络传输就得转为字节流,所以在分布式应用中,你就得实现序列化。如果你不需要分布式应用,那就没必要实现序列化

  8. Collection和Collections的区别?
    Collection是集合类的上级接口,继承与它有关的接口,主要有List和Set
    Collections是针对集合类的一个帮助类,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作

  9. 遍历HashMap的三种方式?
    遍历HashMap的键值对:
    (1)通过entrySet()获取HashMap的"键值对"的Set集合(于Set中无序排放)。
    (2)通过迭代方法遍历集合,再利用getKey(),getValue()方法获取相应键,值。
    遍历HashMap的键:
    通过keySet()方法,获取HashMap的所有键的Set集合,通过迭代取出所有key,再利用get()方法获取value。
    遍历HashMap的值:
    通过values()方法获取HashMap集合的所有value的Collection集合(于集合中无序存放)。

  10. HashMap和HashTable的区别?
    历史原因: HashTable是基于陈旧的Dictionary类的
    HashMap是Java1.2引进的Map接口的一个实现
    同步性: HashTable是线程安全的,也就是同步的
    HashMap是线程不安全的,是异步的
    值: 只有HashMap可以将空值作为一个表的条目的key或者value

  11. 为什么用ConcurrentHashMap,ConcurrentHashMap的原理?
    HashMap虽然经常被我们使用,但是也存在两个比较明显的缺点: 线程不安全、并发编程时容易死循环;
    而使用HashTable虽然能解决并发问题,但是由于使用了synchronized来实现锁机制,也使得在并发时读写效率较低。
    ConcurrentHashMap它将数据分成一段一段的存储,然后给每一段数据加一把锁,每段之间的锁互不影响,因此当进行增删改查时只要是为不同的一个Node的话,那么相互不影响,从而提升效率。

  12. Java有哪些容器?
    数组: 长度限制为Integer.MAX_VALUE
    String: 底层是char 数组 长度 Integer.MAX_VALUE 线程安全的
    集合:
    List 存放有序,列表存储,元素可重复
    eg:ArrayList、LinkedList、Vector
    Set 存放无序,元素不可重复
    eg:HashSet、LinkedHashSet、TreeSet
    Map 存放无序,元素可重复
    eg:HashMap、TreeMap、LinkedHashMap、HashTable
    Queue队列

  13. String s = new String(”abc”)创建了几个对象?
    两个对象,一个是静态区的“abc“,一个是用new创建在堆上的对象

  14. String和StringBuffer,StringBuilder的区别?
    (1)长度是否可变
    String 是被 final 修饰的,他的长度是不可变的,就算调用 String 的concat 方法,那也是把字符串拼接起来并重新创建一个对象,把拼接后的 String 的值赋给新创建的对象
    StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象,StringBuffer 与 StringBuilder 中的方法和功能完全是等价的。调用StringBuffer 的 append 方法,来改变 StringBuffer 的长度,并且,相比较于 StringBuffer,String 一旦发生长度变化,是非常耗费内存的!
    (2)执行效率
    三者在执行速度方面的比较:StringBuilder > StringBuffer > String
    (3)应用场景
    如果要操作少量的数据用 = String
    单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
    多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

  15. 静态变量和实例变量的区别?
    静态变量是被static 关键字修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝,静态变量可以让多个对象共享内存;
    实例变量必须依存于某一个实例,需要先创建对象然后通过对象才能访问到它。

  16. valatile的用途?
    原因:并发编程中,由于 cpu 在主内存中运行的,而线程是在工作内存中执行,线程中修改共享变量的值修改的是工作内存中的变量,需要重新写入主内存中,其他线程才能够读取修改后的共享变量。
    关于并发编程中的三个概念:
    原子性,可见性,有序性。
    valatile 修饰的变量可以让代码块具备可见性和有序性,但是不具备原子性,线程中只有最简单单一的读写操作才具备原子性,如果同时具备读写修改则不具备原子性。
    valatile 用途:
    用来判断线程的执行标志,修饰单例模式的单例类对象,进行 double check。
    valatile 无原子性的解决办法:
    synchronize

  17. ThreadLocal的使用场景?
    ThreadLocal适用的场景是,多个线程都需要使用一个变量,但这个变量的值不需要在各个线程间共享,各个线程都只使用自己的这个变量的值。

  18. 说一下你常用的设计模式?
    创建型模式 共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
    结构型模式 共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
    行为型模式 共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

    设计模式六大原则
    1.开放封闭原则: 对扩展开放,对修改封闭,即程序拓展时不要动原有代码
    2.LSP原则: 任何父类可以出现的地方,子类一定可以出现
    3.依赖倒置原则: 使用接口,依赖于抽象而不是具体
    4.接口隔离原则: 为了解耦,使用多个相互隔离的接口
    5.迪米特法则: 一个实体应当尽量少的与其他实体间发生相互作用,使系统功能模块相对独立
    6.CRP原则: 尽量使用合成/聚合方式,而不是使用继承
    java常见设计模式简要总结原文链接

  19. Java内存模型?
    程序计数器: 是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。
    Java虚拟机栈: 线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。
    本地方法栈: 跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。
    Java堆: 所有线程共享的一块内存区域,对象实例几乎都在这分配内存。
    方法区: 各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。

  20. 垃圾回收机制和不可达算法?
    Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间,在何时回收是不可预料的。
    在Java中,是通过可达性分析(Reachability Analysis)来判定对象是否存活的。该算法的基本思路就是通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。

  21. 了解哪些排序算法?二分查找算法是什么?
    希尔排序、冒泡排序、快速排序、归并排序、堆排序、选择排序、基数排序等
    二分查找也称折半查找,它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

  22. Java的反射是如何实现的?
    Java反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
    优点:可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度。

  23. 谈谈final, finally, finalize的区别?
    final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。内部类要访问局部变量,局部变量必须定义成final类型,
    finally 是异常处理语句结构的一部分,表示总是执行。关闭连接常常放在finally块中执行
    finalize 是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用。

  24. 线程的 run()和 start()有什么区别? 一个线程两次调用start()方法会出现什么情况?
    每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
    Java的线程是不允许启动两次的,第二次调用必然会抛出illegalThraedStateException,这是一种运行时异常,多次调用start被认为是编程错误。第二次调用start()方法时,线程可能处于停止或者其他(非new)状态,但是不论如何,都不可以再次启动的。

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

    • sleep()方法属于Thread类中;wait()方法属于Object类中
    • sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态;
    • wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
  26. notify()和 notifyAll()有什么区别
    notify方法只唤醒一个等待(对象的)线程并使该线程开始执行(随机)。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。
    notifyAll会唤醒所有等待(对象的)线程,哪一个线程将会第一个处理取决于操作系统的实现。

  27. 用JAVA SOCKET编程,读服务器几个字符,再写入本地显示?
    转载此链接

  28. 请从100万个数字中找到最大的10个数字?
    转载此链接

猜你喜欢

转载自blog.csdn.net/weixin_43980936/article/details/102478744