【前言】别人都在你看不到的地方暗自努力,在你看得到的地方,他们也和你一样显得游手好闲,和你一样会抱怨,而只有你自己相信这些都是真的,最后,也只有你一个人继续不思进取 ……
【下载】本人刚学习Java时总结的一些JavaSE常见面试题,偶尔在电脑中翻出,重新整理一下分享给需要的人,主要针对初级程序员。想要PDF完整版下载的,评论里留言留下你的邮箱!
41..比较一下Java和JavaSciprt?
答:其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言:
(1)基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言,因而它本身提供了非常丰富的内部对象供设计人员使用。
(2)解释和编译:Java的源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行。(目前的浏览器几乎都使用了JIT(即时编译)技术来提升JavaScript的运行效率)
(3)强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量前可以不作声明,JavaScript的解释器在运行时检查推断其数据类型。
(4)代码格式不一样。
42.Error和Exception有什么区别?
答:①Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;
②Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
43.try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?
答:会执行,在方法返回调用者前执行。
44.throw和throws的区别、及处理方式?
答:(1)throw:用于抛出异常对象,后面跟的是异常对象;throw用在方法体内;
(2)throws:用于抛出异常类,后面跟的是异常类名,可以跟多个,用逗号隔开。throws用在方法上
(3)异常处理方式:抛出throws、捕捉try - catch - finally。
(4)什么时候定义try,什么时候定义throws?
①功能内部如果出现异常,如果可以处理,就用try;
②如果内部处理不了,就必须声明出来,让调用者处理。
45.编译时异常和运行时异常的区别?
答:(1)编译时异常在函数内被抛出,函数必须声明,否则编译失败。
声明的原因:是需要调用者对该异常进行处理。必须进行处理,否则无法编译通过;(throws)
(2)运行时异常如果在函数内被抛出,在函数上不需要声明。
不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以,不让调用处理的,直接让程序停止,由调用者对代码进行修正。(throw)
46.List、Set、Map是否继承自Collection接口?
答:List、Set是,Map不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。
47.阐述ArrayList、Vector、LinkedList的存储性能和特性?
答:(1)ArrayList:
①ArrayList底层是通过数组实现的,与LinkedList相比,查询快,增删慢;
②ArrayList的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。
(2)Vector:
①Vector:底层也是通过数组实现的,与ArrayList相比,它是同步的,线程安全的;一般情况下:ArrayList适用于单线程,Vector适用于多线程。
②Vector的容量增长与“增长系数有关”,若指定了“增长系数”,且“增长系数有效(即,大于0)”;那么,每次容量不足时,“新的容量”=“原始容量+增长系数”。若增长系数无效(即,小于/等于0),则“新的容量”=“原始容量x
2”。
(3)LinkedList:
①LinkedList底层是通过链表实现的,与ArrayList相比,查询慢,增删快;
②LinkedList在添加新元素时,先是在双向链表中找到要插入节点的位置index;找到之后,再插入一个新节点。同时,双向链表查找index位置的节点时,有一个加速动作:若index
< 双向链表长度的1/2,则从前向后查找;否则,从后向前查找。
48.简述集合架构体系?
49.Collection和Collections的区别?
答:Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。
50.List、Map、Set三个接口存取元素时,各有什么特点?
答:(1)List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。
(2)Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。
(3)Set和Map容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。
51.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?
答:(1)TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。
(2)TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。
(3)Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java中对函数式编程的支持)。
52、Thread类的wait(
)和sleep( )的区别?
答:(1)所在类不同:wait( )是Object类中的方法;sleep(
)是Tread类中的方法;
(2)slepp( )没有释放同步锁,而wait( )释放了同步锁;
(3)slepp( )必须制定时间,而wait( )不用;
(4)slepp( )可以在任何地方使用,而wait( )、notify(
)、notifyAll( )只能在同步方法或同步代码块中使用;
(5)slepp( )必须捕获异常,而wait( )、notify(
)、notifyAll( )不用;
53.线程的sleep()方法和yield()方法有什么区别?
答:①
sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。
54.当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。
55.简述线程的五种状态?
答:(1)新建(new):当一个线程处于新建状态时,它仅仅是一个空的线程对象,系统不为它分配资源。Tread
t = new Tread(new Runner());
(2)就绪(Runable):此时线程处在随时可以运行的状态,在随后的任意时刻,都可能进入运行状态。t.star(
);
(3)运行(Running):处于这个状态的线程占用CPU,执行程序代码。
(4)阻塞(Blocked):阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行,直到线程重新进入就绪状态。wait、sleep、同步锁被占用;
(5)死亡(Dead):当线程退出run()方法时,就进入死亡状态,该线程生命周期结束。可能正常执行完run()方法退出,也可能是遇到异常。
56.创建多线程的两种方式期区别?
答:(1)第一种方式:继承Thread类,由子类重写run方法。步骤如下:
①定义类继承Thread类;
②目的是重写run方法,将要执行的代码都存储到run方法中;
③通过创建Thread类的子类对象,创建线程对象;
④调用线程的start方法,开启线程,并执行run方法。
(2)第二种方式:实现Runnable接口。步骤如下:
①定义类实现Runnable接口。
②覆盖接口中的run方法(用于封装线程要运行的代码)。
③通过Thread类创建线程对象;
④将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。
⑤调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。
(3)区别:
①继承Thread
:
好处:可以直接使用Tread类中的方法,代码简单;
弊端:如果该类已有父类,就不能用这种方法了;
②实现Runnable接口:
好处:可以避免单继承的局限性,即使自己的线程类有父类也没关系;
弊端:不能直接使用Tread类中的方法,要先获取线程对象,代码复杂。
57.synchronized关键字的用法?
答:synchronized关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用synchronized(对象)
{ … }定义同步代码块,或者在声明方法时将synchronized作为方法的修饰符。在第60题的例子中已经展示了synchronized关键字的用法。
58.举例说明同步和异步。
答:如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就必须进行同步存取(数据库操作中的排他锁就是最好的例子)。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。事实上,所谓的同步就是指阻塞式操作,而异步就是非阻塞式操作。
59.启动一个线程是调用run()还是start()方法?
答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。
60.什么是线程池(thread pool)?
答:在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。