一、九种基本数据类型的大小,以及他们的封装类
关于JAVA基本数据类型
名称 |
解释 |
长度(位) |
默认值 |
封装类 |
byte |
字节 |
8 |
0 |
Byte |
shot |
短整型 |
16 |
0 |
Short |
int |
整型 |
32 |
0 |
Integer |
long |
长整型 |
64 |
0 |
Long |
float |
浮点型 |
32 |
0.0f |
Float |
double |
双精度 |
64 |
0.0d |
Double |
char |
字符型 |
16 |
‘\u0000’ |
Character |
boolean |
布尔型 |
1 |
false |
Boolean |
void |
|
|
|
|
操作系统16位的时候,int 2字节,操作系统32位的时候,int 4字节,由于32位系统之前占主流地位,实际现在就算是64位系统,出于兼容性考虑,int也是4字节的。
Java的类型分成两种,一种是基本类型,一种是引用类型。两种的本质区别就是:基本类型是在堆栈处分配空间存“值”。但是引用类型,是在堆里面分配空间存“值”。Void是不能new出来,也就是不能在堆里面分配空间存对应的值。那就是一开始在堆栈处分配好空间了。所以,有些人将Void归成基本类型,也有道理。
二、Switch能否用string做参数?
- JDK1.7之前不能用,JDK1.7后可以用。
- switch后面的括号里面只能放int类型的值,但由于byte,short,char类型,它们会 自动 转换为int类型(精精度小的向大的转化),所以它们也支持。
- 我们也可以用枚举类型实现switch可传入string参数。
三、equals与==的区别
前者比较值,后者比较在内存中地址的位置。
String比较特殊重写了equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
如果自定义的类重写了equals值,用于比较值相同,一定要重写hashcode方法,因为在HashSet/HashMap/HashTable进行查重比较的时候,用于hashcode
四、Object有哪些公用方法?
1.protected Object clone()创建并返回此对象的一个副本。
1)浅复制和深复制的概念
浅复制:被复制的对象的所有变量都与原来的对象有相同的值,但是指向的引用的对象相同,即地址相同,操作一个对象,另一个也会改变。
深复制:被复制的对象的所有变量都与原来的对象有相同的值,但是复制了引用的对象不相同,即地址不同,操作一个对象,另一个不会改变。
2)Java的clone()方法
package com.li;
public class Test4
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Student s1 = new Student("zhangsan", 12);
Student s2 = (Student) s1.clone();
s2.name="lisi";
s2.age=20;
System.out.println("name="+s1.name+","+"age="+s1.age);// name=zhangsan,age=12
}
}
class Student implements Cloneable
{
String name;
int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
@Override
protected Object clone()
{
Object o = null;
try
{
o = (Student)super.clone();
return o;
}
catch(Exception e)
{
e.printStackTrace();
}
return o;
}
}
①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。
package com.li;
public class Test4
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Professor p = new Professor("jiaoshou",50);
Student s1 = new Student("li", 20, p);
Student s2 = (Student) s1.clone();
s2.p.name = "jiaoshou2";
s2.p.age = 55;
//如果加了注释输出:name=jiaoshou2,age=55
System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
//如果不加注释输出:name=jiaoshou,age=50
}
}
class Professor implements Cloneable
{
String name;
int age;
public Professor(String name, int age)
{
this.name = name;
this.age = age;
}
/*
@Override
protected Object clone()
{
Professor o = null;
try
{
o = (Professor) super.clone();
}
catch (Exception e)
{
e.printStackTrace();
}
return o;
}*/
}
class Student implements Cloneable
{
String name;
int age;
Professor p;
public Student(String name, int age, Professor p)
{
this.name=name;
this.age=age;
this.p=p;
}
@Override
protected Object clone()
{
Student o = null;
try
{
o = (Student) super.clone();
}
catch (Exception e)
{
e.printStackTrace();
}
/*o.p = (Professor) p.clone();*/
return o;
}
}
2. boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
3. protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
C++析构函数和Java的finalize()方法不一样。前者是在对象消亡时运行,如果是自己new,即在堆中申请的内存,需要自己手动delete,所以析构函数中经常做一些文件保存之类的收尾工作;后者在Java中很不幸,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的,它最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。
4. Class getClass() 返回此 Object 的运行时类。
5. int hashCode() 返回该对象的哈希码值。
6. void notify() 唤醒在此对象监视器上等待的单个线程。
7. void notifyAll() 唤醒在此对象监视器上等待的所有线程。
8. String toString() 返回该对象的字符串表示。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
9. void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
10. void wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
11. void wait(long timeout, int nanos) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
//以纳秒为单位进行精确控制
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
五、Java的四种引用,强软弱虚,用到的场景。
1.强引用
以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强应用,那就类似必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,jvm宁愿跑出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
2.软引用(SoftReference)
如果一个对象具有软引用,类似与生活可有可无的生活用品。如果内存足,GC就不会回收,如果不足,GC就会回收。软引用可以用来实现内存敏感的高速缓存。软引用可以和一个引用队列联合使用,如果软引用所引用的对象被GC回收,JVM就会把这个软引用加入到与之关联的引用队列中。
3.弱引用(WeakReference)
如果一个对象具有软引用,类似与生活可有可无的生活用品。与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在GC线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存足够与否,都会回收它的内存。不过,由于GC是个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用可以和一个引用队列联合使用,如果弱引用所引用的对象被GC回收,JVM就会把这个弱引用加入到与之关联的引用队列中。
4.虚引用(PhantomReference)
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用以及弱引用的区别在于:虚引用必须和引用队列联合使用。当GC准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
package com.li;
import java.lang.ref.SoftReference;
//软引用实例代码
public class Test4
{
public static void main(String[] args)
{
A a = new A();
SoftReference<A> sr = new SoftReference<A>(a);
a = null;
if(sr != null)
{
a = sr.get();
}
else
{
a = new A();
sr = new SoftReference<A>(a);
}
}
}
class A{
int[] a ;
public A(){
a = new int[100000000];
}
}
六、Hashcode的作用。
- hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;
- 如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;
- 如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;
- 两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。
- 以下代码证明,先比较hash,如果hash相同比较equals。自己敲一遍,事半功倍。
package com.li;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class Test6
{
public static void main(String[] args)
{
Test6 a = new Test6();
a.SetI(1);
Test6 b = new Test6();
b.SetI(1);
Set<Test6> set = new HashSet<Test6>();
set.add(a);
System.out.println("----------");
set.add(b);
System.out.println("----------");
System.out.println(set.toString());//默认调用toString方法,toString()源码调用了hashCode()
/*输出
hashcode
----------
hashcode
equlas
----------
hashcode
[com.li.Test6@1]
*/
}
public int i;
public int getI()
{
return i;
}
public void SetI(int i)
{
this.i = i;
}
public int hashCode()
{
System.out.println("hashcode");
return i%10;
}
public boolean equals(Object object) {
System.out.println("equlas");
if (object == null) {
return false;
}
if (object == this) {
return true;
}
if (!(object instanceof Test6)) {
return false;
}
Test6 other = (Test6) object;
if (other.getI() == this.getI()) {
return true;
}
return false;
}
}
七、ArrayList、LinkedList、Vector的区别。
1.ArrayList
以下代码来自1.8Jdk的ArrayList.java源码
/**
* Default initial capacity.
* 默认数组初始容量大小为10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* The size of the ArrayList (the number of elements it contains).
* 数组里面实际元素的个数
* @serial
*/
private int size;
/**
* 最大容量
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 记录操作次数,快速失败机制,在迭代器中使用,remove抛出异常
*/
protected transient int modCount = 0;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!增加一个
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 实现自增的核心代码,1.5倍递增
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
2.Vector
以下代码来自1.8Jdk的Vector.java源码
/**
* 实现自增的核心代码,2.0倍递增
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
/**
* 主要区别,使用了synchronized修饰,线程安全
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
3.LinkedList
以下代码来自1.8Jdk的LinkedList.java源码
/**
* 私有内部类。用于链表操作
*/
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
总:
时间复杂度:ArrayList、Vector都为动态数组,LinkedList为链表。前者适合查找,后者适合修改删除。
空间复杂度:ArrayList开辟1.5倍、Vector开辟2.0倍,LinkedList每增加一个多一个内部类对象。前两者可以使用trimToSize()方法将多余的空间删除。
线程安全性:ArrayList、LinkedList不安全,但是可以自己实现线程安全。Vector线程安全。
八、String、StringBuffer与StringBuilder的区别。
String使用+""
会创建一个新的对象,StringBuffer是线程安全的,使用append在一个对象进行修改,StringBuilder是1.5之后出现的,和StringBuffer基本一样,只是它不是线程安全的。
九、Map、Set、List、Queue、Stack的特点与用法。
十、HashMap和HashTable的区别。
十一、HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
以下是Jdk1.8的HashMap.java源码
/**默认大小16
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**最大容量 <= 1<<30
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**默认装载因子
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
十二、 TreeMap、HashMap、LindedHashMap的区别。
十三、Collection包结构,与Collections的区别。
十四、try catch finally,try里有return,finally还执行么?
public class HelloJ {
public static void main(String[] args)
{
int i = g();
System.out.println(i);
/*输出
---
1
*/
}
static int g(){
int i = 0;
try{
return i++;
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("---");
return i++;
}
}
}
十五、Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
参考:http://www.mamicode.com/info-detail-1091344.html
十六、Java面向对象的三个特征与含义。