本文试题题库来源于网络。由于自身姿势水平较低,答案并不一定完全正确。如有意见或建议请联系[email protected]
Java中能创建volatile数组吗?
可以。不过只是一个指向数组的引用,而不是整个数组。如果改变引用指向的数组,将会收到volatile保护,但是多个线程同时改变数组的元素,volatile就不能起到保护。
volatile能使得一个非原子操作变成原子操作吗?
用volatile修饰 long 和 double 类型的变量,可使其变成原子操作。
volatile修饰符实践
原子操作。
内存屏障。当写一个volatile变量的时候,JMM会插入一个写屏障,读之前会插入读屏障。在写volatile域时,能保证任何线程都能看到写的值。在写之前,也能保证任何数值的更新对所有线程可见,因为内存屏障会将其他所有写的值更新到缓存。
volatile类型变量提供什么保证
顺序与可见性,禁止指令重排序,提供 happen-before 保证,确保一个线程的修改对其他线程是可见的。还可以提供原子性
10个线程和2个线程的同步代码,哪个更容易
从代码角度,两者时间复杂度是相同的。同步策略上则不一样,同步策略选择依赖于线程的数量,越多的线程意味着更大的竞争,需要利用同步技术,如锁分离。更复杂
如何调用wait()方法,是使用 if 块还是循环
wait方法应该在循环体中使用,因为当线程获得CPU开始执行的时候,其他条件可能还没有满足。在处理前应该循环检测条件是否满足会更好。
synchronized(obj){
while(condition does not hold){
obj.wait();
}
}
參见Effictive Java
什么是多线程下的伪共享(false sharing)
不同处理器上的线程对于变量的修改依赖于相同的缓存行
什么是Busy spin?为什么要用
自旋锁?不释放CPU资源的情况下等待事件。
如何获取一份线程dump文件
Linux可使用 kill -3 PID(Java进程ID)来获取Java应用的dump文件。Windows下可以按下 Ctrl + break. JVM会将dump文件打印到标准输出或者错误文件中。
Swing是否为线程安全?
不是。原因不知道,不了解Swing。
什么是线程局部变量
ThreadLocal方法:void set(T value)、T get()、T initialValue()
ThreadLocal.每个线程Thread内部有一个Thread.ThreadLocalMap类型的成员变量threadlocals来存储实际变量的副本。K为当前ThreadLocal变量,V为变量的副本。初始时,Thread里面的线程为空,当ThreadLocal变量调用set或者get方法时,就会完成对threadlocals进行初始化。在当前线程里面,如果要使用副本变量,可以通过get方法在threadlocals里面查找。
怎样用wait-notify方法来解决生产者-消费者问题?
思路:在同步块中调用wait和notify方法,如果阻塞,通过循环来测试等待条件。
用Java写一个线程安全的单例模式
线程安全即初始化是在多线程环境中,仍能保证单例。用枚举类是最简单实现创建线程安全的单例模式。
public static SingletonThreadSafe getInstance(){
if (singletonThreadSafe == null){
synchronized (SingletonThreadSafe.class){
new SingletonThreadSafe();
}
}
return singletonThreadSafe;
}
//然而在多线程下,存在指令重排序问题,因此可以设置singletonThreadSafe为volatile
sleep()方法和wait()方法区别
两者都是暂停当前运行的线程。区别在于sleep()方法不会释放锁,而wait()方法意味着等待条件,一般在循环体中,该方法需要释放锁。只有这样其他线程才能在满足条件的时候获得锁。
什么是不可变对象(immutable object)?如何创建不可变对象
一旦对象被创建,状态就不能再改变。任何修改都会创建一个新的对象。如String,Integer等包装类。
我们能创建一个包含可变对象的不可变对象吗?
当然啦。需要注意的是不要共享可变对象的引用,需要改变时就返回原对象的一个拷贝。例 : 对象中包含一个日期对象的引用。
Java中应该用什么数据类型代表价格?
BigDecimal.如果有性能和内存方面的考虑可以使用预定义精度的double
怎样将byte转换为String
new String(byte) //注意编码格式
怎样将bytes转换为long
String接收,在Long.ParseLong()
能将int强制转换为byte类型吗?大于byte范围将会什么现象?
可以。高24位将会被丢弃。byte范围 -127-128
存在两个类,B继承A,C继承B,能将B转换为C吗?C=(C)B
可以。不过容易出现类型转换异常。
哪个类包含clone方法,是Cloneable还是Object
java.lang.Cloneable是一个标识性接口,不包含任何方法,clone方法在Object中定义,是一个native方法
Java中的++操作是线程安全的吗?
不是。并非原子操作
a = a + b 和 a += b有什么区别?
+=隐式的将操作结果类型转换为持有的结果类型。
byte a = 127;
byte b = 127;
b = a + b; // error : cannot convert from int to byte
b += a; // ok
能在不强制转换的情况下将一个double类型赋值给long吗?
不能,double的类型比long更广
3*0.1 == 0.3将会返回true还是false
false,有些浮点数不能精确的表示出来(巨坑。。MD。。可以转换成二进制看)
int和Integer哪个会占更多的内存
Integer。包装类,也要保存对象
为什么Java中的String要设计成不可变(Immuable)
使用太频繁,设置不可变,方便多客户端共享
能在switch中使用String吗?
Java 7开始可以。语法糖,内部实现case中使用的是String的hashCode
Java中的构造器链是什么?
当从一个构造器中调用另一个构造器时. 只有重载了 构造器才会出现
64位JVM中,int长度是多少
4个字节,32位。与平台无关。
Serial 与 Parallel GC之间的不同之处
两者在GC执行的时候都会stop-the-world. Serial默认是复制收集器。Parallel使用多个GC线程来执行。
Java中WeakReference与SoftReference区别
Java中一共有4种引用类型:
StrongReference:强引用,new出来的对象,只要引用存在,就不会给GC回收
SoftReference:软引用,只有即将发生OOM的时候会被回收
WeakReference:弱引用,只要有GC就会被回收
PhantomReference:虚引用,或者幽灵引用,被回收的时候仅仅收到系统通知以下。
WeakHashMap是怎样工作的?
与正常的HashMap相似,但是是以弱引用作为key,意思是key对象没有任何引用的时候,key/value就会被回收
JVM选项 -XX:+UserCompressedOops什么用,为什么要用
应用从32位JVM迁到64位JVM时,由于对象的指针从32位增加到了64位,因此堆内存会突然增加,差不多要翻倍。此选项用于压缩,使用32位OOP而不是64位
怎样通过Java判读JVM是62位还是64位?
可以检查某些属性如sun.arch.data.model或者os.arch来获取信息
32位JVM和64位JVM最大堆内存是多少?
32位是2^32次方,4G..64位无限制。
JRE,JDK,JVM,JIT之间有什么不同
JIT(Just In Time Compilation)即时编译,当代码执行超过一定的阈值的时候,会将字节码编译成本地代码。
解释Java堆空间及GC
Heap:所有线程共享,JVM启动是分配,对象创建的时候从堆中分配内存。GC是JVM的一个进程,回收无用对象内存,用于将来的分配。
能保证GC执行吗?
不能,虽然可以调用System.gc(),或者Runtime.getRunTime().gc(), 但是没有办法保证执行
怎样获取Java程序使用的内存?堆使用的百分比
可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及最大堆内存。通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间。Runtime.freeMemory() 方法返回剩余空间的字节数,Runtime.totalMemory() 方法总内存的字节数,Runtime.maxMemory() 返回最大内存的字节数
Java中堆和栈有什么区别
堆:线程共享,存放Java对象 栈:线程私有,保存方法栈帧和局部变量
a==b 和 a.equals(b)有什么区别?
略
a.hashCode()有什么用?与a.equals(b)有什么关系?
hashCode()方法是相应对象整形的hash值。常用于基于hash的集合类,如Hashtable,HashMap,LinkedHashMap。依据Java规范,使用equals方法判断相等的对象必有相同hash值
final,finally,finalize有什么不同
final,finally略。finalize:Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。该方法是有GC在确定这个对象没有被引用时调用,但是什么时候调用finallize没有保证。
Java的编译器常量是什么?使用它有什么风险
即公告静态不可变量 public static final . 在编译的时候会被替换掉。 弊端:当时用一个内部的或者第三方库中的共有编译常量,但是这个值被后面的人改了,但是客户端仍然在使用旧值。为避免,在更新依赖Jar文件时,确保重新编译程序。
List,Set,Map,Queue之间的区别。
List:元素间保持一定的顺序
Map:键值对
Queue:FIFO
poll()方法和remove()方法的区别
都是从队列中取出一个元素。poll()获取失败时会返回空,remove失败时会抛出异常。
Java中LinkedHashMap和PriorityQueue的区别是什么
PriorityQueue保证最高或者最低优先级的元素总是在队列的头部,LinkedHashMap维持的顺序是插入时候的顺序。当遍历一个PriorityQueue时没有任何顺序保证,但LinkedHashMap是插入时候的顺序
ArrayList和LinkedList的区别
ArrayList底层是维持的数组,支持随机访问,而LinkedList底层是连表,不支持随机访问。使用下标访问一个元素,ArrayList时间复杂度是O(1),而LinkedList是O(n)
用哪两种方法实现集合的排序
使用有序集合,如TreeSet和TreeMap。
也可以使用有顺序的集合,如list,然后通过Collections.sort()来排序
Java如何打印数组
Arrays.toString()
Java中的LinkedList是单项链表还是双向?
双向链表。
Java中的TreeMap是采用什么实现的
红黑树
Hashtable与HashMap区别
Hashtable采用同步,HaspMap没有。Hashtable不允许有空的key,HashMap的key可以为null
Java中的HashSet,内部是如何工作的?
HashSet内部采用HashMap来实现。由于Map需要key和value,每一个key都有一个默认的value,类似于HashMap,HashSet不允许重复的key,只允许一个null key,级Hash只允许存储一个null对象。
写一段代码,在遍历ArrayList时移除一个元素
(大坑,需要看源码) 一般使用循环遍历的时候,ArrayList是使用数组实现。删除元素时需要涉及到数组的移动,在遍历元素时,由于该元素符合删除条件,将该元素从数组中删除,并将后一个元素移动至当前位置,导致下一次遍历时没有遍历到,因此无法删除。使用foreach增强遍历时,实际上是Iterable,hasNext,next()元素的简写,在fastRemove()方法中,可以看到将一行modCount值加一,但是在ArrayList返回的迭代器中会做修改次数检查。
//倒叙遍历
public static void remove(ArrayList list) {
for (int i = list.size() - 1; i >= 0; i--) {
String s = list.get(i);
if (s.equals("bb")) {
list.remove(s);
}
}
}
//使用迭代器Iterator的remove方法
public static void remove(ArrayList list) {
Iterator it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("bb")) {
it.remove();
}
}
}
能自己写一个容器实现类,实现一个for-each循环吗?
可以。如果想要使用增强遍历,就要实现Iterable接口。如果实现Collection接口,就默认有该属性
HashMap和ArrayList默认大小是多少
16和10
ArrayList
HashMap 必须是2的整数次方
有没有可能两个不等的对象有相同的hashCode
有可能。两个相等的对象必须有相同的hashCode值,反之没规定
可以在hashCode中使用随机数吗?
不能。对象的hashCode的值必须是相等的。
Java中Comparator与Comparable有什么不同
Comparable用于定义对象的自然顺序,Comparator常用来定义用户指定的顺序。Comparable只能有一个,可以有多个Comparator来定义对象的顺序。
为什么重写equals时候,必须要重写hashCode方法
强制规范必须同时重写,许多hash类容器都依赖于hashCode与equals规定
在Java程序中有三个Socket,需要多少个线程来处理
如果是阻塞,则必须一个线程连接一个socket,非阻塞则不是
Java中怎样创建byteBuffer
ByteBuffer.allocate(int capacity) //创建一个指定capacity的ByteBuffer
ByteBuffer.allocateDirect(int capacity) //创建一个Direct的byteBubyteffer,在与IO操作交互的时候性能较好
ByteBuffer.wrap(byte[] array)
ByteBuffer.wrap(byte[] array,int offset,int length) //将一个byte数组或者数组的一部分包装成byteBuffer
Java采用的是大端还是小端?
大端
ByteBuffer中的字节序是什么
字节序:字节存放的顺序。大端 BIG-ENDIAN
Java中直接缓冲区与非直接缓冲区的区别
直接缓冲区可以通过allocateDirect方法来创建,也可以通过内存映射来创建,如果是直接缓冲区JVM会尽最大努力直接在此缓冲区上执行本机的I/O操作
非直接缓冲区写入步骤
创建一个临时的ByteBuffer对象
将非直接缓冲区的内容复制到临时缓冲区中
用临时缓冲区执行低层次I/O
临时缓冲区对象离开作用域,并最终成为被回收的无用数据
如果采用直接缓冲区会减少一次复制的过程,如果需要使用循环缓冲区,用直接缓冲区可以很大提高性能。虽然直接缓冲区可以使JVM更高效的I/O操作,单使用的内存是系统分配的,绕过了虚拟机堆栈,建立和销毁笔堆栈上的缓冲区要更大的开销。
Java中内存映射缓冲区是什么
?就是不全部加载到内存里面..
socket选项TCP NO DELAY是什么
有包头立即被发送。TCP_CORK组包
TCP协议与UDP协议有什么区别
略
Java中ByteBuffer与StringBuffer有什么区别
略
Java中编写多线程的时候有哪些最佳实践
给线程命名,方便调试
最小化同步的范围,而不是将整个方法同步,只对关键部分做同步
多使用volatile而不是synchronized
使用高层次的并发工具而不是使用wait() notify()方法来实现线程间通信。如BlockingQueue,CountDownLatch,Semeaphore
优先使用并发集合,而不是对集合进行同步
说出几点Java中使用Collections的最佳实践
如果不需要同步使用ArrayList而不是Vector
优先使用并发集合,而不是对集合进行同步
使用接口代表访问集合,如使用List存储ArrayList,用Map存储HashMap
用迭代器来循环集合
使用集合的时候使用泛型
在Java中使用线程的最佳实践
对线程命名
将线程和任务分离,使用线程池来执行Runnale或者Callable
使用线程池
说出5条IO最佳实践
IO对性能非常重要,在应用的关键路径上避免I/O操作。
使用带缓冲区的IO类,而不要读取字节或者字符
在finally中关闭流
使用内存映射文件获取更快的IO
JDBC的最佳实践
使用批量操纵插入和更新数据
使用PreparedStatement来避免SQL异常,并提高性能
使用数据库连接池
通过列名来获取结果集,而不是下标
Java中重载的最佳实践
不要一个方法接收int参数,另外几个接收Integer类型
不要重载参数一致,只是参数顺序不一致
参数多余5个,可以使用可变参数
在多线程下,SimpleDateFormat是线程安全的吗?
不是。需要给simpleDateFormat对象加锁(不建议,影响性能),或者放在方法里面随用随new,或者LocalThread里面
Java中,怎么在格式化的日期中显示时区
参数后加Z
Java中java.util.Date与java.sql.Date有什么区别
java.util.Date针对SQL语句,只有日期,没有时间。都有getTime方法返回毫秒数。java.sql.Date继承于java.sql.Date. 在读写数据库时,PreparedStament的setDate和ResultSet的getDate方法第二个参数都是。
如何计算两个日期之间的差距
public long dateDiff() {
Date date1 = new Date();
Date date2 = new Date();
long n1 = date1.getTime();
long n2 = date2.getTime();
long diff = Math.abs(n1 - n2);
diff /= 3600*1000*24;
return diff;
}
Java中如何将字符串转换为日期
SimpleDateFormat的parse方法。
public static Date string2Date(String date) {
// 创建日期格式化对象
SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
Date returnDate = null;
try {
// 日期格式化对象将日期字符串转换为日期对象
returnDate = df.parse(date);
} catch (ParseException e) {
log.error("String to date error!date=" + date, e);
return returnDate;
}
return returnDate;
}
单元测试
如何测试一个静态方法
可以使用PowerMock库来测试
怎样用Junit来测试一个方法的异常
都有哪些单元测试库
@Before和@BeforeClass有什么区别?
怎样检测一个字符串只包含数字?
public static boolean check(String string){
try {
int num = Integer.valueOf(string);
return true;
} catch (NumberFormatException e) {
return false;
}
}
Java中如何利用泛型写一个LRU缓存
http://blog.csdn.net/beiyeqingteng/article/details/7010411
写一段Java代码将byte转换为long
强制转换?
byte b = 123;
long l = (long)b;
在不使用StringBuffer情况下怎样反转字符串
public String reversal(String src) {
byte[] bytes = src.getBytes();
Stack stack = new Stack();
String string = null;
for (int i=0;i
stack.push(bytes[i]);// stack
}
for (Object object : stack) {
System.out.println(object);
}
return string;
}//写入栈,先进后出
Java中如何统计某一个单词出现的频率
public static void display(File file) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String line = null;
TreeMap treeMap = new TreeMap<>();
while ((line = bufferedReader.readLine()) != null) {
line.toLowerCase();
String reg1 = "\\s+";
String reg2 = "^[a-zA-Z]\\w*";
String str[] = line.split(reg1);//分词
for (String s : str) {
if (s.matches(reg2)) {
if (!treeMap.containsKey(s)){//匹配单词
treeMap.put(s,1);
}
else{
treeMap.put(s,treeMap.get(s)+1);
}
}
}
}
System.out.println(treeMap);
}
如何检查出两个给定的字符串是反序的
if(str1.length() != str2.length()){
return false;
}
String strTemp = str1.reversal();
if(strTemp.equals(str2)){
return true;
}
return false;
打印出数组中的重复元素
public class RepetitiveElements {
public static void main(String[] args) {
int[] arr = new int[]{1, 2, 3, 4, 5, 1, 3, 5};
Set set = new HashSet();
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length; j++) {
if (i != j && arr[i] == arr[j]) {
set.add(arr[i]);
}
}
}
System.out.println("重复的数字:" + set.toString());
}
}
Java中如何将字符串转换为整数
int num = Integer.valueOf(str);
return num;
在没有使用临时变量的情况下如何交换两个整数变量的值
//用栈
int a = 2;
int b = 3;
Stack stack = new Stack();
stack.push(a);
stack.push(b);
a=(int)stack.pop();
b=(int)stack.pop();
OOP
接口是什么,为什么要使用接口而不是具体实现类
略。Java8种可以在接口中声明静态的默认方法
抽象类与接口有什么不同
一个类只能继承一个父类,但是可以实现多个接口。抽象类必须被继承不能new. 接口主要定义类的类型,有助于实现多态机制。
里氏替换原则
子类可以拓展父类的功能,但不能改变父类的原有功能
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
子类可以增加自己的特有方法
子类重载父类的方法时,方法的前置条件(方法的形参) 要比父类方法的输入参数更宽松。
当子类的方法实现父类的抽象方法时,方法的后置条件(返回值)要比父类更严格。
什么情况下会违反迪米特法则?为什么会有这个问题
低耦合。
适配器模式是社么?什么时候用。
适配器模式对外提供接口的转换。如果客户端使用的是某些接口,但是我有两外的一些接口,可以写一个适配去连接这些接口。
什么是依赖注入和控制反转
略
构造器注入和setter注入,那种方式更好
构造器注入保证所有的注入都会被初始化。但是setter注入保证更好的灵活性来设置可选依赖。用XML描述:Setter可读性更强。强制依赖选择构造器,可选依赖选择setter
依赖注入和工厂模式之间有什么不同
都是讲对象的创建从应用的逻辑中分离,依赖注入比工厂模式更清晰,通过依赖注入,你的类就是POJO,它只知道依赖而不关心它们怎么获取。使用工厂模式,你的类需要通过工厂来获取依赖。
适配器模式和装饰模模式有什么区别
适配器模式用于桥接两个接口。装饰模式的目的在于不修改类的情况下给类增加新的功能。
适配器模式和代理模式有什么区别
代理模式是增加一个额外的中间层,以便支持分配,控制,或者只能访问
什么是模板方法模式
抽象类,子类继承复用
什么时候使用访问者模式
?
什么时候用组合模式
?
继承和组合之间有什么不同
两者都可以实现代码复用,但是组合比继承更灵活,因为组合运行在运行时选择不同的实现。
重载和重写
都允许使用相同的名称来实现不同的功能,重载是编译时期的活动,重写是运行时期的活动。可以在同一个类中重载方法,只能在子类中重写方法。重写必须要有继承。
Java中嵌套的公共静态类与与顶级类有什么区别
类的内部可以有多个嵌套的公共静态类。但是一个源文件只有一个顶级公共类,且必须与源文件名称一致。
OOP中组合,聚合,关联有什么区别
关联:两个类彼此之间有关系,就是彼此相关联。组合是比聚合更强的关联。组合中,一个对象是另一个对象的拥有者,而聚合是一个对象使用另一个对象。
开闭原则
一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。
抽象工厂模式和原型模式区别
?
享元模式
享元模式通过共享对象来避免创建过多的对象。为了使用享元模式必须保证对象是不可变的。如JDK中String池,Long池,Integer池等。
正则表达式
?待加强学习
Java中受检查异常和不受检查异常的区别
受检查异常:编译器在编译期间检查,必须通过强制处理或者throw子句中声明。
非受检查是RuntimeException的子类,在编译阶段不受编译器的检查。
Java中,throw和throws区别
throw用于抛出一个java.lang.Throwable类的实例化异常。可以用关键字throw抛出一个error或者exception. 如throw new IllegalArgumentException(“size must be multiple of 2″). 而throws作为方法签名的一部分,方法抛出相应的异常以便调用者能够处理。Java中,任何未处理的受检查异常强制在throws子句中声明。
Java中Serializable与Externalizable区别
Serializable接一个序列化Java类的接口,是JVM默认的序列化方式,以便于在网络上传输或者将他们的状态保存在磁盘上,成本高,脆弱,不安全。Externalizable允许控制整个序列化过程,指定特定的二进制格式,增加安全机制。
Java中DOM和SAX解析器有什么不同
DOM解析器将整个XML文档加载到内存中创建一个DOM模型树,可以更快的查找结点和修改XML结构。SAX是基于事件的解析器,不会将整个DOM文档加载到内存。因此DOM笔SAX更快,但也消耗更多内存,不适合解析大的XML文档。
为什么线程通信的方法wait(),notify(),notifyAll()被定义在Object类里
Java中每个对象都有一个锁(monitor, 也可以称为监视器) 并且wait(), notify()等方法用于等待对象的锁或者通知通知其他对象的监视器可用. 在Java对象中并没有可提供任何对象使用的锁和同步器. 因此这就是为什么这些方法是Object类的一部分,这样Java的每一个类都有用于线程间通信的基本方法.
为什么wait(),notify(),notify()方法都必须在同步方法或者同步块中被调用
当一个线程需要调用对象的wait()方法的时候, 这个线程必须必须拥有该对象的锁, 接着它会释放这个对象锁,并进入等待状态直到其他线程调用这个对象上的notify()方法. 同样,当一个线程需要调用对象的notify()方法时,会释放这个对象的锁.以便其他在等待的线程可以得到这个对象锁..由于所有这些方法都需要线程持有对象的锁,这样只能通过同步来实现. 因此只能在同步方法或者同步代码块中使用.