0


Java核心技术面试题(附答案),纯手码,赶紧带走冲刺10月秋招

1.Java语言有哪些优势 ?

    1.面向对象(封装,继承,多态);

    2.平台无关性(Java虚拟机实现了平台无关性) ;

    3.可靠性;

    4.安全性;

    5.支持多线程;

    6.支持网络编程;

    7.执行方式采用了解释执行 + 编译执行并存的方式;

    8.实践应用案例很丰富。

2.什么是JVM,JRE,JDK ?

    JVM

            JVM是Java虚拟机(Java Virtual Machine) 的缩写,用于运行Java字节码文件(*.class文件)。JVM针对不同的操作系统都有特性的实现(例如Windows,Linux,nacOC),目的是使用相同的字节码啊,在不同操作系统运行结果相同,是Java实现跨平台的核心机制。Java中默认虚拟机为HotSpot VM,除此之外还有JRockit(BEA),j9(IBM),TaoBaoVM(淘宝)等虚拟机;

    JRE

            JRE全称Java Runtime Environment(Java运行时环境)。JRE包括Java虚拟机和Java程序我所需要的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。

    JDK

            JDK是Java开发工具包(Java Development Kit)的缩写,是提供给Java开发人员使用的,JDK中包含JRE以及开发,调节和监视应用程序的工具,编译工具(javac.exe),打包工具(jar.exe),Java监控和管理平台(jConsole,jvisualvm)等,

    JDK包含JRE,JRE包含JVM。 所以JDK > JRE > JVM。

3.Java中常见的基本数据类型有哪些 ?

    Java中的基本数据类型共有8种,分别是:

            数值类型:

                    整型:

                             1.byte        字节型,内存中占1个字节。

                            2.short        短整型,内存中占2个字节。

                            3.int            整型,内存中占4个字节。

                            4.long         长整型,内存中占8个字节。

                    浮点型:

                            5.float        单精度浮点型,内存中占4个字节。

                            6.double     双精度浮点型,内存中占8个字节。

            非数值类型:

                            1.char        字符型,内存中占两个字节。

                            2.boolean        布尔型(在Java虚拟机里采用8位二进制数表示布尔值,00000001表示true,00000000表示false)。boolean类型被编译成int类型来使用,占4个byte。boolean数组被编译成byte数组,每个boolean数组成员占1个byte。

4.Java中的浮点数为什么不精确 ?

    计算机使用二进制运算,程序中1的十进制数先转换成二进制,再进行运算。Float和Double的小数部分在转换成二进制时容易产生无线循环的情况,通常都是取无限接近于原值的近似值,所以导致出现精度丢失的情况。(在金融,建筑,工程,科学等领域,对计算数值的精度要求一般比较高,为了避免计算结果不精准,往往采用BigDecimal + 字符串来解决精度丢失的问题。)

    例如:
BigDecimal d1 = new BigDecimal("0.1");
BigDecimal d2 = new BigDecimal("0.2");
BigDecimal d3 = d1.mutiply(d2);        //计算0.1 × 0.2的精确值。
double result = d3.doubleValue();      //获取double类型的结果。

5. & 和 && 有什么区别呢 ?

    "&按位与" 运算 当位运算符时,a & b时把a和b都转换成二进制数,然后再逐位进行"与运算",同时为1结果为1,否则为0;
int result;
result = 9 & 8;    //9 & 8 = 1001(9) & 1000(8) = 1000(8).
System.out.println(result);         //result = 8
    "&不断路与"运算符 当逻辑运算符时,当执行"表达式1 & 表达式2"时,表达式1等于true或者false,都会继续执行表达式2,执行不会中断。
int i = 3;
if(i++ > 5) & (i++ < 9){
   System.out.println("if语句执行啦");    //该语句未执行
}
System.out.println(i);        //结果输出i = 5,说明执行了两个i++
    "&&短路与"运算 当逻辑运算符,当执行"表达式1 && 表达式2"时,表达式1等于false,执行会中断,表达式2不会执行。 
int i = 3;
if((i++ > 5) && (i ++ < 9)) {
    System.out.println("if语句执行啦");
}
System.out.println(i);        //输出 i = 4,说明 i++只执行了一次。也就说明if语句只判断了 i++ > 5, 结果weifalse,退出if判断语句。

6. 什么是数组 ?

    1.数组时一种引用数据类型,用于保存一组相同类型的数据结构,长度固定;

    2.使用连续的内存空间进行存储,所以元素有序,遍历速度较快。

    3.下标从0开始,尾下标为长度-1,引发ArrayIndexOutOfBoundsException数组下标越界异常;

7. 谈谈你对Arrays工具类的理解 ?

    1.Arrays类时JDK提供专门用来操作数组的工具类,该类提供了大量的静态方法完成对于数据的常见的操作。

    2.static List asList(T...a)  //按照动态参数,创建一个ArrayList集合(内部类)

    3.static void sort(int[] a)   //数组排序(快速排序算法)

    4.static int binarySearch(Object[] a ,  Object key)  //搜索(二分查找算法)

8. == 和 equals() 的区别 ?

  • ==是运算符

     1.基本数据类型 == 用于比较值。
    
     2.引用数据类型 == 用于比较内存地址。
    
  • equals()是Object类中的方法

      1.基本数据类型不能使用equals()
    
      2.引用数据类型如果没有重写equals() ,会默认使用Object类的equals() , 在该方法中采用 == 进行比较内存地址,所以引用数据类型会重写equals() ,可以进行值或内容的比较。例如String类。
    

9.hashCode() 或HashCode的作用是什么 ?

    1.hashCode()是Object类中的native本地方法,底层使用c/c++语言实现,用于获取对象的HashCode哈希码。

    2.HashCode哈希码是该对象的内存地址通过哈希hash算法计算出的一个整数值,代表该对象在哈希表中的位置,作用主要是为了提高查找对象的快捷性,通过HashCode可以快速定位对象的存储地址,

    3.两个对象进行比较,先通过HashCode比较,如果HashCode相等,再条用equals()方法比较,提高效率;

10. 为什么要有 hashCode() ? (以"HashSet如何检查重复"为例子来说明为什么要有hashCode)

    1.当你把对象加入HashSet时,HashSet会先获取该对象的hashCode值,来计算该对象加入的位置,同时与其他已经加入的对象的hashcode值作比较。

    2.如果没有重复的hashCode,HashSet会假设对象没有重复出现,正常添加。

    3.如果发现有相同hashCode值的对象,这时会条用equals()方法来检查hashCode相等的对象是否真的相同。

    4.如果两个相同,HashSet就不会其加入操作成功。

    5.如果两者不同,就会重新散列到其他位置。

    6.这样就大大减少了equals()的执行次数,相应就提高了执行速度。

11.为什么重写equals()时必须重写hahsCode()方法 ?

    equals() 方法和hashCode()方法之间的关系应符合。

            1. 如果两个对象相同(即:用equals比较返回true),那么它们的hashCode值一定要相同。

            2. 如果两个对象的hashCode相同,他们并不一定相同(用equals比较)。

    综上所述,在每个覆盖了equals()方法的类中,也必须覆盖hashCode()方法,如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致HashSet和HashTable等集合。另外,可以避免equals()被频繁调用,减少性能开销。

12. 什么是装箱和拆箱 ?

  •     装箱:将基本类型转换成它们对应的引用类型,例如:Integer i = 666;
    
  •     拆箱:将包装类型转换成基本数据类型,例如:int n =  i;
    

13. 基本类型的包装器类型有哪些 ?

    1. byte(1字节) :      Byte类

    2.short(2字节):       Short类

    3.int(4字节):            Integer类

    4.long(8字节):         Long类

    5. float(4字节):        Float类

    6. double(8字节):    Double类

    7.char(2字节):         Character类

    8.boolean(未定):     Boolean类

14.包装类中的常量池技术有什么作用 ?

    1. Byte,Short,Integer,Long创建范围在[-128 , 127]的缓存数据;

    2.Character创建范围在[ 0 , 127]的缓冲数据;

    3.如果数据处于缓存范围,不必重新创建对象,直接从缓存中获取,减少对象重复创建所带来的内存与性能开销;

    4.如果数据超出缓存范围,才会创建新的对象。

    例如:
//使用常量缓存池,同一内存地址,输出true
//强调一下Integer是引用数据类型,== 比较基本类型比较值,比较引用类型比较地址
Integer n1 = 33;    
Integer n2 = 33;
System.out.println(n1 == n2);

//超出常量缓存池范围,重新分配内存地址,输出false
Integer n3 = 130;
Integer n4 = 130;
System.out.println(n3 == n4);

// n5从常量缓存池取,n6使用new关键字创建,非同一内存地址,输出false
Integer n5 = 40;
Integer n6 = new Integer(40);
System.out.println(n5 == n6);

15. 什么是字符串常量池(String Pool) ?

    1.JVM为了提升性能和减少内存开销,避免字符串的重复创建,维护了一块特殊的内存空间,用于保存常量字符串,即字符串常量池(String Pool),JDK1.7以后,字符串常量池从方法区移到Heap堆区;

    2.字符串常量池的优点(String Pool):避免了相同内容字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能。

16.Java是按值传递还是按引用传递 ?

  •     值传递(pass by value):
    
                      值传递是指在调用方法时,按实际参数的值或内存地址复制一份传递到方法中。
    
  •     引用传递(pass by reference):
    
                      引用传递是指在调用方法时,将实际传输的内存地址直接传递到方法中(不创建参数值或者内存地址的副本)。
    
      在Java中,都是值传递,如果参数时基本类型,复制参数的值,传递给方法。如果参数时引用类型,复制对象参数的Heap堆中内存地址值,传递给方法。
    

17. 重载和重写的区别 ?

  •     重载:
    
                      1.重载发生在编译期,是同一个类中,多个同名方法根据不同传参,执行不同的逻辑处理;
    
                      2.重载发生范围在同一个类中;
    
                      3.方法的参数列表必须不一致(类型不同,个数不同,顺序不同);
    
                      4.方法的返回值和访问修饰符可以不同;
    
                      5.构造方法可以被重载;
    
  •     重写:
    
                      1.重写发生在运行期,是子类对父类方法的内部逻辑重新改造,外部定义不能改变;
    
                      2.重写发生范围在子类中;
    
                      3.参数列表必须与弗雷方法完全一致;
    
                      4.方法名,参数列表必须相同,返回值类型和抛出的异常范围小于等于父类,访问权限修饰符范围大于等于父类;
    
                      5.如果父类方法访问权限修饰符为private/final/static,则子类就不能重写该方法;
    
                      6.构造方法不能被重写;
    

18. 什么是浅拷贝,什么是深拷贝 ?

    浅拷贝(Shallow Copy):

            拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用所指向的对象,实现方式是实现Cloneable接口,重写clone()方法。

    深拷贝(Deep Copy):

            深拷贝不仅拷贝对象本身,而且还需要拷贝对象所包含的引用指向的所有对象(层层拷贝),实现方式有两种。

            方式一:

                    为拷贝的对象包含的每个引用的类型去实现Cloneable接口,重写clone()方法(实现的步骤很繁琐,但是执行效率高)。

            方式二:

                    用对象序列化来实现深拷贝。(实现起来相对简单,但是执行效率较低)。

19.成员变量与局部变量的区别有哪些 ?

    1. 从语法形式上来说:

            成员变量是定义在类中的,而局部变量是在代码块或者方法中定义的变量或者是方法的参数,成员变量可以被public,private,static等修饰符修饰,局部变量不能被访问控制修饰符以及static修饰,但是成员变量和局部变量都可以被final修饰符修饰。

    2. 从内存中的存储方式来说:

            如果成员变量是使用static修饰的,那么这个成员变量是属于类的,如果没有使用static修饰,那么这个成员变量是属于对象。而对象存在于堆内存,局部变量则是存在于栈内存。

    3. 从变量在内存中的生存时间来说:

            成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。

    4.从是否被赋初始值:

            成员变量如果没有被赋初始值,则会自动以类型的默认值而赋初始值,如果该成员变量被final修饰则必须显式的赋初值,而局部变量则不会自动赋值。

20. 什么是构造方法 ?

  •      构造方法名称与类名一致;
    
  •      构造方法没有返回值类型这一结构,不能用void声明构造函数;
    
  •      创建对象时,使用new关键字调用执行构造方法;
    
  •      一个类即使没有声明构造方法,Java会提供默认的无参构造方法。
    

21. 构造方法的作用是什么 ?

    1.构造方法的主要作用是用于完成创建对象的初始化工作。

    2.Java为每个类提供了默认的无参数构造方法,如果我们为一个类定义有参构造方法时,Java就不会在提供无参数构造方法。

    3.当我们为一个类重载构造方法时,应当把无参数的构造方法也定义出来(无论是否会用到,都建议),因为这样可以确保在任何场合下,该类都有无参数的构造方法可以使用。(Spring框架中创建bean,默认采用无参数构造方法)。

22.面向对象的三大特征是什么 ?

  •     1.封装:
    
                      封装的目的是隐藏事务内部的实现细节,以便提高安全性和简化编程。是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息,只能通过允许被外界访问的方法来操作属性。
    
  •       2.继承:
    
                      继承是代码复用的基础机制,使用已存在的类定义作为基础来拓展创建新类,新类的定义可以增加新的数据或新的功能。通过使用继承,可以快速地拓展出新类的定义,可以提高代码的重用,程序的可维护性,提高我们的开发效率。
    
  •       3.多态:
    
                      多态顾名思义,表示一个对象具有多种的状态。具体表现为父类的引用指向子类的实例,使应用程序扩展更灵活。
    

23. 什么是多态 ?

    多态表示一个对象具有多种状态。具体表现为父类的引用指向子类的实例。在Java中多态主要体现在重载,重写,向上(向下)转型等。

    多态的特点:

            1.多态中对象类型和引用类型之间必须具有继承类或者实现接口的关系;

            2.多态中引用类型变量调用的方法,究竟是调用哪个类中的方法,在程序运行期间才能确定(具体是那个方法只能根据引用指向的对象的真正类型去决定)。

            3.多态中不能通过父类的引用去调用只在子类中存在但父类中不存在的方法;

            4.多态中,如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。

24.Java中如何实现多态 ?

    Java中多态的实现方式:

            1.实现接口;

            2.继承父类进行方法重写;

            3.同一个类中进行方法重载;

            4.运行时确定由某个具体实现类或子类,对于某行为方法(重写或者重载)的调用执行,达到运行结果的多态化。

25. String为什么是不可变的 ?

    1.String类中使用final关键字修饰用来保存字符串内容的数组。

    2.JDK8采用char数组:private final char value[];

    3.JDK9采用byte数组:private final byte[] value;

26.String与StringBuffer / StringBuilder有什么区别 ?

    可变性:

            1.String使用final关键字修饰,不管是char数组或者byte数组,所以String是不可变的;

            2.StringBuilder与StringBuffer都继承自AbstractStringBuilder父类,在AbstractStringBuilder中使用char[] value字符数组保存字符串,但是没有用final关键字修饰,所以StringBuilder与StringBuffer都是可变的。

    性能:

            1.每次对String类型进行修改时,都会生成一个新的String对象,性能和内存开销都比较大;

            2.StringBuffer和StringBuilder的操作是直接改变字符串对象本身,而不是生成新的对象,所以性能开销小。

27. StringBuffer和StringBuilder有什么区别 ?

    线程安全:

            1. StringBuffer对操作方法加了synchronized同步锁,所以是线程安全的。

            2. StringBuilder并没有对方法进行加同步锁,所以是线程不安全的。

    性能:

            1.StringBuffer线程安全,开销大,性能低;

            2.StringBuilder线程不安全,开销小,性能高;

            3.相同情况下,使用StringBuilder相比使用StringBuffer能获得10%~15%左右的性能提升,但需要承担多线程不安全的风险;     

28.String,StringBuffer,StringBuilder如何选择使用 ?

    1. 字符串少量修改时,选择使用String;

    2. 单线程频繁修改字符串时,选择使用StringBuilder;

    3. 多线程频繁修改字符串时,选择使用StringBuffer;

29.String类中有哪些常见方法 ?

    1. indexOf() :返回指定字符的索引。

    2. charAt() :返回指定索引处的字符。

    3. replace():字符串替换。

    4. trim():去除字符串两端空白。

    5. split():分割字符串,返回一个分割后的字符串数组。

    6. getBytes():返回字符串的byte类型数组。

    7. length():返回字符串长度。

    8. toLowerCase()/toUpperCase():将字符串转成小写/大写字母。

    9. substring():截取字符串。

    10. equals():字符串比较。

30. String中 intern() 方法的作用是什么 ?

    如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回常量池中字符串的引用(内存地址),否则将新的字符串放入常量池中,并返回新字符串的引用(内存地址)。

31. final关键字的用法有哪些 ?

    1. final修饰的类为最终类,该类不能够被继承。

    2. final修饰的方法为最终方法,该方法不能被子类重写。

    3.final修饰常量,常量必须初始化,初始化之后就不能被修改。

            1). 基本类型:

                    final修饰基本类型的常量,初始化复制后不能被修改;

            2). 引用类型:

                    final修饰引用类型的常量,初始化对象后,不能重新分配内存空间。

32. final,finally,finalize的区别 ?

    1. final用于声明变量,方法和类,分别表示常量,方法不可重写,类不可继承。

    2. finally是异常处理语句结构的一部分,表示无论是否出现总是会执行的代码段。

    3.finalize是Object类中的一个方法,在垃圾收集器执行的时候,会调用被回收对象的finalize()方法,供垃圾收集时执行其他资源回收等操作,例如关闭文件,释放连接等操作。

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

    1.首先从定义方面讲:抽象类使用abstract class关键字,接口使用interface;

    2.从实现方面讲:抽象类的子类使用extends来继承,接口的实现类必须使用implements来实现,类可以实现多个接口,但是只能继承一个类(当然也包括抽象类);

    3.从继承方面来讲:抽象类之间只能单继承,接口直接允许多重继承;

    4.从构造方法方面来讲:抽象类有构造方法(来给子类创建对象用的),接口不允许有构造方法;

    5.抽象类中既可以定义抽象方法也可以定义实例方法,但接口中只允许定义抽象方法(Java8开始,也可以使用default定义默认方法);

    6.从访问权限修饰符来讲:接口中的方法只能使用public修饰,抽象类中的方法却可以用任意的访问权限修饰符来修饰。

    总结:

            1. 接口时对行为的抽象,时抽象方法的集合,利用接口可以达到行为定义和业务实现分离的架构设计目的,并且接口的多重实现以及多继承等特性,在架构设计上更加灵活多变,可拓展性更高。

            2. 抽象类大多用于抽取相关子类的共用行为方法实现或者时共同成员变量,然后通过继承的方式达到代码复用的目的。同时抽象类中的抽象方法还可以用于约束子类对于某种行为必须进行实现。例如Java核心类库中有很多子类的通用部分被抽取成为抽象类,如集合框架中的java.util.AbstractList,字符串的java.lang.AbstractStringBuilder等;

34.说说static关键字的主要使用场景有哪些 ?

    1. 修饰成员变量和成员方法,被static声明的成员变量属于静态成员变量,存放在JVM内存区域的方法去,被static修饰的成员方法时属于类的,是被类中所有的对象所共享的,可以通过类名或者对象名去调用。

    2. 修饰代码块使之成为静态代码块,静态代码块在代码块之前执行,代码块在构造方法前执行,不管创建多少个类的对象,该类中的静态代码块只执行一次。

35.静态方法与实例方法的区别有哪些 ?

    1.静态方法是属于类本身的,而实例方法是属于该类的每个对象实例的;

    2.在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式,但是一般都是通过前者调用方式去调用,也就是说调用静态方法时无需创建对象实例的;

    3.静态方法在访问本类的成员时,只允许访问静态成员变量和静态方法,而不允许访问成员变量和实例方法,而实例方法则无此限制。

36. 说说静态代码块static{} 与代码块{}的相同点和不同点 。

    相同点:

            都是在JVM加载类时且先于构造方法执行前执行的,在类中可以定义多个,相同类型定义多个时,按照定义的先后顺序执行;

    不同点: 

            1. 静态代码块在代码块之前执行,执行顺序为静态代码块,代码块,构造方法。

            2. 静态代码块只在第一次使用new关键字创建对象前执行一次,之后不会再次执行,而代码块再每次new对象时都会执行一次。

            3. 静态代码块不可以在普通方法中定义,而代码块可以在普通方法中定义(无意义)。

37.Object类中有哪些常见的方法 ?

    //返回对象的Class对象(反射时使用)
public final native Class<?> getClass()
    //返回对象的哈希码
public native int hashCode()
    //比较两个对象的内存地址是否相等
public boolean equals(Object obj)
    //返回当前对象的拷贝(浅拷贝对象)
protected native Object clone()
    //返回对象的类名 + 对象的哈希码16进制字符串
public String toString()
    //唤醒在此对象锁上等待的一个线程,如果有多个线程等待,只会任意唤醒一个
public final native void notify()
    //唤醒所有在此对象锁上等待的所有线程,而不是一个线程
public final native void notifyAll()
    //调用该方法的线程进入等待状态,只有等待另外线程的通知或被中断才会返回
public final native void wait() throws InterruptedException
    //对象被垃圾回收器回收时调用的方法
protected void finalize() throws Throwable

38. Java中常见接口有哪些 ?

    1.集合框架:Collection接口,List接口,Set接口,Map接口;

    2.比较器:Comparator接口,Comparable接口;

    3.IO操作:Closeable接口(可以关闭的文件流);

    4.标记接口:RandomAccess接口(集合元素随机访问),Serializable接口(序列化),Cloneable接口(对象克隆);

    5.线程接口:Runnable接口。

39. 什么是异常 ?

   1. 异常Exception,是指程序运行时,由于输入错误,网络,程序逻辑等原因导致运行时出现的问题,出现异常时,程序会暂时终端执行,并根据产生异常的原因,创建对应异常类型的异常对象,并抛出给JVM捕获处理;

    2. 在Java中,主要使用try - catch,finally,throw,throws 来处理异常。

40. 你是如何理解Java中的异常体系的 ?

    1. Throwable类可以用来表示可以作为异常抛出的类,是所有异常类的父类;

    2. Throwable类有两个子类,分别是Error类和Exception类。

    3. Error类描述程序运行时系统的内部错误,通常比较严重,用于通知用户和尽量使应用程序安全终止,应用程序不应该尝试去捕获这种异常。通常为JVM虚拟机异常,例如:StackOverflowError等。

    4.Exception类用于描述运行时异常类型。Exception类下面又分为两个子类分支,一个分支派生自RuntimeException,这种异常通常为程序错误导致的异常;另一个分支派生自RuntimeException,这种异常通常为程序错误导致的异常;另一个分支为非派生自RuntimeException的异常,这种异常通常是程序本身没有问题,由于I/O错误,网络等问题导致的异常。

41.Error和Exception的区别是什么 ?

    1. Error类型的错误通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA应用程序也不应对这类错误进行捕获,一旦这类错误发生,应用程序通常会被终止,仅靠应用程序本身无法恢复;

    2. Exception类型的异常是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。

42. throw 和 throws的区别是什么 ?

    throw关键字用来抛出方法或者代码块中的异常对象,检查异常和非检查异常都可以被抛出,在方法内部使用;

    throws关键字用来标识该方法可以抛出的异常类型列表,在方法定义时,在参数列表之后和方法体之前进行定义。

43. 检查型异常和非检查型异常有什么区别 ?

    1. 继承Exception类的异常是检查型异常,都需要使用try - catch和finally关键字在编译阶段进行处理,否则会出现编译器报错;

    2.继承RuntimeException的异常时非检查型异常,可以不处理。

44. 如果在try/catch中出现return,会执行finally中的语句吗 ?

    1. 在执行try,catch中的return 之前一定会执行finally中的代码;

    2. 如果finally中有return语句,就会直接执行finally中的return语句;

    3. finally是在return后面的表达式运算之后执行,此时并没有返回运算结果值,而是把值临时保存起来。不管finally对该值做任何的改变,返回值都不会改变,依然返回之前临时保存起来的值。

45. Java中的常见异常有哪些 ?

    1. NullPointerException 空指针异常:调用未实例化的null引用,引发该异常;

    2. ClassNotFoundException 找不到类异常:按照类的完全限定名加载一个不存在的类(如反射时),会引发该异常;

    3. NumberFormatException 数字格式化异常:将字符串转换为数字时,如果该字符串中包含非数字内容时,会引发该异常;

    4. IndexOutOfBoundsException 下标越界异常:数组或字符串下标超出范围时,会引发该异常;

    5. IllegalArgumentException 不合法参数异常:传入参数不合法,引发该异常;

    6. ClassCastException 类型转换异常:转换不符合的Class类型,引发该异常;

    7. SQLException SQL异常:在操作数据库时,产生SQL语法错误时,会引发该异常;

    8. IOException 读写异常:对文件流进行IO读写操作发生错误时,会引发该异常;

    9.NoSuchMethodException 方法不存在异常:找不到调用方法,引发该异常。

46. 枚举是什么 ?

    1.在Java中,被enum关键字修饰的类型就是枚举类型,枚举类型是JDK1.5中引入的新特性(ebum的全称是enumeration);

    2.枚举类型的作用是将常量组织起来,统一的进行定义管理,例如错误码,状态码等等;

    3.枚举本质上是一种受限制的类,创建一个enum枚举类型,编译器会为该枚举类生成一个相关的类,这个类默认继承自java.lang.Enum。

47. 你对Java集合是怎么理解的:

    1. Java中的集合框架主要是由java.util包中的集合接口与实现类组成的,主要包括Collection接口和Map接口以及相关实现类,并且包括Iterator迭代器和Collections等工具类;

    2. Collection接口包含List接口和Set接口;

    3. List是有序列表集合,元素可以重复,索引从0开始,实现类由LinkedList,ArrayList,Vector;

    4. Set是无需散列集合,元素不允许重复,Set的实现类有HashSet和TreeSet。HashSet是使用HashMap来实现存储的;TreeSet是使用TreeMap实现存储的;

    5. Map是键值对集合接口,采用key - value键值对保存的,实现类有HashMap,TreeMap,LinkedHashMap,Hashtable;

    6. Iterator迭代器接口用于遍历集合,用于遍历List和Set;

    7.Collections是操作集合的工具类,包含有排序,搜素,乱序等方法。

48. List,Set,Map三者的特点是 ?

    1. List 集合存储的元素是有序的是可重复的;

    2. Set 集合存储的元素是无序的是不可重复的;

    3. Map集合是使用键值对存储的,Key是无序且不可重复的,Value可重复,每一个Key都映射有一个Value。

49. 如何更好的选择集合 ?

    根据集合的特点去选择:

            1. 需要根据键值获取元素值时就选用Map接口下的集合,需要排序时就选择TreeMap,不需要排序时就选择HashMap,需要保持有序选择时就选择LinkedHashMap;

            2. 只需要存放元素值时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如说TreeSet或者HashSet,不需要保证元素唯一时选择实现List接口的ArrayList或者LinkedList。

50. 如何对集合进行排序 ?

    使用Collections.sort()方法对List集合内元素进行排序,排序时的比较规则有两种实现方式:

            1.排序时,List集合内的元素类型实现Comparable接口(默认比较器),重写comparaTo(T obj)方法,用来进行排序时,实现默认的比较规则;

            2.排序时,给sort() 方法传入Comparator接口实现类对象(自定义比较器),重写compare(T obj1, T obj2)方法,用来进行自定义比较规则排序。

51. ArrayList和Vector区别 ?

    1. 初始容量:

            1. ArrayList初始默认容量为0;添加第一个元素时,扩容为10;

            2. Vector初始默认容量为10;

    2. 扩容方式:

            1. ArrayList在原有容量基础上扩容0.5倍;

            2. Vector在原有容量基础上,扩容1倍;

    3. 线程安全:

            1. ArrayList是线程不安全的;

            2. Vector是线程安全的;

    4. 执行效率:

            1.Vector的方法都是由同步锁的,在方法执行期间需要加锁,解锁,所以性能会低于ArrayList。

52. ArrayList与LinkedList的区别 ?

    1. 底层数据结构:ArrayList底层使用的是Object数组,LinkedList底层使用的是双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环);

    2. 插入和删除元素: ArrayList采用数组存储,插入删除时需要移动元素,所以性能较差,LinkedList采用链表存储,性能比较高;

    3. RandomAccess接口:使用Collections.binarySearch查找元素时ArrayList实现了RandomAccess接口,使用indexdBinarySearch(基于下标的二分查找)。而LinkedList没有实现该接口,使用iteratorBinarySearch(基于迭代器的二分查找),ArrayList支持随机高效的访问,但LinkedList不支持随机高效的访问。

53. List的遍历例方式该如何选择?

    1.实现了RandomAccess接口的List集合,优先选用普通的for循环,其次选择foreach;

    2.未实现RandomAccess接口List集合,优先选择iterator遍历(foreach遍历底层也是通过iterator的方式进行的),当未实现RandomAccess接口的List集合存储的元素过多时,千万勿使用普通的for循环。

54. 谈谈ArrayList的扩容机制 。

    1.使用无参数构造方法创建ArrayList时,实际上初始化赋值的时一个空数组,当向数组中添加第一个元素时,数组容量扩为10;

    2.当数组容量不足时,调用grow()方法进行扩容,每次扩容后容量都会变为原来的1.5倍作右(在原有容量基础上,扩0.5倍);

    3.最大容量为Integer.MAX_VALUE 或着 Integer.MAX_VALUE - 8;

55. CopyOnWriteArrayList是什么 ?

    1. CopyOnWriteList是java.util.concurrent并发包提供的线程安全的List集合容器,兼顾安全与性能,用于在线程安全场景下取代Vector和ArrayList;

    2. CopyOnWriteArrayList在add(),set(),remove()等操作时,通过ReentrantLock加锁,然后复制出来一个新数组的方式来实现线程安全;

    3. CopyOnWriteArrayList适合读操作多,写操作少的应用场景。

56.CopyOnWriteArrayList有啥缺点 ?

    1. 内存占用:

            如果 CopyOnWriteArrayList经常要增删改集合中的数据,执行add(),set(),remove()方法,每次都需要复制一个新数组,比较耗费内存;

    2. 数据一致性:

            CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性,因为增删改操作的是新数组,读取操作的是原数组。

57.CopyOnWriteArrayList的实现原理是什么 ?

    1. CopyOnWriteArrayList的所有修改操作的底层原理都是通过创建数组的新副本来实现。

    2. 当CopyOnWriteArrayList需要被修改的时候,并不修改原有内容,而是对原有数据进行一次性复制,将修改的内容写入新的副本中,然后再将修改完的副本替换原来的数据,这样就可以保证写操作不会影响都操作了。

58. CopyOnWriteArrayList为什么并发安全且性能比Vector好 ?

    1. Vector是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获取锁,性能就会大大降低;

    2. 而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector,CopyOnWriteArrayList支持读多写少的并发情况。读写分离,写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array。

59.HashSet,LinkedHashSet和TreeSet有那些区别 ?

    1. HashSet是Set接口的主要实现类,它是无序的,HashSet的底层实现是HashMap,HashSet是线程不安全的,可以存储null值;

    2. LinkedHashSet是HashSet的子类,它是有序的,它能够按照所添加的顺序进行遍历;

    3. TreeSet集合底层使用红黑树,它能够按照添加元素的顺序进行遍历,并且可以自动进行排序(需实现Comparable接口或者Comparator接口)。

60.HashSet是如何检查重复的 ?

    1.当对象加入HashSet时,HashSet会先计算对象的hashCode值来判断对象将要添加的位置,如果该位置没有其他元素,则代表不重复;

    2.如果该位置存在其他元素,会比较该位置链表内的其他元素的hashCode值,如果没有相同的hashCode,代表不重复;

    3.如果发现有相同的hashCode,接下来会调用equals()方法来检查这两个元素是否相同,如果equals()比较的结果是true,代表重复,否则代表不重复。

标签: java JDK Java面试

本文转载自: https://blog.csdn.net/chen_kai_fa/article/details/125500937
版权归原作者 是小陈呀~ 所有, 如有侵权,请联系我们删除。

“Java核心技术面试题(附答案),纯手码,赶紧带走冲刺10月秋招”的评论:

还没有评论