Java面试葵花宝典

Java葵花宝典

一、Java基础

1、**final关键字的作用?

  1. 被 final 修饰的不可以被继承
  2. 被 final 修饰的方法不可以被重写
  3. 被 final 修饰的变量不可以被改变
  4. 被 final 修饰的方法,JVM会尝试将其内联,以提高运行效率
  5. 被 final 修饰的常量,在编译阶段会存入常量池中
  6. 如果修饰引用,那么表示引用不可变,引用指向的内容可变

2、**abstract class和interface有什么区别?

  1. 声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。
  2. 不能创建abstract类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例
  3. 不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
  4. 接口(interface)是抽象类变体。在接口中,所有方法都是抽象的多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final 成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。
  5. 当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。
  6. 由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。
  7. 引用可以转换到接口类型或从接口类型转换instanceof 运算符可以用来决定某对象的类是否实现了接口

3、**Java 集合类:list、set、queue、map、stack的特点与用法?

  1. Map键值对,键 Key 是唯一且不能重复的一个键对应一个值,值可以重复TreeMap 可以保证顺序HashMap 不保证顺序,即为无序的,Map 中可以将 Key 和 Value 单独抽取出来,其中 KeySet()方法可以将所有的 keys 抽取成一个 Set,而 Values()方法可以将map 中所有的 values 抽取成一个集合。
  2. Set是不包含重复元素的集合,Set 中最多包含一个 null 元素,只能用Iterator实现单向遍历,Set中没有同步方法
  3. List是有序的可重复集合,可以在任意位置增加删除元素,用 Iterator 实现单向遍历,也可用ListIterator 实现双向遍历
  4. Queue:遵从先进先出原则,使用时尽量避免 add()和 remove()方法,而是使用 offer()来添加元素,使用 poll()来移除元素,它的优点是可以通过返回值来判断是否成功,LinkedList实现了 Queue 接口,Queue 通常不允许插入 null 元素。
  5. Stack:遵从后进先出原则,Stack 继承自 Vector,它通过五个操作对类 Vector 进行扩展,允许将向量视为堆栈,它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 peek()方法、测试堆栈是否为空的 empty 方法等。
  6. 用法建议:
    1. 如果涉及堆栈,队列等操作,建议使用 List
    2. 对于快速插入和删除元素的,建议使用 LinkedList
    3. 如果需要快速随机访问元素的,建议使用 ArrayList

4、**说出ArrayList,Vector,LinkedList的存储性能和特性?

  1. ArrayListVector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

5、内存泄漏和内存溢出?

  1. 内存泄漏(memoryleak),是指应用程序在申请内存后,无法释放已经申请的内存空间,一次内存泄漏危害可以忽略,但如果任其发展最终会导致内存溢出(outofmemory)。如读取文件后流要进行及时的关闭以及对数据库连接的释放。
  2. 内存溢出(outofmemory)是指应用程序在申请内存时,没有足够的内存空间供其使用。如我们在项目中对于大批量数据的导入,采用分批量提交的方式。

6、**反射中,Class.forName()和ClassLoader.loadClass()的区别?

  1. Class.forName(className)方法,内部实际调用的方法是Class.forName(className,true,classloader);第2boolean参数表示是否需要初始化,Class.forName(className)默认是需要初始化,一旦初始化,就会触发目标对象的 static块代码执行,static参数也会被再次初始化
  2. ClassLoader.loadClass(className)方法,内部实际调用的方法是ClassLoader.loadClass(className,false);第2boolean参数,表示目标对象是否进行链接false表示不进行链接,由上面的介绍,可以不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行

7、Int和Integer的区别?

  1. Integerint包装类型,在拆箱和装箱中,二者自动转换。int是基本类型,直接存数值;而integer是对象;用一个引用指向这个对象。由于Integer是一个对象,在JVM中对象需要一定的数据结构进行描述,相比int而言,其占用的内存更大一些.

8、**String、StringBuilder、StringBuffer的区别?

  1. String是字符串常量不可变,使用字符串拼接时是不同的2个空间
  2. StringBuffer是字符串变量可变线程安全,字符串拼接直接在字符串后追加
  3. StringBuilder是字符串变量可变非线程安全,字符串拼接直接在字符串后追加
  4. 注意事项:
    1. StringBuilder执行效率高于StringBuffer高于String
    2. String是一个常量,是不可变的,所以对于每一次+=赋值都会创建一个新的对象,StringBuffer和StringBuilder都是可变的,当进行字符串拼接时采用append方法,在原来的基础上进行追加,所以性能比String要高,又因为StringBuffer是线程安全的而 StringBuilder是线程非安全的。因为StringBuffer的所有公开方法都是synchronized修饰的,而StringBuilder并没有 StringBuilder修饰。所以StringBuilder的效率高于StringBuffer。
    3. 对于大数据量的字符串的拼接,采用StringBuffer,StringBuilder。

9、**Hashtable和Hashmap的区别?

  1. HashTable是线程安全的,HashMap非线程安全的
  2. Hashtable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
  3. 两者的遍历方式大同小异,Hashtable仅仅比HashMap多一个elements方法。

10、说几个常见的编译时异常?

  1. SQLException提供有关数据库访问错误或其他错误的信息的异常。
  2. IOexception表示发生了某种I/O异常的信号。此类是由失败或中断的I/O操作产生的一般异常类。
  3. FileNotFoundException当试图打开指定路径名表示的文件失败时,抛出此异常。
  4. ClassNotFoundException找不到具有指定名称的类的定义。
  5. EOFException当输入过程中意外到达文件或流的末尾时,抛出此异常。

11、方法重载的规则?

  1. 方法名一致,参数列表中参数的顺序,类型,个数不同。
  2. 重载与方法的返回值无关,存在于父类和子类,同类中。
  3. 可以抛出不同的异常,可以有不同修饰符。

12、方法重写的规则?

  1. 参数列表、方法名、返回值类型必须完全一致,构造方法不能被重写;
  2. 声明为 final 的方法不能被重写;
  3. 声明为 static 的方法不存在重写(重写和多态联合才有意义);
  4. 访问权限不能比父类更低;
  5. 重写之后的方法不能抛出更宽泛的异常

13、throw 和 throws 的区别?

  1. throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
  2. throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。
  3. throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
  4. throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
  5. throws 表示出现异常的一种可能性,并不一定会发生这种异常。

14、抽象类和接口的区别?

  1. 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
  2. 类可以实现很多个接口,但是只能继承一个抽象类
  3. 类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现 抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
  4. 抽象类可以在不提供接口方法实现的情况下实现接口。
  5. Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。 6、Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private,protecte 或者是 public。
  6. 接口是绝对抽象的,不可以被实例化(java 8 已支持在接口中实现默认的方法)。抽象类 也不可以被实例化,但是,如果它包含 main 方法的话是可以被调用的。

15、Java 的基础类型和字节大小?

  1. 布尔型 boolean 8 位;
  2. 字节型 byte 8 位;
  3. 字符型 char 16 位;
  4. 短整型 short 16 位;
  5. 整形 int 32 位;
  6. 长整形 long 64 位;
  7. 浮点型 float 32 位;
  8. 双精度 double 64 位;

16、四个访问修饰符合访问级别?Protected、 public、没有访问修饰符、private

Protected、public、没有访问修饰符、private

17、String 和 StringBuffer 的区别?

  1. String 和 StringBuffer 主要区别是性能:String 是不可变对象,每次对 String 类型进行操作都等同于产生了一个新的String 对象,然后指向新的 String 对象。所以尽量不要对 String 进行大量的拼接操作,否则会产生很多临时对象,导致 GC 开始工作,影响系统性能。StringBuffer 是对象本身操作,而不是产生新的对象,因此在有大量拼接的情况下,我们建议使用StringBuffer(线程安全)。

18、**HashSet 的底层实现是什么?

  1. HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的。
  2. 在 HashSet 的构造法中会初始化一个 HashMap 对象,HashSet 不允许值重复。
  3. 因此,HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的,当存储的值已经存在时返回 false。

19、抽象类的意义?

  1. 为其他子类提供一个公共的类型
  2. 封装子类中重复定义的内容
  3. 定义抽象方法,子类虽然有不同的实现,但是定义时一致的

20、为什么重写 equals 时必须重写 hashCode 方法?

  1. hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。如果两个对象相等,则 hashcode 一定也是相同的;
  2. 如果两个对象相等,对两个对象分别调用 equals 方法都返回 true;
  3. 如果两个对象有相同的 hashcode 值,它们也不一定是相等的因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖。
  4. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。

21、HashSet 和 TreeSet 有什么区别?

  1. HashSet 是由一个 hash 表来实现的,因此,它的元素是无序的。add(),remove(),contains() 方法的时间复杂度是 O(1)。
  2. TreeSet 是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是 O(logn)。

22、强引用和软引用和弱引用以及虚引用?

  1. 强引用:最普遍的一种引用方式,如 String s = “abc”,变量 s 就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。
  2. 软引用(SoftReference):用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列 ReferenceQueue 联合使用,如果软引用的对象被垃圾回收,JVM 就会把这个软引用加入到与之关联的引用队列中。
  3. 弱引用(WeakReference):弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的 生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
  4. 虚引用(PhantomReference):就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。
  5. 虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

23、数组在内存中如何分配?

  1. 当一个对象使用 new 关键字创建的时候,会在堆上分配内存空间,然后才返回到对象的引用。这对数组来说也是一样的,因为数组也是一个对象,简单的值类型的数组,每个数组成员是一个引用(指针)引用到栈上的空间。

24、Java 中怎么创建一个不可变对象?

  1. 对象的状态在构造函数之后都不能被修改,任何修改应该通过创建一个新对象来实现。
  2. 所有的对象属性应该都设置为 final
  3. 对象创建要正确,例如:对象的应用不能在构造函数中被泄露出去
  4. 对象要设置为 final,确保不要继承的 Class 修改了 immutability 特性

25、Java 中 ++ 操作符是线程安全的吗?

  1. 不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。

26、**new 一个对象的过程和 clone 一个对象的过程?

  1. new 操作符的本意是分配内存。程序执行到 new 操作符时,首先去看 new 操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
  2. clone 在第一步是和 new 相似的,都是分配内存,调用 clone 方法时,分配的内存和原对象(即调用 clone 方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone 方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

27、Java 中==和 equals()的区别?

  1. 使用==比较原生类型如:boolean、int、char 等等,使用 equals()比较对象。
  2. ==是判断两个变量或实例是不是指向同一个内存空间。equals 是判断两个变量或实例所指向的内存空间的值是不是相同。
  3. ==是指对内存地址进行比较。equals()是对字符串的内容进行比较。
  4. ==指引用是否相同,equals()指的是值是否相同。

28、final、finalize和finally的不同之处?

  1. final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
  2. finally 是异常处理语句结构的一部分,表示总是执行。
  3. finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

29、Java的多态表现在哪里?

  1. 多态要有动态绑定,否则就不是多态,方法重载也不是多态(因为方法重载是编译期决定好的,没有后期也就是运行期的动态绑定)当满足这三个条件:1、有继承 2、有重写 3、要有父类引用指向子类对象

30、静态类型有什么特点?

  1. 静态的属性:随着类的加载而加载,该属性不在属于某个对象,属于整个类
  2. 静态的方法:直接用类名调用,静态方法里不能访问非静态成员变量
  3. 静态类:不能直接创建对象,不可被继承

31、**Java创建对象的几种方式?

  1. new 创建新对象
  2. 通过反射机制
  3. 采用 clone 机制
  4. 通过序列化机制

32、Object 中有哪些公共方法?

  1. Object 是所有类的父类,任何类都默认继承 Object clone 保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法,否则抛出 CloneNotSupportedException 异常。
  2. equals 在 Object 中与 == 是一样的,子类一般需要重写该方法。hashCode 该方法用于哈希查找,重写了 equals 方法一般都要重写 hashCode 方法。这个方法在一些具有哈希功能的 Collection 中用到。getClass final 方法,获得运行时类型 wait 使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

33、&和&&的区别?

  1. &是位运算符,表示按位与运算
  2. &&是逻辑运算符,表示逻辑与(and)。

34、在.java源文件中可以有多个类吗(内部类除外)?

  1. 一个.java 源文件中可以包括多个类(不是内部类),但是单个文件中只能有一个 public 类,并且该 public 类必须与文件名相同

35、如何正确的退出多层嵌套循环?

  1. 使用标号和 break
  2. 通过在外层循环中添加标识符

36、内部类有什么作用?

  1. 内部类可以很好的实现隐藏,一般的非内部类,是不允许有 private 与 protected 权限的,但内部类可以
  2. 内部类拥有外围类的所有元素的访问权限
  3. 可是实现多重继承
  4. 可以避免修改接口而实现同一个类中两种同名方法的调用

37、**深拷贝和浅拷贝的区别是什么?

  1. 浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
  2. 深拷贝:被复制对象的所有变量都含有与原来的对象相同的值。而那些引用其他对象的变量将指向被复制过的新对象。而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍.

38、String是基本数据类型吗?

  1. 基本数据类型包括 byte、int、char、long、float、double、boolean 和 short。
  2. java.lang.String 类是 final 类型的,因此不可以继承这个类、不能修改这个类。
  3. 为了提高效率节省空间,我们应该用 StringBuffer 类

39、static的用法?

  1. Static 可以修饰内部类、方法、变量、代码块;
  2. Static 修饰的类是静态内部类
  3. Static 修饰的方法是静态方法,表示该方法属于当前类的,而不属于某个对象的,静态方法也不能被重写,可以直接使用类名来调用。在 static 方法中不能使用 this 或者 super 关键字。
  4. Static 修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在 JVM 加载类的时候,只为静态分配一次内存。
  5. Static 修饰的代码块叫静态代码块,通常用来做程序优化的。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。

40、什么是值传递和引用传递?

  1. 对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响原对象的值。
  2. 对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象所做的改变会反映到所有的对象上。

41、重载和重写的区别?

  1. 方法的重写 Overriding 和重载 Overloading 是 Java 多态性的不同表现。
  2. 重写 Overriding 是父类与子类之间多态性的一种表现,重载 Overloading 是一个类中多态性的一种表现。
  3. 如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。
  4. 如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。

42、成员变量和局部变量的区别有哪些?

  1. 从语法形式上,看成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数
  2. 成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰,成员变量和局部变量都能被 final 所修饰;
  3. 从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存
  4. 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在, 而局部变量随着方法的调用而自动消失。
  5. 成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被 final 修饰但没有被 static 修饰的成员变量必须显示地赋值),而局部变量则不会自动赋值。

43、静态方法和实例方法有何不同?

  • 静态方法和实例方法的区别主要体现在两个方面:
    1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。
    2. 而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
    3. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法,实例方法则无此限制

44、什么是多态?

  1. 允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

45、多态的优点?

  1. 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆 Circle 类工作,对其他任何圆形几何体,如圆环,也同样工作。
  2. 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。

46、多态存在的三个必要条件?

  1. 要有继承。
  2. 要有方法的重写。
  3. 父类引用指向子类对象(对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接)

47、**TreeMap、HashMap、LindedHashMap的区别?

  1. LinkedHashMap 可以保证 HashMap 集合有序。存入的顺序和取出的顺序一致。TreeMap 实现 SortMap 接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器
  2. 当用 Iterator 遍历 TreeMap 时,得到的记录是排过序的
  3. HashMap 不保证顺序,即为无序的,具有很快的访问速度。HashMap 最多只允许一条记录的键为 Null,允许多条记录的值为 Null,HashMap 不支持线程的同步。

48、Java(OOP)面向对象的特征有哪些方面?

  1. 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么;
  2. 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类)。得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段;
  3. 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装。我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
  4. 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为 编译时的多态性 和 运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当 A 系统访问 B 系统提供的服务时,B 系统有多种提供服务的方式,但一切对 A 系统来说都是透明的。
  5. 方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:
    1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);
      1. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

49、列出一些常见的运行时异常?

  1. ArithmeticException(算术异常)
  2. ClassCastException(类转换异常)
  3. IllegalArgumentException(非法参数异常)
  4. IndexOutOfBoundsException(下标越界异常)
  5. NullPointerException(空指针异常)
  6. SecurityException(安全异常)

50、什么是反射?

  1. 反射就是动态加载对象,并对对象进行剖析。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动 态获取信息以及动态调用对象方法的功能成为 Java 反射机制。

51、反射的作用?

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的方法

52、获取class的三种方式?

  1. 对象调用 getClass() 方法来获取;
  2. 类名.class 的方式得到;
  3. 通过 Class 对象的 forName() 静态方法来获取

53、break和continue的区别?

  1. break 和 continue 都是用来控制循环的语句。
  2. break 用于完全结束一个循环,跳出循环体,执行循环后面的语句。
  3. continue 用于跳过本次循环,继续下次循环。

54、**运行时异常与一般异常有何异同?

  1. 异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。
  2. java 编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。

55、List、Map、Set 三个接口存取元素时,各有什么特点?

  1. List 以特定索引来存取元素,可以有重复元素。
  2. Set 不能存放重复元素(用对象的 equals() 方法来区分元素是否重复)。
  3. Map 保存键值对(key-value pair)映射,映射关系可以是 一对一 或 多对一

56、Collection和Collections的区别?

  1. Collection 是集合类的上级接口,继承于他的接口主要有 Set 和 List。
  2. Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

57、**Error和Exception有什么区别?

  1. error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
  2. exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。

58、EJB 的生命周期,以及如何管理事务?

  1. SessionBean:Stateless Session Bean 的生命周期是由容器决定的,当客户机发出请求要建立一个 Bean 的实例时,EJB 容器不一定要创建一个新的 Bean 的实例供客户机调用,而是随便找一个现有的实例提供给客户机。
  2. 当客户机第一次调用一个 Stateful Session Bean 时,容器必须立即在服务器中创建一个新的 Bean 实例,并关联到客户机上,以后此客户机调用 Stateful Session Bean 的方法时,容器会把调用分派到与此客户机相关联的 Bean 实例。
  3. EntityBean:Entity Beans 能存活相对较长的时间,并且状态是持续的。只要数据库中的数据存在,Entity beans 就一直存活。而不是按照应用程序或者服务进程来说的。即使 EJB 容器崩溃了,Entity beans 也是存活的。
  4. Entity Beans 生命周期能够被容器或者 Beans 自己管理。EJB 通过以下技术管理实务:对象管理组织(OMG)的对象实务服务(OTS),Sun Microsystems 的 Transaction Service(JTS)、Java Transaction API(JTA),开发组(X/Open)的 XA 接口。

59、Comparable和Comparator接口的区别?

  1. Comparable 接口只包含一个 compareTo()方法。这个方法可以个给两个对象排序。具体来说,它返回负数,0,正数。其意义是表明输入对象小于,等于,大于已经存在的对象。
  2. Comparator 接口包含 compare()和 equals()两个方法。

60、switc能否作用在byte、long、string上?

  1. switch 可作用在 char、byte、short、int
  2. switch 可作用于 char、byte、short、int 的包装类上
  3. switch 不可作用于 long、double、float、boolean,包括他们的包装类
  4. switch 中可以是字符串类型,String(Java1.7 以后才可以作用在 String 上)
  5. switch 可以是枚举类型(JDK1.5 之后)

61、jdk中哪些类是不能继承的?

  1. 不能继承的是类是那些用 final 关键字修饰的类。
  2. 一般比较基本的类型或防止扩展类无意间破坏原来方法的实现的类型都应该是 final 的,在 jdk 中 System,String,StringBuffer 等都是基本类型。

62、**Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?

  1. Set 里的元素是不能重复的,元素重复与否是使用 equals()方法进行判断的。
  2. equals() 和 == 方法决定引用值是否指向同一对象
  3. equals() 在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。

63、JDK和JRE的区别是什么?

  1. Java 运行时环境(JRE)是将要执行 Java 程序的 Java 虚拟机。它同时也包含了执行 applet 需要的浏览器插件。
  2. Java 开发工具包(JDK)是完整的 Java 软件开发包,包含了 JRE,编译器和其他的工具(比如:JavaDoc,Java 调试器),可以让开发者开发、编译、执行Java应用程序。

64、是否可以在static环境中访问非 static变量?

  1. static 变量在 Java 中是属于类的,它在所有的实例中的值是一样的。
  2. 当类被 Java 虚拟机载入的时候,会对 static 变量进行初始化。如果你的代码尝试不用实例来访问非 static 的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。

65、Java支持多继承么?

  1. Java 不支持多继承。
  2. 每个类都只能继承一个类,但是可以实现多个接口。

66、什么是迭代器(Iterator)?

  1. Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。
  2. 迭代器可以在迭代的过程中删除底层集合的元素。
  3. 克隆(cloning) 或者是 序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。

67、Iterator和ListIterator的区别是什么?

  1. Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
  2. Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。
  3. ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引等等。

68、Enumeration接口和Iterator接口的区别有哪些?

  1. Enumeration 速度是 Iterator 的 2 倍,同时占用更少的内存。
  2. 但是,Iterator 远远比 Enumeration 安全,因为其他线程不能够修改正在被 iterator 遍历的集合里面的对象。
  3. 同时,Iterator 允许调用者删除底层集合里面的元素,这对 Enumeration 来说是不可能的。

69、List, Set, Map是否继承自 Collection接口?

  1. 只有 List 和 Set 接口继承于 Collection 接口,Map 是与 Collection 并列的接口概念

70、字符串常量池到底存在于内存空间的哪里?

  1. jdk 6.0 字符串常量池在方法区,方法区的具体体现可以看做是堆中的永久区。
  2. jdk 7.0 java 虚拟机规范中不再声明方法区,字符串常量池存放在堆空间中。
  3. jdk 8.0 java 虚拟机规范中又声明了元空间,字符串常量池存放在元空间中。

71、Java中的编译期常量是什么?使用它又什么风险?

  1. 公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 是可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行时不能改变。
  2. 这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了一个新的 jar。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。

72、**用哪两种方式来实现集合的排序?

  1. 可以使用有序集合,如 TreeSet 或 TreeMap,
  2. 也可以使用有顺序的的集合,如 list,然后通过 Collections.sort() 来排序。

73、**说出 JDK 1.7 中的三个新特性?

  1. 虽然 JDK 1.7 不像 JDK 5 和 8 一样的大版本。但是,还是有很多新的特性。
  2. 如 try-with-resource 语句,这样你在使用流或者资源的时候,就不需要手动关闭,Java 会自动关闭。
  3. Fork-Join 池某种程度上是实现 Java 版的 Map-reduce。
  4. 允许 Switch 中有 String 变量和文本。
  5. 菱形操作符(<>)用于类型推断,不再需要在变量声明的右边申明泛型,因此可以写出可读写更强、更简洁的代码。
  6. 另一个值得一提的特性是改善异常处理,如允许在同一个 catch 块中捕获多个异常。

74、**说出 5 个 JDK 1.8 引入的新特性?

Java 8 在 Java 历史上是一个开创新的版本,下面 JDK 8 中 5 个主要的特性:

  1. Lambda 表达式,允许像对象一样传递匿名函数 Stream API,充分利用现代多核 CPU,可以写出很简洁的代码

  2. Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用扩展方法,

  3. 现在,接口中可以有静态、默认方法。

  4. 重复注解,现在你可以将相同的注解在同一类型上使用多次。

75、**ArrayList源码分析?

  1. ArrayList 是一种变长的集合类,基于定长数组实现,使用默认构造方法初始化出来的容量是 10(1.7 之后都是延迟初始化,即第一次调用 add 方法添加元素的时候才将 elementData 容量初始化为 10)。
  2. ArrayList 允许空值和重复元素,当往 ArrayList 中添加的元素数量大于其底层数组容量时,其会通过扩容机制重新生成一个更大的数组。ArrayList 扩容的长度是原长度的 1.5 倍
  3. 由于 ArrayList 底层基于数组实现,所以其可以保证在 O(1) 复杂度下完成随机查找操作。
  4. ArrayList 是非线程安全类,并发环境下,多个线程同时操作 ArrayList,会引发不可预知的异常或错误。
  5. 顺序添加很方便
  6. 删除和插入需要复制数组,性能差(可以使用 LinkindList)
  7. Integer.MAX_VALUE - 8 :主要是考虑到不同的 JVM,有的 JVM 会在加入一些数据头,当扩容后的容量大于 MAX_ARRAY_SIZE,我们会去比较最小需要容量和 MAX_ARRAY_SIZE 做比较,如果比它大,只能取 Integer.MAX_VALUE,否则是 Integer.MAX_VALUE -8。 这个是从 jdk1.7 开始才有的

76、**HashMap源码分析?

  1. jdk1.8 之前 list + 链表
  2. jdk1.8 之后 list + 链表(当链表长度到 8 时,转化为红黑树) HashMap 的扩容因子默认是 0.75,也就是会浪费 1/4 的空间,达到扩容因子时,会将 list 扩容一倍。0.75 是时间与空间一个平衡值;

77、**ConcurrentHashMap源码分析?

  1. ConcurrentHashMap 所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如 size()和 containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在 ConcurrentHashMap 内部,段数组是 final 的,并且其成员变量实际上也是 final 的,但是,仅仅是将数组声明为 final 的并不保证数组成员也是 final 的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。
  2. ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。Segment 是一种可重入锁 ReentrantLock,在ConcurrentHashMap 里扮演锁的角色,HashEntry 则用于存储键值对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组,Segment 的结构和 HashMap 类似,是一种数组和链表结构,一个 Segment 里包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护者一个 HashEntry 数组里的元素,当对 HashEntry数组的数据进行修改时,必须首先获得它对应的 Segment 锁。

二、Java I/O

1、IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞?

  1. 输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。
  2. IO 里面常见的类,第一印象就只知道 IO 流中有很多类,IO 流主要分为字符流和字节流。字符流中有抽象类 InputStream 和 OutputStream,它们的子类有 FileInputStream,FileOutputStream,BufferedOutputStream 等。
  3. 字符流 BufferedReader 和 Writer 等都实现了 Closeable,Flushable,Appendable这些接口。
  4. 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
  5. java 中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,否则程序会一直停留在该语句上,不会执行下面的语句。比如 read() 和 readLine() 方法。

2、谈谈对 NIO 的认知?

  • 对于 NIO,它是非阻塞式,核心类包括:
    1. Buffer 为所有的原始类型提供(Buffer)缓存支持。
    2. Charset 字符集编码解码解决方案
    3. Channel 一个新的原始 I/O 抽象,用于读写 Buffer 类型,通道可以认为是一种连接,可以是到特定设备,程序或者是网络的连接。

3、字节流和字符流的区别?

  1. 字符流和字节流的使用非常相似,但是实际上字节流的操作不会经过缓冲区(内存)而是直接操作文本本身的,而字符流的操作会先经过缓冲区(内存)然后通过缓冲区再操作文件
  2. 以字节为单位输入输出数据,字节流按照 8 位传输
  3. 以字符为单位输入输出数据,字符流按照 16 位传输

4、NIO 和传统的 IO 有什么区别?

  1. 传统 IO 一般是一个线程等待连接,连接过来之后分配给 processor 线程,processor 线程与通道连接后,如果通道没有数据过来就会产生阻塞(线程被动挂起),从而不能做别的事情。
  2. NIO 则不同。首先,在 selector 线程轮询的过程中就已经过滤掉了不感兴趣的事件,其次,在 processor 处理感兴趣事件的 read 和 write 都是非阻塞操作即直接返回的,线程没有被挂起。
  3. 传统 IO 的管道是单向的,NIO 的管道是双向的。
  4. 两者都是同步的,也就是 java 程序亲力亲为的去读写数据,不管传统 IO 还是 NIO 都需要 read 和 write 方法,这些都是 java 程序调用的而不是系统帮我们调用的,NIO2.0 里这点得到了改观,即使用异步非阻塞 AsynchronousXXX 四个类来处理。

5、BIO 和 NIO 和 AIO 的区别以及应用场景?

  1. 同步:java 自己去处理 IO。

  2. 异步:java 将 IO 交给操作系统去处理,告诉缓存区大小,处理完成回调。

  3. 阻塞:使用阻塞 IO 时,Java 调用会一直阻塞到读写完成才返回。

  4. 非阻塞:使用非阻塞 IO 时,如果不能立马读写,Java 调用会马上返回,当 IO 事件分发器通知可读写时在进行读写,不断循环直到读写完成。

  5. BIO:同步并阻塞,服务器的实现模式是一个连接一个线程,这样的模式很明显的一个缺陷是:由于客户端连接数与服务器线程数成正比关系,可能造成不必要的线程开销,严重的还将导致服务器内存溢出。当然,这种情况可以通过线程池机制改善,但并不能从本质上消除这个弊端。

  6. NIO:在 JDK1.4 以前,Java 的 IO 模型一直是 BIO,但从 JDK1.4 开始,JDK 引入的新的 IO 模型 NIO,它是同步非阻塞的。而服务器的实现模式是多个请求一个线程,即请求会注册到多路复用器 Selector 上,多路复用器轮询到连接有 IO 请求时才启动一个线程处理。

  7. AIO:JDK1.7 发布了 NIO2.0,这就是真正意义上的异步非阻塞,服务器的实现模式为多个有效请求一个线程,客户端的 IO 请求都是由 OS 先完成再通知服务器应用去启动线程处理(回 调)。

  8. 应用场景:并发连接数不多时采用 BIO,因为它编程和调试都非常简单,但如果涉及到高并发的情况,应选择 NIO 或 AIO,更好的建议是采用成熟的网络通信框架 Netty。

6、什么是 Java 序列化,如何实现 Java 序列化?

  1. 序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问题
  2. 序列化的实现:将需要被序列化的类实现 Serialize 接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,再使用 ObjectOutputStream 对象的 write(Object obj)方法就可以将参数 obj 的对象写出

7、PrintStream、BufferedWriter、PrintWriter 的比较?

  1. PrintStream 类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成 PrintStream 后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream
  2. BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过 write()方法可以将获取到的字符输出,然后通过 newLine()进行换行操作。BufferedWriter 中的字符流必须通过调用 flush 方法才能将其刷出去。并且 BufferedWriter 只能对字符流进行操作。如果要对字节流操作,则使用 BufferedInputStream
  3. PrintWriter 的 println 方法自动添加换行,不会抛异常,若关心异常,需要调用 checkError 方法看是否有异常发生,PrintWriter 构造方法可指定参数,实现自动刷新缓存(autoflush)

8、 什么是节点流,什么是处理流,各有什么好处,处理流的创建有什么特征?

  1. 节点流 直接与数据源相连,用于输入或者输出
  2. 处理流:在节点流的基础上对之进行加工,进行一些功能的扩展
  3. 处理流的构造器必须要 传入节点流的子类

9、什么是 IO 流?

  1. 它是一种数据的流从源头流到目的地。比如文件拷贝,输入流和输出流都包括了。输入流从文件中读取数据存储到进程(process)中,输出流从进程中读取数据然后写入到目标文件。

10、有哪些可用的 Filter 流?

  1. 在 java.io 包中主要由 4 个可用的 filter Stream。两个字节 filter stream,两个字符 filter stream。分别是 FilterInputStream,FilterOutputStream,FilterReader and FilterWriter。这些类是抽象类,不能被实例化的。

11、Java 中有几种类型的流?

  1. 按照流的方向:输入流(inputStream)和输出流(outputStream)
  2. 按照实现功能分:节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。 如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过 其他流的多次包装,称为流的链接。)
  3. 按照处理数据的单位: 字节流和字符流。字节流继承于 InputStream 和 OutputStream, 字符流继承于 InputStreamReader 和 OutputStreamWriter。

12、如何实现对象克隆?

  1. 有两种方式:
    1. 实现 Cloneable 接口并重写 Object 类中的 clone()方法;
    2. 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

13、什么是缓冲区?有什么作用?

  1. 缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数 据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就可以显著的提升性能。
  2. 对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

14、什么是阻塞 IO?什么是非阻塞 IO?

  1. IO 操作包括:对硬盘的读写、对 socket 的读写以及外设的读写。

  2. 当用户线程发起一个 IO 请求操作(本文以读请求操作为例),内核会去查看要读取的数据是否就绪,对于阻塞 IO 来说,如果数据没有就绪,则会一直在那等待,直到数据就绪;对于非阻塞 IO 来说,如果数据没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪。当数据就绪之后,便将数据拷贝到用户线程,这样才完成了一个完整的 IO 读请求操作,也就是说一个完整的 IO 读请求操作包括两个阶段:

    1. 查看数据是否就绪;
    2. 进行数据拷贝(内核将数据拷贝到用户线程)。
  3. 那么阻塞(blocking IO)和非阻塞(non-blocking IO)的区别就在于第一个阶段,如果数据没有就绪,在查看数据是否就绪的过程中是一直等待,还是直接返回一个标志信息。 Java 中传统的 IO 都是阻塞 IO,比如通过 socket 来读数据,调用 read()方法之后,如果数据没有就绪,当前线程就会一直阻塞在 read 方法调用那里,直到有数据才返回;而如果是非阻塞 IO 的话,当数据没有就绪,read()方法应该返回一个标志信息,告知当前线程数据没有就绪,而不是一直在那里等待。

三、Java Web

1、session 和 cookie 的区别?

  1. session 是存储在服务器端,cookie 是存储在客户端的,所以安全来讲 session 的安全性要比 cookie 高,然后我们获取 session 里的信息是通过存放在会话 cookie 里的 sessionid 获取的。又由于 session 是存放在服务器的内存中,所以 session 里的东西不断增加会造成服务器的负担,所以会把很重要的信息存储在 session 中,而把一些次要东西存储在客户端的 cookie 里
  2. 然后 cookie 确切的说分为两大类分为会话 cookie 和持久化 cookie:
    1. 会话 cookie 确切的说,是存放在客户端浏览器的内存中,所以说他的生命周期和浏览器是一致的,浏览器关了会话 cookie 也就消失了
    2. 然而持久化 cookie 是存放在客户端硬盘中,而持久化 cookie 的生命周期就是我们在设置 cookie 时候设置的那个保存时间,然后我们考虑一问题当浏览器关闭时 session 会不会丢失
    3. 从上面叙述分析 session 的信息是通过会话 cookie 的 sessionid 获取的,当浏览器关闭的时候会话 cookie 消失所以我们的 sessionid 也就消失了,但是 session 的信息还存在服务器端,这时我们只是查不到所谓的 session 但它并不是不存在。
    4. 那么,session 在什么情况下丢失,就是在服务器关闭的时候,或者是 session 过期(默认时间是 30 分钟),再或者调用了 invalidate() 的 或者是我们想要 session 中的某一条数据消失调用 session.removeAttribute()方法
    5. 然后 session 在什么时候被创建呢,确切的说是通过调用 getsession()来创建,这就是 session 与 cookie 的区别.
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值