史上最全的java面试题 (一)

Java部分

基础部分:

1.面向对象的特征有哪些方面?

答 :

抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。

封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。

多态:不同子类型的对象对同一消息作出不同的响应。多态性分为编译时的多态性和运行时的多态性。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。

 

2.访问修饰符public,private,protected,以及不写(默认)时的区别?

答:

修饰符

当前类

同 包

子 类

其他包

public

protected

×

default

×

×

private

×

×

×

 

3.int和Integer有什么区别?

答:

Int是八大基础类型之一,数字仅用作运算。

Integer是封装类,有多种方法可以使用。

Int的默认值为0,无法区分赋值为0还是为空。

Integer的默认值为null,可以区分赋值为0还是为空。

容器中一般要求使用封装类。

4.&和&&的区别?

答:

&是位运算和逻辑与,a&b,先转换为二进制,再运算。表达式1&表达式2,要都为true才为true,否则为false。

&&是短路与,如果表达式1为false,后面的就不做运算了。

5.解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。

答:

Stack一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间

Heap通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域。

方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的100、"hello"和常量都是放在常量池中,常量池是方法区的一部分。

栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间。

6.String和StringBuilder、StringBuffer的区别?

答:String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因此它的效率也比StringBuffer要高。

7.描述一下JVM加载class文件的原理机制?

8.Java语言的优点?

答:

1.面向对象,更容易反映现实生活的对象。

2.跨平台性,一次编译,到处运行。

3.提供多种类库。简化开发流程,缩短开发时间。

4.提供了对web应用开发的支持。

5.健壮性和安全性,提供了防止恶意代码攻击的安全机制。垃圾回收机制等。

6.去除了C++中的头文件,指针,等特性,更简洁严谨。

9.Java 中会存在内存泄漏吗,请简单描述。

答:理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。

10.GC是什么?为什么要有GC?

答:GC是垃圾收集的意思,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。

内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。

11.什么时候用断言(assert)?

答:断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。

  1. 写出选择,插入,冒泡算法?

答:

冒泡算法:

public class BubbleSort {

   public static void sort(int[] a) {

      for (int i = 0; i < a.length - 1; i++) {

        for (int j = 0; j < a.length - i - 1; j++) {

           if (a[j] > a[j + 1]) {

              int temp = a[j];

              a[j] = a[j + 1];

              a[j + 1] = temp;

           }

        }

}

}

}

选择算法:

public class ChoiceSort {

   public static void sort(int[] a) {

      for (int i = 0; i < a.length - 1; i++) {

        for (int j = i + 1; j < a.length; j++) {

           if(a[i] > a[j]) {

              int temp = a[i];

              a[i] = a[j];

              a[j] = temp;

           }

        }

      } 

   }

}

插入算法:

public static void sort(int[] a) {

      for (int i = 1; i < a.length ; i++) {

        int currentValue = a[i];

        int position = i;

        for (int j = i-1 ; j >= 0; j--) {

              if(a[j] > currentValue) {

              a[j+1] = a[j];

              position--;

           }

        }

      }

   }

}

  1. Java中实现多态的机制是什么?

答:结合重载和重写来回答。

  1. 垃圾回收器的原理是什么?垃圾回收器是否可以马上回收内存?如何通知虚拟机进行垃圾回收?

答:Java语言提供了垃圾回收器来自动检测对象的作用域,实现自动的把不再被使用的储存空间释放掉。具体而言,垃圾回收器要负责三项任务:分配内存、确保被引用对象的内存不被错误的回收以及回收不再被引用的对象的内存空间。

垃圾回收器优缺点:1.将程序员从释放内存的复杂工作中解脱出来,提高开发人员的生产效率。2对开发人员屏蔽释放内存的方法,可以避免因为开发人员的错误操作内存从而导致程序的崩溃,保证了程序的稳定性。3回收垃圾的过程增加了jvm的负担,从而降低了程序的执行效率。

由于垃圾回收器的存在,Java语言本身没有给开发人员提供显示释放已分配内存的方法,也就是说,开发人员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。但开发人员可以调用system.gc通知垃圾回收器运行,但jvm不会保证立即运行。由于gc方法的执行会停止所有的响应,会对程序的正常运行以及性能造成极大的威胁,所以实际开发中不推荐频繁使用gc。

  1. Fail -fast和fail-safe迭代器的区别是什么?

答:

fail-fast:直接在容器上进行遍历,在遍历的过程中,一旦发现容器中的数据被修改了,会立刻抛出concurrentmodificationexception异常导致遍历失败。最常见的fail-fast容器hashmap和ArrayList。

Fail-safe:这种遍历基于容易的一个克隆,因此对容器内容修改不影响遍历。常见fail-safe容器有concurrenthashmap和copyonwriteArrayList。

  1. 对于一些敏感的数据(例如密码),为什么使用字符数组储存比使用String更安全?

答:

String是不可变类,它被储存在常量池中。一旦字符串被创建出来,直到被垃圾回收器回收为止。即使字符串不再被使用,它仍然会在内存中存在一段时间,此时有权限访问memory dump的程序都可能会访问到该字符串,从而把敏感的数据暴露出去,这个一个非常大的安全隐患。如果使用字符数组,一段程序不再使用这个数据,程序员就可以把字符数组的内容设置为空,此时这个数据在内存中就不存在了。

Static和final:

  1. Java 中的final关键字有哪些用法?

答:

final可以修饰类,方法,变量

类被修饰后变为不可以被继承的类。

被声明为final的方法也同样只能使用,不能在子类中被重写。

被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。

  1. Java中的Static关键字作用是什么?

答:static可以修饰变量,代码块,内部类。

Static修饰后的方法为静态方法,属于类方法,类被加载后就可以使用了,类名.静态方法名。静态方法中不能使用this和super,不能调用非静态方法,也不能访问实例变量。

Static修饰后的变量为静态变量,属于类,只要类被加载,静态变量就可以被使用了,对静态变量使用两种方式。类.静态变量/对象.静态变量。实例变量属于对象,只要对象创建后,才能被使用。只能用对象.实例变量。

Static代码块,类加载时按顺序初始化,只执行一次。

Static内部类,可以不依赖外部类实例化而被实例化,只能访问外部类的静态成员和静态方法(包括私有)。

  1. 阐述final、finally、finalize的区别。

finally通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。

finalize Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。

  1. 是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

答:不行,因为非静态方法属于对象,因对象的创建而存在,静态方法属于类,随着类的加载而创建,因此,存在静态方法时,非静态方法可能不存在。

  1. 阐述静态变量和实例变量的区别?

答:

Static修饰后的变量为静态变量,属于类,只要类被加载,静态变量就可以被使用了,对静态变量使用两种方式。类.静态变量/对象.静态变量。

实例变量属于对象,只要对象创建后,才能被使用。只能用对象.实例变量。

6.静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?

答:Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。

7.静态代码块,构造方法,非静态代码块。静态变量,加载顺序?

答:父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数。

接口和抽象:

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

答:接口由interface修饰,必须为public,实现使用implements,多实现。

抽象由abstract修饰,必须为public,实现使用extends,单继承。

接口内部的方法不能实现,只能是public修饰,变量必须为常量。

抽象内部的方法可以实现,也可以不实现,抽象内部可以私有,实现类的修饰符范围必须比抽象类小。

抽象和接口均不可实例化。

  1. 接口能否继承接口?抽象类是否可以实现接口?抽象类是否可以继承实体类?

答:接口可以继承接口,抽象可以实现接口,抽象可以继承实体类。

  1. 抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?

答:

都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

 

重载和重写:

  1. 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

答:

重载和重写是多态性的不同表现,其中重载是一个类中多态性的一种表现,是指一个类中定义了多个同名的方法,参数类型或参数个数不同,使用重载时需注意:

  1. 重载是通过不同的参数来区分,例如不同的参数类型,不同的参数个数,不同的参数顺序。
  2. 不能通过方法的访问权限、返回值类型和抛出异常类型来重载。
  3. 对于继承来说,如果基类的访问权限为private,那么就不能再派生类中对其进行重载,如果派生类也定义了一个同名的方法,这只是一个新的方法,不会达到重载的效果。

重写是指派生类覆盖基类的方法,对其重写,以达到不同的作用,使用重写时需注意:

  1. 派生类的覆盖方法必须和基类中被覆盖的方法有相同的方法名和参数。
  2. 派生类的覆盖方法的返回值必须和基类中被覆盖的方法的返回值相同。
  3. 派生类的覆盖方法所抛出的异常必须和基类中被覆盖的方法所抛出的异常一致或是其子类。
  4. 基类中被覆盖的方法不能为private,否则,其子类只是定义了一个方法,并没有对其进行覆盖。

重载和重写的区别:

  1. 覆盖是子类和父类的关系,垂直关系;重载是同一个类中方法之间的关系,是水平关系。
  2. 覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
  3. 覆盖要求参数列表相同;重载要求参数列表不同。
  4. 覆盖关系中,调用方法体是根据对象的类型来决定的;而重载是根据调用时的实参表与形参表来选择方法体的。

重载的方法可以改变返回值类型,重写的方法不能改变返回值类型。

集合:

  1. List、Set、Map是否继承自Collection接口?

答:List、Set继承自Collection,map不是。与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。

  1. 阐述ArrayList、Vector、LinkedList的存储性能和特性。

答:

1ArrayList、Vector底层是数组,内存会开辟一个连续的储存空间,数据储存是连续的,可以通过下标或者索引来访问数据,因此查询快。插入需要移动每个数组元素的位置,因此增删慢。动态扩充空间,vector扩充为原来2倍(扩充大小可调),arraylist扩充为1.5倍。

2LinkedList底层是链表,双向链表结构,对数据的索引会从链表头开始遍历,因此查询慢,而插入,只需要改变链表元素的指向即可,插入快。

3ArrayList和LinkedList是线程不安全的,Vector线程安全,效率比Vector高。

4在实际使用中,在对数据的主要操作为索引或只在集合末端增删元素,使用ArrayList和Vector,当对数据的主要操作是在指定位置插入删除元素,使用LinkedLsit,在多线程中使用容器时,使用Vector。

  1. Collection和Collections的区别?

答:Collection是集合框架的接口,子类有List和Set。Collections是集合框架的一个工具类,提供了一系列的静态方法可以使用,这些方法包括对容器的搜索、排序、线程安全化等等。

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

答:List的实现类有ArrayList和LinkedList、Vector,可以重复,有序

Map的实现类有HashMap和TreeMap,键值对存储,键唯一

Set的实现类有HashSet和TreeSet,不能重复,无序,类似数学意义的集合

  1. TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?

答:TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java中对函数式编程的支持)。

  1. HashTable和HashMap的区别?

答:

HashTable的键不可以使用null,HashMap的键最多可以使用一个null

HashTable是线程安全的,HashMap是线程不安全的

HashTable遍历是使用enumeration,HashMap遍历是使用iterator

HashTable默认大小是11,扩充是按公式old*2+1,HashMap的默认大小是16,扩充是2的指数

HashTable的contain方法,HashMap改变为containvalue和containkey

异常:

  1. Error和Exception有什么区别?

答:Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception表示需要捕捉或者需要程序进行

处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。

 

  1. try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

答:在return前,在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值。

 

  1. Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?

答:一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法可能抛出的各种异常;finally为确保一段代码不管发生什么异常状况都要被执行。

  1. 运行时异常与受检异常有何异同?

答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,在Effective Java中对异常的使用给出了以下指导原则:
- 不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
- 对可以恢复的情况使用受检异常,对编程错误使用运行时异常
- 避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
- 优先使用标准的异常
- 每个方法抛出的异常都要有文档
- 保持异常的原子性
- 不要在catch中忽略掉捕获到的异常
5.列出一些你常见的运行时异常?

答:

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

  1. 如何捕获一个线程抛出的异常?

可以通过设置线程的UncaughtExceptionHandler(异常捕获处理方法)来捕获线程抛出的异常。

  1. 请给出Java异常类的继承体系结构,以及Java异常的分类,且为每种类型的异常各举几个例子。

答:Java提供了两种错误的处理类,分别为error和exception,且他们拥有共同父类throwable。

Error表示程序在运行期间出现了非常严重的错误,并且是不可恢复的,属于jvm层的严重错误,会导致程序终止运行。一个正常运行的程序中是不应该存在error的。OutOfMemoryError、ThreadDeath和NotClassDefFounderError都属于错误。

Exception表示可以恢复的异常,是编译器可以捕捉到的。包含两种类型,运行时异常和检查异常。

检查异常:IO异常和sql异常。这种异常是发生在编译阶段,把可能会出现异常的代码放在try块中,把对异常的处理代码放catch块中。常见sqlexception、ioexception、unknownhostexcep。

运行时异常:编译器没有强制对其进行捕获并处理。如果不对这种异常进行处理,当出现这种异常时,会由jvm处理。常见的nulpointerexception、arraystoreexception、classcastexception、indexoutboundexception、bufferoverflowexception、Arithmeticexception。

 

内部类:

  1. 内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?

答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

 

线程:

  1. Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?

答:

sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态)。

wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

 

  1. 线程的sleep()方法和yield()方法有什么区别?

答:

A.sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
B.线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
C.sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
D.sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。


3.当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?

  1. 请说出与线程同步以及线程调度相关的方法。

答:

- wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
- sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;
- notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;
- notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

 

  1. 编写多线程程序有几种实现方式?

答:三种,thread,runnable,callable

  1. 举例说明同步和异步。

答:如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就必须进行同步存取(数据库操作中的排他锁就是最好的例子)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值