九种基本数据类型的大小,以及他们的封装类。
基本类型 | 大小(位) | 字节 | 最小值 | 最大值 | 封装类 |
---|---|---|---|---|---|
boolean | - | 1 | - | - | Boolean |
byte | 8 | 1 | -128 | 127 | Byte |
char | 16 | 2 | Unicode 0 | Unicode 2^16-1 | Character |
short | 16 | 2 | -2^15 | 2^15-1 | Short |
int | 32 | 4 | -2^31 | 2^31-1 | Integer |
float | 32 | 4 | Float | ||
double | 64 | 8 | Double | ||
long | 64 | 8 | -2^63 | 2^63-1 | Long |
void | - | - | - | Void |
Switch能否用string做参数?
JDK1.7之前是只支持int 或char
JDK1.7开始支持String
JDK1.5 开始支持 Enum 类
equals与==的区别
“==” 用于基本数据类型的比较,判断引用是否指向堆内存的同一快地址。
equals 用于判断两个变量是否是对同一个对象的引用,即堆中的内容是否相同,返回值为布尔类型。
可以用equals方法检测两个字符串是否相等。
一定不能使用 == 运算符检测两个字符串是否相等!== 用来确定两个字符串是否放置在同一个位置上。
如果虚拟机始终将相同的字符串共享,就可以使用 == 运算符检测是否相等。但是实际上只有字符串常量是共享的,而+或者substring等操作产生的结果并不是共享的。
Object有哪些公用方法?
- equals方法
Object类中的equals方法用于检测一个对象是否等于另外一个对象。
- hashCode方法
该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
- toString方法
用于返回表示对象值的字符串。
Java的四种引用,强弱软虚,用到的场景
- 强引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收期绝不会回收它。
- 软引用
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些 对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可以用来实现内存敏感的高速缓存。
- 弱引用
弱引用与软引用的区别在于:只具有弱引用的对象具有更短暂的生命周期。
在垃圾回收器线程扫描它所管辖的内存区域过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
不过,由于垃圾回收器是一个优先级很低的线程,因此不一样很快发现那些只有弱引用的对象。
如果你想引用一个对象,但这个对象具有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。
- 虚引用
虚引用不会决定对象的生命周期,如果一个对象仅持有虚引用,那么他就和没有任何引用一样,在任何适合都可能被垃圾回收器回收。
总结:
Java 4种引用的级别由高到低依次为:
强》软》弱》虚
Hashcode的作用
hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的
ArrayList、LinkedList、Vector的区别
ArrayList本质上是一个数组,当更多的元素添加到ArrayList中时,其大小会动态的增长,内部元素通过get和set方式进行访问。不是线程安全的。
LinkedList是一个双链表,因此在删除和添加元素的时候优于数组形式的ArrayList,但是在get和set方面弱于ArrayList;
Vector几乎和ArrayList一样,但是Vector是线程安全的,在更多元素进来时,Vector每次请求双倍的空间,而ArrayList每次对size增长50%。
String、StringBuffer与StringBuilder的区别
String是不可变类
StringBuffer是可变类
StringBuilder不是线程安全的
在执行效率方面,StringBuilder最高,StringBuffer次之,String最低
如果要操作的数据量比较小,应优先用String类
如果是在单线程下操作大量数据,应优先用StringBuilder类
如果在多线程下操作大量数据,应优先考虑StringBuffer类。
Map、Set、List、Queue、Stack的特点与用法
- Map
键映射到值的对象。 一个映射不能包含重复的键,每个键最多只能映射到一个值。
某些映射实现可明确保证其顺序,如TreeMap类;另一些映射实现不保证顺序,如HashMap类。
Map中元素,可以将key序列,value序列单独抽取出来。
使用keySet()抽取key序列,将map中所有keys生成一个Set。
使用 values() 抽取value序列,将map中的所有values生成一个Collection。
为什么一个是Set,一个是Collection。因为key是独一无二的,value允许重复。
- Set
一个不包含重复元素的Collection。
不可随机访问包含的元素
只能用lterator实现单向遍历
Set没有同步方法
- List
可随机访问包含的元素
元素是有序的
可在任意位置增删元素
不管访问多少次,元素位置不变
允许重复元素
用Iterator实现单向遍历,也可用ListIterator实现双向遍历
- Queue
先进先出
用offer()来加入元素
用poll()来获取并移出元素
peek()方法查看或使用前端元素
Queue实现通常不允许插入null元素
- Stack
后进先出
Stack继承自Vector,是同步的
提供了push、pop、peek、empty方法
- 用法
如果涉及到堆栈,队列等操作,应该考虑用List
对于需要快速插入,删除元素,应该用LinkedList
如果需要快速随机访问元素,应该用ArrayList
如果单线程环境,考虑非同步的类,效率较高。
HashMap和HashTable的区别
主要区别:线程安全,同步,速度
- HashMap几乎等价于HashTable,除了HashMap是非同步的,并可以接受null
HashMap和ConcurrentHashMap的区别,HashMap的底层源码
HashMap的本质是数组加链表。根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面。
ConcurrentHashMap在HashMap的基础上,将数据分为多个segment,默认16个,然后每次操作对一个segment加锁,避免多线程锁的几率,提高并发效率。
HashMap就是一个Entry数组,Entry数组中包含了键和值,其中next也是一个Entry对象,当hash冲突时,形成一个链表。
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n; //hash值冲突后存放在链表的下一个
key = k;
hash = h;
}
.........
}
HashMap存储数据的put方法
public V put(K key, V value) {
if (key == null) //如果键为null的话,调用putForNullKey(value)
return putForNullKey(value);
int hash = hash(key.hashCode());//根据键的hashCode计算hash码
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
//处理冲突的,如果hash值相同,则在该位置用链表存储
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
//如果key相同则覆盖并返回旧值
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
当我们往HashMap中put元素时,先根据key的hash值得到这个元素在数组中的位置(即下标),然后就可以把这个元素放到对应的位置中了,如果这个元素的位置上已经存在其他元素了,那么在同一个位子上的元素将会以链表的形式存放,新加入的放链表头,之前加入的放后面。
从HashMap中get元素时,首先计算key的hash值,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
如果没有与key相同的键,则调用addEntry方法创建一个Entry对象:
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
//如果要加入的位置有值,将该位置原先的值设置为新entry的next,也就是新entry链表的下一个节点
table[bucketIndex] = new Entry<>(hash, key, value, e);
if (size++ >= threshold) //如果大于临界值就扩容
resize(2 * table.length); //以2的倍数扩容
}
扩容数据
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);//用来将原先table的元素全部移到newTable里面
table = newTable; //再将newTable赋值给table
threshold = (int)(newCapacity * loadFactor);//重新计算临界值
}
TreeMap、HashMap、LindedHashMap的区别。
Collection包结构,与Collections的区别。
try catch finally,try里有return,finally还执行么?
- try中没有异常且try中有return
try---finally---return
- try中有异常,try中有return
try---catch---finally---return
总之finally永远执行
- Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
- Java面向对象的三个特征与含义。
Override和Overload的含义与区别
- 重写(Override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写。
返回值和形参都不能改变。即外壳不变,重写内在实现。
重写的好处在于子类可以根据需要,定义特定于自己的行为。
public class LiftOff {
public static void main(String args []){
Animal a= new Animal();
Animal b = new pig();
a.eat();
b.eat();
}
}
class Animal{
public void eat(){
System.out.println("Animal eat xx ");
}
}
class pig extends Animal{
public void eat(){
System.out.println("pig eat siliao");
}
}
Animal eat xx
pig eat siliao
重写规则:
参数列表必须完全与被重写方法相同(也就是说重写,不能添加写方法,不能添加参数。)
返回类型必须完全与被重写方法的返回类型相同
父类的成员方法只能被他的子类重写
声明为final的方法不能被重写
声明为static的方法不能被重写,但是能再次声明。
构造方法不能被重写
- 重载(Overload)
重载是在同一个类里,方法名字相同,参数不同,返回类型可相同也可不同的多个方法。
每个重载的方法都必须有一个独一无二的参数类型列表。
被重载的方法必须改变参数列表,被重载的方法可以改变返回类型,被重载的方法可以改变访问修饰符,方法能在同一个类中或在一个子类中被重载。
public class LiftOff {
public int test(){
System.out.println("Overload1");
return 1;
}
public void test(int a){
System.out.println("Overload1"+ a);
}
public String test(String a1 , String a2){
System.out.println("Overload1"+ a1+a2);
return a1;
}
public static void main(String args []){
LiftOff t=new LiftOff();
System.out.println(t.test());
t.test(2);
System.out.println(t.test("asd","erf"));
}
}
Overload1
1
Overload12
Overload1asderf
asd
重载和重写区别:
重载方法(Overload) | 重写方法(Override) | |
---|---|---|
参数列表 | 必须修改 | 不能改 |
返回类型 | 可以修改 | 不能改 |
异常 | 可以修改 | 可以减少或删除,不能抛出新的 |
访问修饰符 | 可以修改 | 只能降低限制,不能变高限制 |
限制又低到高: public、protected、private
Interface与abstract类的区别
如果一个类中包含抽象方法,那么这个类就是抽象类。类或方法声明为abstract
接口就是指一个方法的集合,接口中所有方法都没有方法体,接口通过关键字interface实现。
接口和抽象类的相同点:
- 都不能被实例化
- 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才才能被实例化。
不同点:
- 接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法;而抽象类可以有定义和实现,即其方法可以在抽象类中被实现。
- 接口需要实现(用implement),但抽象类只能被继承(用extends),一个类可以实现多个接口,但是一个类只可以继承一个抽象类,因此使用接口可以间接达到多重继承的目的。
- 接口强调特定功能的实现,"has - a" ;抽象类强调所属关系,"is - a "
- 接口中定义的成员变量默认为 public static final , 只能够有静态的不能被修改的数据成员,而且,必须给其赋值,其所以的成员方法都是public,abstract的,而且只能被这两个关键字修饰。而抽象类可以有自己的数据成员变量,也可以有非抽象的成员方法,而且,抽象类中的成员变量默认为default,当然也可以定义为private,protected,public。所以,当功能需要累积时,用抽象类,不需要累积时,用接口。
- 接口被运用于实现比较常用的功能,便于以后的维护;抽象类更倾向于充当公共类的角色,不适用于日后重新修改内部代码。
Static class 与non static class的区别
java多态的实现原理
实现多线程的两种方法:Thread与Runable
线程同步的方法:sychronized、lock、reentrantLock等
锁的等级:方法锁、对象锁、类锁
Java中锁的机制
:
synchronized 在修饰代码块的时候需要一个reference对象作为锁的对象。
在修饰方法的时候默认是当前对象作为锁的对象。
在修饰类的时候默认是当前的Class对象作为锁的对象。
线程同步的方法: sychronized、lock、reentrantLock分析
- 方法锁(synchronized修饰方法时)
通过在方法声明中加入synchronized关键字来声明synchronized方法。
- 对象锁(synchronized修饰方法或代码块)
当一个对象中有synchronized method 或 synchronized block 的时候调用此对象的同步方法或进入其同步区域时,就必须先获得对象锁,如何此对象的对象锁已被其他调用者占用,则需要等待此锁被释放。(方法锁也是对象锁)
写出生产者消费者模式。
ThreadLocal的设计理念与作用。
ThreadPool用法与优势。
Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
wait()和sleep()的区别
他们都是一种使线程暂停执行的方法
区别:
- 原理不同。sleep()是Thread类的静态方法;wait()方法是Object类的方法。
- 对锁的处理机制不同。sleep不放,wait释放。
- 使用区域不同
- sleep()必须捕获异常,wait()不需要
foreach与正常for循环效率对比
Java IO与NIO。
反射的作用与原理
反射机制能够实现在运行时对类进行装在,因此能增加程序的灵活性。
功能:
- 得到一个对象所属的类;
- 获取一个类所有的成员变量和方法;
- 在运行时创建对象
- 在运行时调用对象的方法
Java创建对象的方式有几种
- 通过new实例化一个对象
- 通过反射机制创建对象
- clone()
- 反序列化的方式