a) 九种基本数据类型的大小,以及他们的封装类
boolean 取值只有true 和 false,大小为1bit(1字节byte = 8bit) 封装类为Boolean
char char在Java中是2byte(16bit),因为Java用的是Unicode 封装类为Character
byte byte大小为8bit 封装类Byte
short short大小为16bit 封装类Short
int int 大小为32bit 封装类Integer
long long 大小为 64bit 封装类Long
float float 大小为 32bit 封装类Float
double double 大小为 64bit 封装类Double
void Void 类是一个不可实例化的占位符类 封装类Void
b) Switch能否用string做参数,equals与==的区别
开发过程中,java中的switch功能不支持字符串作为条件。使用枚举可以解决这个问题。
import java.util.Scanner;
public class switchUseString {
@SuppressWarnings("resource")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String day = sc.nextLine();
switch (Day.toDay(day.toUpperCase())) {
case SUNDAY:
System.out.println("星期天");
break;
case MONDAY:
System.out.println("星期一");
break;
case TUESDAY:
System.out.println("星期二");
break;
case WEDNESDAY:
System.out.println("星期三");
break;
case THURSDAY:
System.out.println("星期四");
break;
case FRIDAY:
System.out.println("星期五");
break;
case SATURDAY:
System.out.println("星期六");
default:
break;
}
}
public enum Day{
SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY;
public static Day toDay(String str){
return valueOf(str);
}
}
}
基本数据类型的比较,应用双等号(==),比较的是他们的值。
引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中。
复合数据类型(类)用(==)表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同。
复合数据类型之间进行equals比较,表示的两个变量是否是对同一个对象的引用,即堆中的内容是否相同。
第三个例子,两个对象均不是new出来的,它们其实指向的是同一个地址
c) Object有哪些公用方法,一些特性,Hashcode的作用
boolean equals(Object obj) //指示其他某个对象是否与此对象“相等”。
Class<?>
getClass() //
返回此
Object
的运行时类。
int hashCode() //返回该对象的哈希码值。非常重要的一个函数,和equals()方法一样重要,建议去看源码。
void notify() //唤醒在此对象监视器上等待的单个线程。
void notifyAll() //唤醒在此对象监视器上等待的所有线程。
String toString() //返回该对象的字符串表示。
void wait() //在其他线程调用此对象的 notify()
方法或 notifyAll()
方法前,导致当前线程等待。
void wait(long timeout) // 在其他线程调用此对象的 notify()
方法或 notifyAll()
方法,或者超过指定的时间量前,导致当前线程等待。
void wait(long timeout, int nanos)//在其他线程调用此对象的 notify()
方法或 notifyAll()
方法,或者其他某个线程中断当前线程,或者已超 过某个实际时间量前,导致当前线程等待。
equals() :默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址 (是不是同一个对象)
要是类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。。equals方法 用于比较对象的内容是否相等(覆盖以后)
HashCode:hashcode方法一般只有在集合中用到。当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。
将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果 hashcode值相等,就再通过equals方法判断要放入对象与集合中的任意对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。
d) Java的四种引用,应用场景
从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
强引用:是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
软引用:如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用:如果一个对象只具有弱引用,那就类似于可有可物的生活用品。 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
虚引用:"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
e) ArrayList、LinkedList、Vector的区别,各自的应用场景
|--ArrayList 底层数据结构是数组,查询快,增删慢。线程不安全,效率高
|--LinkedList 底层数据结构是链表,查询慢,增删快。线程不安全,效率高
|--Vector 底层数据结构是数组,查询快,增删慢。线程安全,效率低
f) String、StringBuffer与StringBuilder的区别
三者在执行速度方面的比较:StringBuilder > StringBuffer > String
String类是不可变类,任何对String的改变都会引发新的String对象的生成;StringBuffer则是可变类,任何对它所指代的字符串的改变都不会产生新 的对象。StringBuffer和StringBuilder类的原理和操作基本相同,区别在于StringBufferd支持并发操作,线性安全,适合多线程中使用。StringBuilder 不支持并发操作,线性不安全,不适合多线程中使用,但其在单线程中的性能比StringBuffer高。
StringBuilder:线程非安全的,StringBuffer:线程安全的
1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
g) Map、Set、List、Queue、Stack的特点与用法
Map指映射,Set指集,List指列表,Queue指队列,Stack指栈
Map将键映射到值的一种对象。一个映射不能包含重复的键;每个键最多只能映射到一个值,值可以是重复的。
Set继承自父接口Collection,相对于存入顺序,值是无序的,并且值是唯一的(value1.equals(value2)),不能重复。
List继承自父接口Collection,存入的值是有序的,值不唯一,可以有重复内容。
如果涉及到堆栈,队列等操作,应该考虑用List。对于需要快速插入,删除元素,应该使用LinkedList,如果单线程中需要快速随机访问元素,应该使用ArrayList,如果多线程中要快速随机访问元素,则使用vector。
Collection ——|
|——List——|
| |——ArrayList(底层是数组)
| |——Vector(底层是数组)
| | |__Stack
| |
| |——LinkedList(底层是链表)
|
|——Set——|
|——HashSet(底层是hash表)
|——TreeSet(底层是红黑树)
Map——|
|——TreeMap(底层是红黑树)
|——HashMap(HashMap底层就是一个数组结构,数组中的每一项又是一个链表,数组和链表的结合体)
|——Hashtable
|——linkedHashMap
在集合中常见的数据结构
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
h) HashMap和HashTable的区别
Hashtable和HashMap类有三个重要的不同之处
第一个不同主要是历史原因。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。
第二个不同(最重要的)是Hashtable的方法是同步的,而HashMap的方法不是。使用者不用采取任何特殊的行为就可以在一个多线程的应用程序中用一个Hashtable,但必须为HashMap提供额外的同步。常用的方法就是利用Collections类的静态方法synchronizedMap(),它创建一个线程安全的Map对象,并把它作为一个封装的对象来返回。这个对象的方法可以让你同步访问潜在的HashMap。这么做的结果就是当你不需要同步时,你不能切断Hashtable中的同步(比如在一个单线程的应用程序中),而且同步增加了很多处理费用。
第三个不同是,只有HashMap可以让你将null作为key或value。HashMap中只能有一条记录可以是一个空的key,但任意数量的记录可以是空的value。hashtable不允许这样。并且HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。
i) HashMap和ConcurrentHashMap的区别,HashMap的底层源码
HashMap不是线程安全的,因此多线程操作时需要格外小心。在JDK1.5中,Doug Lea开发出了concurrent包,Map也可以实现线程安全。
ConcurrentHashMap具体是怎么实现线程安全的呢?
从ConcurrentHashMap代码中可以看出,它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中。ConcurrentHashMap中默认是把segments初始化为长度为16的数组。根据ConcurrentHashMap.segmentFor的算法,3、4对应的Segment都是segments[1],7对应的Segment是segments[12]。
(1)Thread1和Thread2先后进入Segment.put方法时,Thread1会首先获取到锁,可以进入,而Thread2则会阻塞在锁上
(2)切换到Thread3,也走到Segment.put方法,因为7所存储的Segment和3、4不同,因此,不会阻塞在lock()
j) TreeMap、HashMap、LindedHashMap、Hashtable的区别,应用场景
Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。
K)OOM产生原因,如何解决
OOM即Out Of Memory 内存溢出
JVM内存区域:
①程序计数器:一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器。
②Java虚拟机的栈:Java虚拟机栈是线程私有的,生命周期与线程相同。通常用来存放基本数据类型,引用数据类型。Java虚拟机的栈有三个区域:局部变量区,运行环境区,操作数区。
栈区域有两种异常类型:如果线程请求的栈深度大于虚拟机所允许的深度,将抛StrackOverflowError异常;如果虚拟机栈可以动态扩展(大部分虚拟机都可动态扩展),扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。
③本地方法栈:与虚拟机栈的作用相似,区别是虚拟机栈为虚拟机执行Java方法服务,本地方法栈则为虚拟机用到的Native方法服务。和虚拟机栈一样,可能会抛出StackOverflowError和OutOfMemoryError异常。
④Java Heap(堆):Java堆是JVM所管理的内存中最大的区域。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,主要存放对象实例。Java堆是垃圾收集器管理的主要区域,其可细分为新生代和老年代。如果在堆中没有完成实例的内存分配,并且也无法再扩展时,会抛出OutOfMemoryError异常。
⑤方法区:方法区和Java堆一样是各个线程共享的内存区域,用于存放已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。当方法区无法满足内存分配的需求时,将抛出OutOfMemoryError异常。方法区同时包含运行时常量池,用于存放编译期生成的各种字面量和符号引用。
⑥直接内存:直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,是JVM外部的内存区域,这部分区域也可能导致OutOfMemoryError异常。
常见内存溢出错误解决办法
①OutOfMemoryError异常
除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能。Java Heap 溢出一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess. java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。
出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,于是就能找到泄漏对象时通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。如果不存在泄漏,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。
- 检查程序,看是否有死循环或不必要地重复创建大量对象。找到原因后,修改程序和算法。 我以前写一个使用K-Means文本聚类算法对几万条文本记录(每条记录的特征向量大约10来个)进行文本聚类时,由于程序细节上有问题,就导致了Java heap space的内存溢出问题,后来通过修改程序得到了解决。
- 增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。如:
set JAVA_OPTS= -Xms256m -Xmx1024m
②虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
这里需要注意当栈的大小越大可分配的线程数就越少。
③运行时常量池溢出
异常信息:java.lang.OutOfMemoryError:PermGen space
如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。
④方法区溢出
方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。
异常信息:java.lang.OutOfMemoryError:PermGen space
方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。
l) Collection包结构,与Collections的区别
Collection是Collection层次结构中的根接口。Collection 表示一组对象,这些对象也称为collection 的元素。一些collection 允许有重复的元素(List及其实现子类),而另一些则不允许(Set及其实现子类)。一些collection 是有序的(List及其实现子类),而另一些则是无序的(Set及其实现子类)。
boolean add(E e)将指定元素添加到此Collection中
boolean addAll(Collection<? extends E> c)将指定Collection中的所有元素添加到此Collection中
void clear() 移除此Collection中的所有元素
boolean contains(Object o)如果此Collection包含指定的元素返回true
boolean containsAll(Collection<?> c)如果此Collection中包含指定Collection中的所有元素,返回true
Iterator<E> iterator()返回在此Collection的元素上进行迭代的迭代器
boolean retainAll(Collection<?> c)仅保留此Collection中也包含在指定Collection中的元素
Object[] toArray()返回包含此Collection中所有元素的数组
Collections 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。它包含在 collection 上操作的多态算法,即“包装器”,包装器返回由指定 collection 支持的新 collection,以及少数其他内容。 java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
m) Excption与Error的区别
Throwable 是所有 Java 程序中错误处理的父类 ,Error和Exception都继承自Throwable,并且实现了Serializable接口。
Error表示由 JVM 所侦测到的无法预期的错误,由于这是属于JVM 层次的严重错误,导致JVM无法继续执行,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。合理的应用程序不应该去try/catch这种错误。绝大多数的错误都是非正常的,就根本不该出现的。
Exception 是Throwable的一种形式的子类,用于指示一种合理的程序想去catch的条件。即它仅仅是一种程序运行条件,而非严重错误,并且鼓励用户程序 去catch它。表示可恢复的例外,这是可捕捉到的。
Error和RuntimeException 及其子类都是未检查的异常(unchecked exceptions),而所有其他的Exception类都是检查了的异常(checked exceptions).
checked exceptions: 通常是从一个可以恢复的程序中抛出来的,并且最好能够从这种异常中使用程序恢复。比如FileNotFoundException
unchecked exceptions: 通常是如果一切正常的话本不该发生的异常,但是的确发生了。比如ArrayIndexOutOfBoundException, ClassCastException等。
Exception和Error的不同总结:
Exception:
1.可以是可被控制(checked) 或不可控制的(unchecked)
2.表示一个由程序员导致的错误
3.应该在应用程序级被处理
Error:
1.总是不可控制的(unchecked)
2.经常用来用于表示系统错误或低层资源的错误
3.如何可能的话,应该在系统级被捕捉
n) Override和Overload的含义去区别
Override,又叫重写或者覆盖,是指父类中已有的方法,子类中也定义了修饰符 返回类型 方法名 参数列表等等都一样的方法,而方法的内容不同
例如:
class Fu{
public void print(){
System.out.println("Fu is here");
}
}
class Zi extends Fu{
public void print(){
System.out.println("Zi is here");
}
}
public class OverrideAndOverload {
public static void main(String[] args) {
Fu fu = new Fu();
fu.print();
Fu zi = new Zi();//体现了多态的三个必要条件:继承,重写,父类引用指向子类对象
zi.print();
}
}
//结果:
//Fu is here
//Zi is here
Overload又叫重载,指同一个类中有两个及其以上的相同方法名的方法。
例如:
class Load{
public void print(){
System.out.println("无参数的时候");
}
public void print(String str){
System.out.println("有参数的时候: "+ str);
}
public void print(String str ,int num){
System.out.println("有参数的时候: "+str+"次数:"+num);
}
}
public class OverrideAndOverload {
public static void main(String[] args) {
Load load = new Load();
load.print();
load.print("重载");
load.print("重载",2);
}
}
//结果:
//无参数的时候
//有参数的时候: 重载
//有参数的时候: 重载次数:2
o) Interface与Abstract
p) Static class与non static classs 的区别
static class的成员和方法都可以使用类名来引用,而non-static class必须使用实例对象来引用自己的成员和方法。
static与non-static在引用数据成员方面的差别:因为static、non-static的数据相关性,static只能引用类的static数据成员;而non-static既可以引用类的static数据成员,也可以引用对象自身的数据。
Java允许我们在一个类里面定义静态类。比如内部类(nested class)。把内部类封闭起来的类叫外部类。在Java中,我们不能用static修饰顶级类(top level class)。只有内部类可以用static修饰。
静态内部类和非静态内部类的区别
(1)内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。
(2)非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。
(3)一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。
q) Java的锁机制
Collection<String> c = Collections.synchronizedCollection(new ArrayList<String>());
List<String> list = Collections.synchronizedList(new ArrayList<String>());
Set<String> set = Collections.synchronizedSet(new HashSet<String>());
Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
r) Concurrent包了解
在JDK1.5出现了Java.util.concurrent工具包用以简化并发业务的开发,借助该包将有效的减少竞争条件和死锁线程。
Executor:具体Runnable任务的执行者。
ExecutorService:一个线程池管理者,其实现类有多种,程序员可以将Runnable、Callable提交到线程池让起调度。
Semaphore:一个计数信号量
ReentrantLock:一个可重入的互斥锁定lock,功能类似synchronized,但更强大
Future:与Runnable、Callable进行交互的接口,比如一个线程执行结束后取返回的结果
BlockingQueue:阻塞队列
CompletionService:ExecutorService的扩展,可以获得线程执行结果
CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CyclicBarrier:一个同步辅助类,它允许一组线程相互等待,直到到达某个公共屏障点
Future:Future表示异步计算的结果
ScheduledExecutorService:一个ExecutorService,可安排在给定的延迟后运行或定期执行的命令
详细内容参考:http://www.open-open.com/bbs/view/1320131360999/
s) wait()和sleep()的区别,for each()和正常for循环效率对比
sleep()方法属于Thread类,该方法可以让程序暂停执行指定的时间,让出CPU给其他线程,但他的监控状态依然保持着,当到了指定的时间又会自动恢复运行状态,调用sleep()方法的过程中,线程不会释放对象锁。
wait()方法属于Object类,当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
sleep与wait的不同点是: sleep并不释放锁,并且sleep的暂停和wait暂停是不一样的,obj.wait会使线程进入obj对象的等待集合中并等待唤醒。
wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。
For each 底层其实是通过iterator实现的。仅遍历的话使用for each()更合适,效率更高。for循环内部如果涉及到复杂操作的话,使用for循环效率更高。
t) Java IO与NIO
IO是面向流的阻塞式IO,NIO是面向缓冲的非阻塞式IO
Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同,它将数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被完全读取/写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器(Selector),然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
参考:http://ifeve.com/java-nio-vs-io/
u) 反射的作用于原理
什么是Java中的类反射:Reflection 是 Java 的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。Java 的这一能力在实际应用中用得不是很多。Reflection 是 Java 被视为动态(或准动态)语言的关键,允许程序于执行期 Reflection APIs 取得任何已知名称之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,并可于执行期生成instances、变更 fields 內容或唤起 methods。
Java类反射中所必须的类:Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
总结:Java 反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。
反射有两个缺点。第一个是性能问题,用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况 下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。第二是安全限制,由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
参考:http://www.cnblogs.com/forlina/archive/2011/06/21/2085849.html
http://www.cnblogs.com/dyllove98/archive/2013/06/15/3137620.html
v) 泛型常用特点,List<String>能否转为List<Object>
w) 解析XML的几种方式的原理与特点:DOM、SAX、PULL
x) Java与C++对比,Java1.7与1.8新特性
y) JNI的使用