面向对象编程(OOP)
Java是一个支持并发、基于类和面向对象和计算机编程语言。如下是面向对象软件开发的优点:
1、代码开发模块化,更容易维护和修改。
2、代码复用。
3、增强代码的可靠性和灵活性。
4、增加代码的可理解性。
面向对象编程有很多重要的特性,比如:封装,继承,多态和抽象。
1、封装:
1、封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。
2、在Java当中,有4种修饰符:public,private,default和protected。
3、每一种修饰符给其他的位于同一个包或者不用包下面对象赋予了不同的访问权限。
4、其中private的作用范围限定于当前类中;
5、default是默认的访问修饰符,作用范围是同一个包中;
6、protected的作用范围不包括其他的包,在同一包,当前类和其子类中均能使用;
7、public是公开的,在当前工程中均可以使用。
封装的一些优点:
1、通过隐藏对象的属性来保护对象内部的状态;
2、提高了代码的可用性和可维护行,因为对象的行为可以被单独的改变或者是扩展。
3、禁止对象之间的不良交互提高模块化。
2、多态:
1、多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。
2、一个多态类型上的操作可以应用到其他类型的值上面。
3、继承:
1、继承给对象提供从基类获取字段的方法和能力。
2、继承提供类代码的重用行,也可以在不修改类的情况下给现存的类添加新特性
4、抽象:
1、抽象是把想发从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节类常见类。
2、Java支持创建只暴露接口而不包含方法实现的抽象的类,
3、这种抽象技术的主要目的是把类的行为和实现细节分离开。
抽象个封装的不同点:
1、抽象个封装是互补的概念,一方面,抽象关注对象的行为。另一方面,封装关注对象行为的细节。
2、一般是通过隐藏对象内部状态信息做到疯转,因此,封装可以看成是用来提供抽象的一种策略。
常见的Java问题:
1、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
1、Java虚拟机是一个可执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。
2、Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者重新编译。
3、Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。
2、JDK和JRE的区别是什么?
1、Java运行时环境(JRE)是将要执行的Java程序的Java虚拟机。它同时也包含了执行applet需要的浏览器插件。
2、Java开发工具包(JDK)是完整的Java软件开发包,包含了JRE,编译器和其他的工具(比如:JavaDoc,Java调试器),
可以让开发者开发、编译、执行Java应用程序。
3、“static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
“static”关键字表明一个成员变量或者成员方法可以在没有所属的类的实例变量的情况下被访问。Java中static方法不能被覆盖,
因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
4、是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的。
当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,
编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
5、Java支持的数据类型有哪些?什么是自动拆装箱?
Java语言支持的8种基本数据类型是:
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
boolean
Boolean
char
Character
自动装箱是Java编译器在基本数据类型和对应的包装类型之间做一个转化,比如:把int转化成integer等等。反之就是自动拆箱。
6、Java中的方法覆盖(override)和方法重载(overloading)是什么意思?
Java中的方法重载发生在同一个类里面两个或者多喝方法的方法名相同凡是参数不同的情况。与此相对,方法覆盖是说子类重新定义了父类的方法。
方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。
7、Java中,什么是构造函数?什么是构造函数重载?什么是复制构造函数?
当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。
在程序员没有给类提供构造函数的情况下,Java编译器会为这个类创建一个默认的构造函数。
Java中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数必须有它自己唯一的参数列表。
Java不支持像C++中那样的复制构造函数,这个不同点是因为如果你不自己写构造函数的情况下,Java不会创建默认的复制构造函数。
8、Java支持多继承么?
不支持,Java不支持多继承。每个类只能继承一个类,但是可以实现多个接口。
9、接口和抽象类的区别是什么?
1、Java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:
2、接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
3、类可以实现很多个接口,但是只能继续一个抽象类
4、类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不是想抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成抽象的。
5、抽象类可以在不提供接口方法实现的情况下实现接口。
6、Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
7、Java接口中的成员函数默认是public的。抽象类的成员函数可以是其他修饰符修饰的。
8、接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
10、什么是值传递和引用传递?
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响源对象的值。
对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象所做的改变会反映到所有的对象上。
11、String是最基本的类型吗?
不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;
除了基本类型,剩下的都是引用类型,Java 5以后引入的枚举类型也算是一种比较特殊的引用数据类型。
12、float f = 3.4;是否正确?
不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型,会造成精度损失,因此需要强制类型转换float = (float)3.4或者写成 float f = 3.4F.。
13、short s1 = 1 ; s1 = s1 + 1;有错吗?short s1 = 1 ; s1+=1;有错吗?
对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1 + 1运算结果也是int型,需要强制类型转换才能赋值给short型。
而short s1 = 1 ; s1+=1;可以正确编译,因为s1+=1; 相当于s1 = (short)(s1 + 1);其中隐含的强制类型转换。
14、Java有没有goto?
goto是Java中的保留字,在目前版本的Java中没有使用。除了goto之外,const也是java中的保留字,目前均没有使用。
15、&和&&的区别
&运算符有两种用法:(1)、按位与:(2)、逻辑与。&& 运算符是短路与运算。
16、解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。
通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都是用JVM中的栈空间;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如果直接书写100 hello 和常量都是放在常量池中,常量池是方法区的一部分。栈空间操作起来最快但是栈很小,通常大量的对象都放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StactOverflowError,而对和常量池空间不足则会引发OutOfMemoryError。
17、数组有没有length()方法?String有没有length()方法?
数组中没有length()方法,有length的属性。String有length()方法。JavaScript中,获得字符的长度是通过length属性得到的,这一点很容易与java混淆。
18、在Java中,如何跳出当前的多重嵌套循环?
在最外层循环前加一个标记A,然后用break A;可以跳出多重循环。cuntinue是跳出当前循环。
19、构造器(constructor)是否可以被重写(override)?
构造器不能被继承,因此不能被重写,但可以被重载。
20、String和StringBuilder、StringBuffer的区别?
Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象是可以直接进行修改。StringBuiler是Java 5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有的方法都没有被sychronized修饰,因此它的效率要比StringBuffer要高。
21、进程和线程的区别是什么?
进程是执行着的应用程序,而线程是进程内部的一个执行序列。
一个进程可以有多个线程。线程又叫做轻量级进程。
22、创建线程有几种不同的方式?
有三种方式可以用来创建线程:
1、继承Thread类
2、实现Runnable接口
3、应用程序可以使用Executor框架来创建线程池
实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。
在应用设计中已经继承了别的对象的情况下,还需要多继承(而Java不支持多继承),
只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。
23、概括的解释下线程的几种可用状态。
线程在执行过程中,可以处于下面几种状态:
就绪(Eunnable):线程准备运行,不一定立马就能开始执行。
运行中(Running):进程正在执行线程的代码。
等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。
睡眠中(Sleeping):线程被强制睡眠。
I/O阻塞(Blocked on I/O):等待I/O操作完成。
同步阻塞(Blocked on Sychronization):等待获取锁。
死亡(Dead):线程完成了执行。
24、同步方法和同步代码块的区别是什么?
在Java语言中,每一个对象有一把锁。线程可以使用sychronized关键字来获取对象上的锁。
sychronized关键字可应用在方法级别(粗粒度锁)或者是代码块级别(细粒度锁)。
25、在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?
监视器和锁在Java虚拟机中是一块使用的。监视器件事一块同步代码块,确保一次只
有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。
线程在获取锁之前不允许执行同步代码。
26、什么是死锁(deadlock)
两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。
结果就是两个进程都陷入了无限的等待中。
27、如何确保N个线程可以访问N个资源同时又不导致死锁?
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,
并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,
就不会出现死锁了。
28、Thread类中的start()和run()方法有什么区别?
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,
这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是
在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
29、Java中Runnable和Callable有什么不同?
Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,
Callable是在JDK1.5增加的。它们的主要区别是Callable的call()方法可以返回值和抛出异常,
而Runnable的run()方法没有这些功能。Callable可以放回装载有计算结果的Future对象。
30、Java中CyclicBarrier和CountDownLatch有什么不同?
CylicBarrier和CountDownLatch都可以用来让一组线程等待其它线程。与CyclicBarrier不同的是,
CountdownLatch不能重新使用。
31、Java内存模型是什么?
Java内存模型规定和指引Java程序在不同的内存架构、CPU和操作系统间有确定性得行为。它在多线
程的情况下尤其重要。Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间
是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。比如,先行发生关系
确保了:
1、线程内的代码能够按先后顺序执行,这被称为程序次序规则。
2、对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则
3、前一个对volatile的写操作在后一个volatile的读操作之前,也叫volatile变量规则。
4、一个线程内的任何操作必需在这个线程的start()调用之后,也叫做线程启动规则。
5、一个线程内的任何操作都会在线程终止之前,线程终止规则。
6、一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则。
7、可传递性
32、Java中的volatile变量是什么?
volatile是一个特殊的修饰符,只有成员变量才能使用它。在Java并发程序缺少同步类的情况下,
多线程对成员变量的操作对其它线程是透明的。volatile变量可以保证下一个读取操作会在前一个写
操作之后发生,就是上一题的volatile变量规则。
33、什么是线程安全?Vector是一个线程安全类吗?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次
运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
一个线程安全的计数器类的同一个石磊对象再被多个线程使用的情况下也不会出现计算失误。很显然
你可以将集合类分成两组,线程安全和非线程安全的。Vector是用同步方法来实现线程安全的,
而和它想相似的ArrayList不是线程安全的。
34、Java中什么是竞态条件?举个例子说明
竞态条件会导致程序在并发情况下出现一个bugs。多线程对一些资源的额竞争的时候就会产生竞态条
件,如果首先要执行的程序竞争失败排到后面执行了,那么整个程序就会出现一些不确定的bugs。
这种hugs很难发现而且会重复出现,因为线程间的随机竞争,一个例子就是无序处理。
35、Java中如何停止一个线程?
Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(),susoend()和
resume()的控制方法,但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,
之后Java API的设计者就没有提供一个兼容切线程安全的方法来停止一个线程。当run()或者call()
方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile布尔变量来
退出run()方法的循环或者是取消任务来中断线程。
36、一个线程运行时发生异常会怎样?
简单的说,如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler是用于处理
未捕获异常造成线程突然中断情况的一个内嵌接口。方一个为捕获异常将造成线程中断的时候JVM会使用
Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数
传递给handler的uncaughtException()方法进行处理。
37、如何在两个线程间共享数据?
你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构。
38、Java中notify和notifyAll有什么区别?
因为多线程可以等待单监控锁,Java API 的设计人员提供了一些方法当等待条件改的时候通知它们,
但是这些方法没有完全实现。notify()不能唤醒某个具体的线程,所以只有一个线程在等待的时候它
才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保至少有一个线程能继续运行。
39、为什么wait,notify和notifyAll这个方法不在thread类里面?
Java提供的锁是对象及的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些
锁那么调用对象中的wait()方法就没有意义了。如果wait()方法定义在Thread类中,线程正在等待某
些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的
是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以他们定义
在Object类中因为锁属于对象。
40、什么是ThreadLocal变量?
ThreadLocal变量是Java里一种特殊的变量。每个线程都有一个ThreadLocal就是每个线程都拥有了自己
独立的一个变量,竞争条件被彻底消除了。它是为创建代价高昂的对象获取线程安全的好方法,比如你
可以用ThreadLocal让SimpleDateDormat变成线程安全的,因为那个类创建代价高昂且每次调用都需要
创建不同的实例所以不值得在局部范围使用它,如果为每个线程提供一个自己独有的变量拷贝,将大大
提高效率。首先,通过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者
不变性的情况下获得了线程安全。线程局部变量的另一个不错的例子是ThreadLocalRandom类,它在
多线程环境中减少了创建高昂的Random对象的个数。
41、什么是FutureTask?
在Java并发程序中FuntureTask表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成
和取回运算结果等方法。只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞。一个
FuntureTask对象可以对调用了Callable和Runnable的对象进行包装,由于FuntureTask也是调用了Runnable
接口所以它可以提交给Excutor来执行。
42、Java中interrupted和isInterrupted方法的区别?
interrupted()和isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断
机制是内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。
43、为什么wait和notify方法要在同步块中调用?
主要是因为Java API 强制要求这么做,如果你不这么做,你的代码会抛出IllegalMonitorStateException
异常,还有一个原因是为了避免wait和notify之间产生竞态条件。
44、为什么你应该在循环中检查等待条件?
处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有
满足结束条件的情况下退出。因此,当一个等待线程醒来是,不能认为它原来的等待状态仍然是有效
的,在notify()方法调用之后和等待线程醒来之前这段时间可能会改变。这就是在循环中使用wait()
方法效果更好的原因。
45、Java中的同步集合与并发集合有什么区别?
同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更
高。在Java 1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的
扩展性。Java 5介绍了并发集合像ConcurrentHashMap,不仅提供线程安全还用锁分离和内部分区等
现在技术提高了可扩展性。
46、Java中堆和栈有什么不同?
栈是一块和线程紧密相关的内存区域,每个线程都有自己的栈内存,用于存储本地变量,方法参数
和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用区域内
存。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈,如果多个线程使用该
变量就可能引发问题,这是volatile变量就可以发挥作用了,它要求线程从主存中读取变量的值。
47、什么是线程池?为什么要使用它?
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程,那么响应的时间会变长,影响到用
户体验,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干个
线程来响应处理,它们被称为线程池。里面的线程叫工作线程。从JDK 1.5开始,Java API提供了
Executor框架让你可以创建不同的线程池。比如单线程池,每处理一个任务;数目固定的线程池或者
是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。
48、如何写代码来解决生产者消费者问题?
在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行
消费,你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notifyAll来解
决这个问题,比较赞的办法是用Semaphore或者BlockingQueue来实现生产者消费者模型。
49、如何避免死锁?
Java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力
作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,
死锁的发生必须满足以下四个条件:
互斥条件:一个资源每次只能被一个进程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁的最简单方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的
进程申请资源必须以一定的顺序(升序或者降序)做操作来避免死锁。
50、Java中活锁和死锁有什么区别?
活锁和死锁类似,不同之处在于处于活锁的线程或进程的状态是不断改变的,活锁可以认为是一种
特殊的饥饿。一个现实的活锁例子是两个人在狭小的走廊碰到,两个人都试着避让对方好让彼此通
过,但是因为避让的方向都一样导致最后谁都不能通过走廊。简单的说就是,活锁和死锁的主要区
别是前者进程的状态可以改变但是却不能继续执行。
51、怎么检测一个线程是否拥有锁?
在Java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且晋档当前线程拥有某个具体
对象锁。
52、你如何在Java中获取线程堆栈?
对于不同的操作系统,有多种方法来获得Java进程的线程堆栈。当你获取线程堆栈是,JVM会把所有
线程的状态存到日志文件或者输出到控制台。在Windows你可以使用Ctrl+Break组合键来获取线程
堆栈,Linux下用kill -3命令。你也可以用jstack这个工具来获取,它对线程id进行操作,你可以用
jps这个工具找到id。
54、JVM中哪个参数是用来控制线程的栈堆大小的?
-Xss参数使用用来控制线程的堆栈大小的。
55、Java中sychronized和ReentrantLock有什么不同?
Java在过去很长一段时间只能通过suchronized关键字来实现互斥,它有一些缺点。比如你不能扩展
锁之外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5通过Lock接口提供了更复杂的控制
来解决这些问题。ReentrantLock类实现了Lock,他拥有与sychronized相同的并发性和内存语意且它
还具有可扩展性。
56、如果有三个线程T1,T2,T3,怎么确保它们按顺序执行?
在多线程中有多种方法让线程安特定的顺序执行,你可以用线程类的join()方法在一个线程中启动
另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个
(T3调用T2,T2掉用T1),这样T1就会先完成而T3最后完成。
57、Thread类中的yield方法有什么作用?
Yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。他是一个静态方法
而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU,执行yield()的线程有可能
在进入暂停状态后马上又被执行。
58、Java中ConcurrentHashMap的并发度是什么?
ConrurrentHashMap把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用
并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样在多线程
的情况下就能避免争用。
59、Java中Semaphore是什么?
Java中的Semaphore是一种新的同步类,它是一个计数信号。从概念上讲,从概念上讲,信号量维
护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每
个 release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,
Semaphore只对可用许可的号码进行计数,并采取相应的行动。信号量常常用于多线程的代码中,
比如数据库连接池。
60、如果你提交任务是,线程池队列已满,会发生什么?
抛出一个RejectedExecutionException异常。
61、Java线程池中submit()和execute()方法有什么区别?
两个方法都可以向线程池提交任务,execute()方法的返回值类型是void,它定义在Executor接口中,而
submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展
了Executor接口。
62、什么是阻塞式方法?
阻塞式方法是指程序会一直等待该方法完成期间不做其它事情,ServerSocket的accept()方法就是一直
等待客户端连接。这里的阻塞是指调用结果返回之前,当前线程会被挂起,直到得到结果之后才返回。
此外,还有异步和非阻塞方法在任务完成之前就能返回。
63、如何在Java中创建Immutable对象?
Immutable可以在没有同步的情况下共享,降低了对该对象进行并发访问时的同步化开销。可是Java没有
@Immutable这个注解符,要创建不可变类,要实现下面几个步骤:通过构造方法初始化所有成员、对变量
不要提供setter方法、将所有成员声明为私有的,这样就不允许直接访问这些成员、在getter方法中,
不要直接返回对象本身,而是克隆对象,并返回对象的拷贝。
64、Java多线程中调用wait() 和 sleep()方法有什么不同?
Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。wait()方法用于线程
间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让
当前线程停止执行一段时间,但不会释放锁。
65、如何强制启动一个线程?
这个问题就像是如何强制进行Java垃圾回收,目前还没有觉得方法,虽然你可以使用System.gc()来
进行垃圾回收,但是不保证能成功。在Java里面没有办法强制启动一个线程,它是被线程调度器控制
着且Java没有公布相关的API。
66、Java集合类框架的基本接口有哪些?
Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合里面最基本的接口有:
1、Collection:代表一组对象,每一个对象都是它的子元素。
2、Set:不包含重复元素的Collection。
3、List:有顺序的Collection,并且可以包含重复元素。
4、Map:可以把键(key)映射到值(value)的对象,键不能重复。
67、为什么集合类没有实现Cloneable和Serializable接口?
集合类接口指定了一组叫做元素的对象。集合类接口类的每一种具体的实现类都可以选择以它自己的方
式对元素进行保护和排序。有的集合类允许重复的键,有些不允许。
68、什么是迭代器(Iterator)?
Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合元素都包含了可以返回迭代器实例的
迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合
类的具体实现来决定如何被克隆或者序列化。
69、Iterator和ListIterator的区别是什么?
主要区别如下:
1、Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
2、Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
3、ListIterator实现了Iterator接口,并包含其他的功能,比如增加元素,替换元素,
获取前一个和后一个元素的索引等。
70、快速失败(fai-fast)和安全失败(fail-safe)的区别是什么?
Iterator的安全失败是基于对底层集合做拷贝,因此它不受源集合上修改的影响。java.util
包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是
安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败
的迭代器永远不会抛出这样的异常。
71、Java中的HashMap的工作原理是什么?
Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使
用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,
HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,
value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(loadfactor)
和扩容极限(threshold resizing)。
72、hashCode()和equals()方法的重要性体现在什么地方?
Java中的HashMap使用hsahCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会
用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,
可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对
HashMap的精确性和正确性是至关重要的。
73、HashMap和Hashtable有什么区别?
HashMap和Hashtable都实现了Map接口,因此很多特性都非常相似。但是他们也有不同的:
1、HashMap允许键和值是null,而Hashtable不允许键或者值都是null。
2、Hashtable是同步的,而HashMap不是。因此,HashMap更适合单线程环境,而Hashtable适合
多线程环境。
3、HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable
提供了对键的枚举(Enumeration)。
一般认为Hashtable是一个遗留的类。
74、数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?
不同点:
1、Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
2、ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
3、Array大小是固定的,ArrayList的大小是动态变化的。
4、对于基本类型数据,集合使用自动自动装箱来减少编码工作量。但是,当处理固定大小的
基本数据类型的时候,这种方式相对比较慢。
75、Arraylist和LinkedList有什么区别?
ArrayList与LinkedList都实现了List接口,他们有以下的不同点:
1、ArrayList是基于索引的数据接口,它的底层是hi数组。他可以以O(1)时间复杂度对元素
进行随机访问。与此对应,LinkedList是以元素列表的形式存储他的数据,每一个元素都和
它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)
2、相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为元素被添加到集合
任意位置的时候,不需要想数组那样重新计算大小或者是更新索引。
3、LinkedList比ArrayList更占内存,因为LinkedList为每一个字节存储了两个引用,一个指向前
一个元素,一个指向下一个元素。
76、Comparable和Comparator接口是干什么的?列出它们的区别。
Java提供了只包含一个compareTo()方法的Comparable接口。这个方法可以给两个对象排序。具体
来说,他返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象。
Java提供了包含compare()和equals两个方法的Comparator接口。compare()方法用来给输入参数排序,
返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作
为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入
参数和当前comparator的排序结果是相同的时候,这个方法才返回true。
77、什么是Java优先级队列(Priority Queue)?
PriorityQueue是一个基于优先级堆的无界队列,它的元素是按照自然顺序(natural order)排序的。
在创建的时候,我们可以给它提供一个负责给元素排序的比较器。PriorityQueue不允许null值,因
为他们没有自然顺序,或者说他们没有任何的相关联的比较器。最后,PriorityQueue不是线程安全
的,入队和出队的时间复杂度是O(log(n))。
78、Java集合类框架的最佳实践有哪些?
1、根据应用的需要正确选择要使用的集合类型对性能非常重要,比如:加入元素的大小是固定的,
而且能事先知道,我们就应该用Array而不是ArrayList。
2、有些集合类允许指定初始容量。因此,如果我们能估计出存储的元素数目,我们可以设置初始化
来避免重新计算容量hash值或者扩容。
3、为了类型安全,可读性和健壮性的原因总是要使用泛型。同时,使用泛型还可以避免运行时的
ClassCastException。
4、使用JDK提供的不变类(immutable class)作为Map的键可以避免为我们自己的类实现hashCode()
和equals()方法。
5、编程的时候接口要优于实现。
6、底层的集合实际上是空的情况下,返回长度是0的集合或者是数组,不要返回null。
79、Enumeration接口和Iterator接口的区别有哪些?
Enumeration速度是Iterator的2倍,同时占用更少的内存。但是,Iterator远远比Enumeration安全,
因为其他线程不能够修改正在被iterator遍历的集合里面的对象。同时,Iterator允许调用者删除
底层集合里面的元素,这对Enumeration来说是不可能的。
80、HashSet和TreeSet有什么区别?
HashSet是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()方法的时间
复杂度是O(1).
另一方面,TreeSet是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove()
contains()方法的时间复杂度是O(logn)。
81、Java中两种异常类型是什么?它们有什么区别?
Java中有两种异常:受检查(checked)异常和不受检查(unchecked)异常。不受检查的异常不需
要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并
且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用throws
语句在方法或者是构造函数上声明。
82、Java中Exception和Error有什么区别?
Exception和Error都是Throwable的子类。Exception用于用户程序可以捕获异常的情况。Error定义
了不期望被用户程序捕获的异常。
83、throw和throws有什么区别?
throw关键字用来在程序中明确的抛出异常,相反,throws语句用来表明方法不能处理的异常。每一
个方法都必须要指定哪些异常不能处理,所以方法的调用者才能够确保处理可能发生的异常,多个异
常是用逗号分隔的。
84、异常处理的时候,finally代码块的重要性是什么?
无论是否抛出异常,finally代码块总是会被执行。就算是没有catch语句同时又抛出异常的情况下,
finally代码块任然会被执行。最后要说的是,finally代码块主要用来释放资源,比如:I/O缓冲区,
数据库连接。。。
85、异常处理完成以后,Exception对象会发生什么变化?
Exception对象会在下一个垃圾回收过程中被回收掉。
86、finally代码块与finalize()方法有什么区别?
无论是否抛出异常,finallly代码块都会执行,他主要是用来释放应用占用的资源。finalize()方法是
Object类的一个protected方法,它是在对象被垃圾回收之前由Java虚拟机来调用的。
87、什么是JDBC?
JDBC是允许用户在不同数据库之间做选择的一个抽象层。JDBC允许开发者用JAVA写数据库应用程序,
而不需要关系底层特定数据库的细节。
88、解释下驱动(Driver)在JDBC中的角色。
JDBC驱动提供了特定厂商对JDBC API接口类的实现,驱动必须要提供java.sql包下面的这些类的实现:
Connection,Statement,OreparedStatement,CallableStatement,ResultSet和Driver。
89、Class.forName()方法有什么作用?
这个方法用来载入跟数据库建立连接的驱动。
90、PreparedStatement比Statement有什么优势?
PreparedStatement是预编译的,因此,性能会更好。同时,不同的查询参数值,
PreparedStatement可以重用。
91、什么时候使用CallableStatement?用来准备CallableStatement的方法是什么?
CallableStatement用来执行存储过程。存储过程是由数据库存储和提供的。存储
过程可以接受输入参数,也可以有返回结果。非常鼓励使用存储过程,因为它提供
了安全性和模块化。准备一个CallableStatement的方法是:
CallableStatement.prepareCall();
92、数据库连接池是什么意思?
像打开关闭数据库连接这种和数据库的交互可能是很费时的,尤其是当客户端数量
增加的时候,会消耗大量的资源,成本是非常高的。可以在应用服务器启动的时候
建立很多个数据库连接并维护在一个池中。连接请求有池中的连接提供。在连接使用
完毕以后,把连接归还到池中,以用于满足将来更多的请求。
93、什么是Servlet?
Servlet是用来出来客户端请求,并产生动态网页内容的Java类。Servlet主要是用来
处理或者是存储HTML表单提交的数据,产生动态内容,在无状态的HTTP协议下管理状态信息。
94、说一下Servlet的体系结构。
所有的Servlet都必须要实现的核心接口是javax.servlet.Servlet。每一个Servlet都必须要
直接或者是间接实现这个接口,或者是继承javax.servlet.GenerriServlet或者
javax.servlet.http.HTTPServlet。最后,Servlet使用多线程可以并行的为多个请求服务。
95、Applet和Servlet有什么区别?
Applet是运行在客户端主机的浏览器上的客户端Java程序。而Servlet是运行在web服务器上的服务
端的组件。applet可以使用用户界面类,而Servlet没有用户界面,相反,Servlet是等待客户端的
HTTP请求,然后为请求产生响应。
96、GenericServlet和HttpServlet有什么区别?
GenericServlet是一个通用的协议无关的Servlet,它实现了Servlet和ServletConfig接口。继承自
GenericServlet的Servlet应该要覆盖service()方法。最后,为了开发一个能用网页上服务于使用
HTTP协议请求的Servlet,你的Servlet必须要继承自HttpServlet。
97、解释一下Servlet的声明周期。
对每一个客户端的请求,Servlet引擎载入Servlet,调用它的init()方法,完成Servlet的初始化。然
后,Servlet对象通过为每一个请求单独调用service()方法来处理所有随后来自客户端的骑牛,最后,
调用Servlet(这里应该是Servlet而不是server)的destroy()方法把Servlet删除掉。
98、doGet()方法和doPost()方法有什么区别?
doGet():GET方法会把名值对追加在请求的URL后面。因为URL对字符数目有限制,进而限制了用在
客户端请求的参数值的数目。请求请求中的参数值是可见的,因此,敏感信息不能用
这种方式传递。
doPost():POST方法通过把请求参数值放在请求体中来克服GET方法的限制,因此,可以放松参数
的数目是没有限制的。最后,通过POST请求传递的敏感信息对外部客户端是不可见的。
99、什么是Web应用程序?
Web应用程序是对Web或者是应用服务器的动态扩展。有两种类型的Web应用:面向表现和面向服务的。
面向表现的Web应用程序会产生包含了很多种标记语言和动态内东的交互web页面作为对请求的响应。
而面向服务的Web应用实现了Web服务的端点(endpoint)。一般来说,一个Web应用可以看成一组安装
在服务器URL名称空间的特定子集下面的Servlet的集合。
100、什么是服务端包含(Server Side Include)?
服务端包含(SSI)是一种简单的解释型服务端脚本语言,大多数时候仅用在Web上,用servlet标签嵌
如进来。SSI最常用的场景是把一个或多个文件包含到Web服务器的一个Web界面中。当浏览器访问
Web页面的时候,Web服务器会用对应的servlet产生的文本来替换Web页面中的servlet标签。
101、转发与重定向的区别?
转发在服务器端完成的;重定向是在客户端完成的
转发的速度快;重定向速度慢
转发的是同一次请求;重定向是两次不同请求
转发不会执行转发后的代码;重定向会执行重定向之后的代码
转发地址栏没有变化;重定向地址栏有变化
转发必须是在同一台服务器下完成;重定向可以在不同的服务器下完成
102、什么是Servlet链(Servlet Chaining)?
Servlet链是把一个Servlet的输出发送给另一个Servlet的方法。第二个Servlet的输出可以
发送给第三个Servlet,依次类推。联调上最后一个Servlet负责把响应发送给客户端。
103、你如何知道是哪一个客户端的机器正在请求你的Servlet?
ServletRequest类可以找出客户端机器的IP地址或者是主机名。getRemoteAddr()方法获取
客户端主机的IP地址,getRemoteHost()可以获取主机名。
104、HTTP响应的结构是怎么样的?
HTTP响应由三个部分组成:
1、状态码(Status Code):描述了响应的状态。可以用来检查是否成功的完成了请求。请求失败的
情况下,状态码可以用来找出失败额原因。如果Servlet没有返回状态码,默认会返回成功的
状态吗HttpServletResponse.SC_OK。
2、HTTP头部(HTTP Header):它们包含了更多关于响应的信息。比如:头部可以指定认为响应过期的
过期日期,或者是指定用来给用户安全的传输实体内容的编码格式。
3、主体(Body):它包含了响应的内容。它可以包含HTML代码,图片,等等。主题是由传输在HTTP
消息头中紧跟在头部后面的数据字节组成的。
105、什么是cookie?session和cookie有什么区别?
cookie是Web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个Web服务器存储
cookie。以后浏览器在给特定的Web服务器发请求的时候,同时会发送给所有为该服务器存储的
cookie。以下是seesion与cookie的区别:
1、无论客户端浏览器做怎么样的设置,session都应该能正常工作。客户端可以选择禁用cookie,
但是,session仍然是能够工作的,因为客户端无法禁用服务端的session。
2、在存储数据量方面session和cookie也是不一样的。session能够存储任意的Java对象,cookie
只能存储String类型的对象。
106、浏览器和Servlet通信使用的是什么协议?
HTTP协议。
107、什么是HTTP隧道?
HTTP隧道是一种利用HTTP或者HTTPS把多种网络协议封装起来进行通信的技术。因此,HTTP协议扮演
了一个打通用于通信的网络协议的管道的包装器的角色。把其他协议的请求掩盖成HTTP的请求就是
HTTP隧道。
108、什么是URL编码和URL解码?
URL编码是负责把URL里面的空格和其他的特殊字符替换成对应的十六进制表示,反之就是解码。