Java 面试题之面向对象(OOP) 部分(二)

3.1. int 和 Integer 有什么区别?

      Java 语言是一个面向对象的语言,但 Java 中的基础类型不是面向对象的,为了解决这个问题,在设计类时为每个基本类型设计了一个包装类(Wrapper Class)。

      Java 的数据类型分为基础数据类型和引用数据类型。对应八个基本数据类型的封装类分别为 Byte、Boolean、Character、Integer、Long、Float、Double、Short。封装类可以对对象进行操作,并且带有处理处理值的相关方法。

3.2. int 与 String 如何相互转化?

      int -》 String:

String string = String.valueOf(i);

      String -》 int:

int num = Integer.parseInt(string);

3.3.在 Java 中如何引发异常?对异常处理的两条途径是什么?

      在 Java 语言中,可以使用 throw 关键字来引发异常。

      对异常处理的两条途径为:

      1)使用 throws 抛出异常;

      2)使用 try ... catch 捕获异常

扫描二维码关注公众号,回复: 9257014 查看本文章

3.4.异常分为几种类型?

      异常(Exception)分为两类,运行时异常(非检查时异常)和 非运行时异常(检查时异常)

      非运行时异常表示程序的代码逻辑存在错误,应该尽可能避免其出现的异常。Java 编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求声明未被捕获的运行时异常。

      常见的运行时异常:

      1)NullPointerException(空指针异常):操作一个空引用时会出现此异常;

      2)NumberFormatException(数字格式化异常):试图将字符串转化为数值类型时,但字符串无法转化成适当格式时,抛出该异常;

      3)ClassCastException(强制转换异常):强制类型转换类型不匹配时出现此异常;

      4)ArrayIndexOutOfBoundsException(数组下标越界异常):当使用一个不存在的数组下标时,出现此异常;

      5)ArthimaticException(数字异常):当出现异常的运算条件时,出现此异常。

      常见的非运行时异常:

      1)SQLException:提供关于数据库访问错的异常;

      2)IOException:当出现IO错误时,出现此异常;

      3)ClassNotFoundException:当应用程序试图使用 Class 类中的 forName 方法、loadClass 方法时,出现此异常。

3.5. try {} 里有一个 return,那么跟在 try 后面的 finally {} 里的 code 是否执行?什么时候执行?

      finally 里的 code 会在 return 前面执行。

3.6.当使用多个 catch 语句捕获多个异常时,Java 规定捕获 Exception 的 catch 语句必须排在最后,谈谈对此的理解?

try {...}
catch (ClassCastException) {...}
catch (NumberFormatException) {...}
catch (ArrayIndexOutOfBoundsException) {...}
catch (Exception ex) {...} // 此句必须放在最后

      Exception 是异常的父类,如果要捕获的异常存在继承关系,则子类在前,父类在后。因为要是 catch (Exception ex){...} 在前,则后面的子类异常无法执行。Java 编译器不允许这样的情况发生,会出现编译错误。

3.7. Java 语句如何进行异常处理,关键字:throws,throw,try,catch,finally 分别代表什么意义?在 try 块中可以抛出异常吗?

      Java 中通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供良好的接口。在 Java 中,每个异常都是一个对象,它是 Throwable 后者其他子类的实力。当一个方法出现异常后,便抛出一个异常对象,该对象中包含了异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java 的异常处理是通过上面的五个关键字来实现的。

      try 用来指定一块预防所有“异常”的程序;catch 子句紧跟在 try 块后面,用来指定你想要捕捉的“异常”的类型;

      throw 用来明确表示抛出一个异常;

      throws 表明可能抛出多个异常;

      finally 表示无论是否发生异常,都会执行该代码块

3.8. Collection 和 Collections 的区别?

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

3.9.说说 java 的集合类:HashMap 是如何设计的?是如何解决冲突的?

      1)HashMap 是基于哈希表的 Map 接口的非同步实现。在 Java 编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造,HashMap 也不例外。HashMap 实际上是一个“链表的数组”的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。HashMap 底层就是一个数组,而数组的每一项又是一个链表。当新建一个 HashMap 时就会初始化一个数组。Entry 就是数组中的元素,每个Map.Entry 其实就是一个 key.value,它持有一个指向下一个元素的引用,这也就构成了一个链表。

      2)HashMap 的存储。当我们往 HashMap 中 put 元素的时候,先根据 key 的 hashCode 重新计算 hash 值,根据 hash 值得到这个元素在数组中的位置(下标)。如果数组中该位置无其他元素,则将该元素放在该位置上;如果已经放有其他元素,那么将以链表的形式存储,新加入的放在链表头部。

      3)HashMap 的读取。从 HashMap 中 get 元素时,先根据 key 的 HashCode 索引到数据位置,然后根据 equals 方法找到需要的元素。

      4)HashMap 的扩容(resize / rehash)。当 HashMap 中的元素越来越多时,hash 冲突的几率也就越来越大,因为数组的长度是固定的,因此为了提高查询/存放元素的效率,就对对数组进行扩容,数组扩容操作也会存在于 ArrayList 中,这是一个常见的操作。在 HashMap扩容时,会出现最消耗系统性能的点:原始数组中的元素必须通过重新计算,获得存放位置,这就是 resize。那么 HashMap  什么时候开始扩容呢? 当 HashMap 的元素个数超过数组大小 * loadFactory 时,开始扩容,loafFactory 默认为 0.75。

3.10.简述 HashMap 和 HashTable 的区别?

      1)HashMap 没有排序,允许一个或多个 null 值,而 HashTable 不允许。

      2)HashMap 把 HashTable 的contains 方法去掉了,改为 containKey 和 containValue 方法,因为 contains 方法容易引起误解。

      3)HashTable 继承自 Dictionary 类,HashMap 是 java 1.2 引进的 Map 接口的实现。

      4)两者采用的 hash/rehash 算法大致相同,性能上不会有很大的差异。但 HashTable 是 synchronize 的,当多个线程同时访问时,不需要设置实现同步的方法。

3.11.HashMap 和 HashSet 有什么关系?

      HashSet 是利用 HashMap 实现的。

3.12.Vector 和 ArrayList 有什么差异?

      1)同步性:Vector 是线程安全的(同步),而 ArrayList 是线程不安全的。

      2)扩容:当需要扩容时, Vector 默认扩容一倍,而 ArrayList 默认一半。

3.13.List 底层是怎么实现的?双向链表和数组的区别?

      在 java 中 List 是一个接口,继承于 Collection 接口,并定义了添加元素,删除元素,取出元素等对集合操作的抽象方法。

      双向链表和数组区别为:

      1)数组必须事先定义好长度,不能动态增减。

      2)链表可以动态插入。

3.14.请说明什么是线程安全?

      如果多个进程同时运行一段代码,并且多个线程运行的结果和单进程运行的结果相同,就是线程安全的。通常线程安全问题都是由全局变量和局部变量引起的,若每个进程对变量只有读操作而没有写操作,一般说来,线程是安全的。

3.15.线程池是什么?

      当一个程序中若创建大量线程,并在任务结束后销毁,会给系统带来过度消耗资源,以及过度切换进程的危险,从而可能导致系统崩溃。我们通过创建线程池来解决这个问题。当服务器接收到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务结束后不关闭该线程,而是将线程还回到线程池中。在线程池的编排模式下,任务是提交给线程池,而不是提交给单个线程,因此可以一次性向线程池提交多个任务。

3.16.数组 / String 里有没有 length()方法?

      数组里没有 length()方法,只有 length 属性;而 String 里有 length()方法。

3.17.谈谈对反射机制的理解?

      Java 中类的反射是一种自我管理机制,通过反射可实现:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用一个对象的方法。

发布了7 篇原创文章 · 获赞 10 · 访问量 2980

猜你喜欢

转载自blog.csdn.net/qq_40798777/article/details/104363441
今日推荐