写的比较多,但自我感觉还是比较实用的。
J2se基础:
1. 八种基本数据类型的大小,以及他们的封装类;
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
a)、整数:包括int,short,byte,long
b)、浮点型:float,double
c)、字符:char
d)、布尔:boolean
基本类别 | 大小 | 最小值 | 最大值 | 包装类 |
---|---|---|---|---|
boolean | ------- | ------ | ------- | Boolean |
char | 16-bit | Unicode 0 | Unicode 2^16-1 | Character |
byte | 8-bit | -128 | +127 | Byte |
short | 16-bit | -2^15 | +2^15-1 | Short |
int | 32-bit | -2^31 | +2^31-1 | Integer |
long | 64-bit | -2^63 | +2^63-1 | Long |
float | 32-bit | IEEE754 | IEEE754 | Float |
double | 63-bit | IEEE754 | IEEE754 | Double |
更详细信息网址:http://blog.youkuaiyun.com/jj___jj/article/details/5589415
2. switch能否用String做参数?
switch(expr1)中,expr1是一个整数表达式,整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。因此传递给 switch 和case 语句的参数应该是 int、 short、 char 或者 byte,还有enum。 long,string 都不能作用于swtich。
在jdk 1.7中switch的参数类型可以是字符串类型。
3.equals 和==的区别
a). == 是一个运算符。
b).Equals则是string对象的方法,可以.(点)出来。
我们比较无非就是这两种 1、基本数据类型比较 2、引用对象比较
a)、基本数据类型比较
==和Equals都比较两个值是否相等。相等为true 否则为false;
b)、引用对象比较
==和Equals都是比较栈内存中的地址是否相等 。相等为true 否则为false;
需注意几点:
a)、string是一个特殊的引用类型。对于两个字符串的比较,不管是 == 和 Equals 这两者比较的都是字符串是否相同;
b)、当你创建两个string对象时,内存中的地址是不相同的,你可以赋相同的值。
所以字符串的内容相同。引用地址不一定相同,(相同内容的对象地址不一定相同),但反过来却是肯定的;
c)、基本数据类型比较(string 除外) == 和 Equals 两者都是比较值;
4.Object有哪些公用方法;
Object是所有类的父类,任何类都默认继承Object。
clone
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常
equals
在Object中与==是一样的,子类一般需要重写该方法
hashCode
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到
getClass
final方法,获得运行时类型
wait
使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生:
a). 其他线程调用了该对象的notify方法
b). 其他线程调用了该对象的notifyAll方法
c). 其他线程调用了interrupt中断该线程
d). 时间间隔到了
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常
notify
唤醒在该对象上等待的某个线程
notifyAll
唤醒在该对象上等待的所有线程
toString
转换成字符串,一般子类都有重写,否则打印句柄
内容比较多可自行百度,其实LZ也不太清楚。。。
6.Hashcode的作用;
首先,想要明白hashCode的作用,你必须要先知道Java中的集合。
总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。
这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
所以,Java对于eqauls方法和hashCode方法是这样规定的:
a)、如果两个对象相同,那么它们的hashCode值一定要相同;
b)、如果两个对象的hashCode相同,它们并不一定相同
上面说的对象相同指的是用eqauls方法比较。
你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降。
7. ArrayList,LinkedList,Vector的区别;
a) 线程安全:
Vector、Stack:线程安全;
ArrayList、LinkedList:非线程安全。
b)实现方式:
LinkedList:双向链表;
ArrayList,Vector,Stack:数组。
c)容量扩展方面:
由于ArrayList和Vector(Stack继承自Vector,只在Vector的基础上添加了几个Stack相关的方法,故之后不再对Stack做特别的说明)使用数组实现,当数组长度不够时,其内部会创建一个更大的数组,然后将原数组中的数据拷贝至新数组中,如需扩展,则每次至少扩展至(原长度*3)/2 + 1,如果在创建Vector时不指定capacityIncrement(自动扩展长度)的值,如需扩展,则每次至少扩展至原长度的2倍
8. String,StringBuffer,StringBuilder的区别:
String是字符串常量,StringBuffer是线程安全的,StringBuilder是线程不安全的。
a)Stirng:字符串常量,字符串长度不可变。Java中String是immutable(不可变)的。
b)StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。
c)StringBuilder:字符串变量(非线程安全)。在内部,StringBuilder对象被当作是一个包含字符序列的变长数组。
java.lang.StringBuilder是一个可变的字符序列,是JDK5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。
主要区别:
String 类型和StringBuffer的主要性能区别:String是不可变的对象, 因此在每次对String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,性能就会降低。
使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。所以多数情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
在某些特别情况下, String 对象的字符串拼接其实是被 Java Compiler 编译成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢
使用策略:
a)基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。
b)不要使用String类的"+"来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则。
c)为了获得更好的性能,在构造 StirngBuffer 或 StirngBuilder 时应尽可能指定它们的容量。当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能。
d)StringBuilder一般使用在方法内部来完成类似"+"功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中。
e)相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer。
9.Map、Set、List、Queue、Stack的特点与用法:
- Map
Map是键值对,键Key是唯一不能重复的,一个键对应一个值,值可以重复。
TreeMap可以保证顺序,HashMap不保证顺序,即为无序的。
Map中可以将Key和Value单独抽取出来,其中KeySet()方法可以将所有的keys抽取正一个Set。而Values()方法可以将map中所有的values抽取成一个集合。
- Set
不包含重复元素的集合,set中最多包含一个null元素
只能用Lterator实现单项遍历,Set中没有同步方法。
- List
有序的可重复集合。
可以在任意位置增加删除元素。
用Iterator实现单向遍历,也可用ListIterator实现双向遍历
- Queue
Queue遵从先进先出原则。
使用时尽量避免add()和remove()方法,而是使用offer()来添加元素,使用poll()来移除元素,它的优点是可以通过返回值来判断是否成功。
LinkedList实现了Queue接口。
Queue通常不允许插入null元素。
-
Stack
Stack遵从后进先出原则。
Stack继承自Vector。
它通过五个操作对类Vector进行扩展,允许将向量视为堆栈,它提供了通常的push和pop操作,以及取堆栈顶点的peek()方法、测试堆栈是否为空的empty方法等 -
用法
如果涉及堆栈,队列等操作,建议使用List
对于快速插入和删除元素的,建议使用LinkedList
如果需要快速随机访问元素的,建议使用ArrayLis
10. HashMap和HashTable的区别:
我们先看2个类的定义
public class Hashtable
extends Dictionary
implements Map, Cloneable, java.io.Serializable
public class HashMap
extends AbstractMap
implements Map, Cloneable, Serializable
可见Hashtable 继承自 Dictiionary 而 HashMap继承自AbstractMap
Hashtable的put方法如下
01. public synchronized V put(K key, V value) { //###### 注意这里1
02. // Make sure the value is not null
03. if (value == null) { //###### 注意这里 2
04. throw new NullPointerException();
05. }
06. // Makes sure the key is not already in the hashtable.
07. Entry tab[] = table;
08. int hash = key.hashCode(); //###### 注意这里 3
09. int index = (hash & 0x7FFFFFFF) % tab.length;
10. for (Entry e = tab[index]; e != null; e = e.next) {
11. if ((e.hash == hash) && e.key.equals(key)) {
12. V old = e.value;
13. e.value = value;
14. return old;
15. }
16. }
17. modCount++;
18. if (count >= threshold) {
19. // Rehash the table if the threshold is exceeded
20. rehash();
21. tab = table;
22. index = (hash & 0x7FFFFFFF) % tab.length;
23. }
24. // Creates the new entry.
25. Entry e = tab[index];
26. tab[index] = new Entry(hash, key, value, e);
27. count++;
28. return null;
29.}
注意1 方法是同步的
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常 HashMap的put方法如下
01. public V put(K key, V value) { //###### 注意这里 1
02. if (key == null) //###### 注意这里 2
03. return putForNullKey(value);
04. int hash = hash(key.hashCode());
05. int i = indexFor(hash, table.length);
06. for (Entry e = table[i]; e != null; e = e.next) {
07. Object k;
08. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
09. V oldValue = e.value;
10. e.value = value;
11. e.recordAccess(this);
12. return oldValue;
13. }
14. }
15. modCount++;
16. addEntry(hash, key, value, i); //###### 注意这里
17. return null;
18.}
注意1 方法是非同步的
注意2 方法允许key==null
注意3 方法并没有对value进行任何调用,所以允许为null
补充:
Hashtable 有一个 contains方法,容易引起误会,所以在HashMap里面已经去掉了
当然,2个类都用containsKey和containsValue方法。
HashMap Hashtable
父类 AbstractMap Dictiionary
是否同步 否 是
k,v可否null 是 否
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,
主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。