Java基础知识和常用数据结构整理与分析

来源:互联网 发布:淘宝茵曼旗舰店 编辑:程序博客网 时间:2024/06/07 14:14

转载地址:http://blog.csdn.net/chenbaige/article/details/57107337

(1)Object有哪些公用方法

protected Object clone()private native Object internalClone()public boolean equals(Object o)protected void finalize()public final Class<?> getClass()public int hashCode()public final native void notify()public final native void notifyAll()public String toString()public final native void wait() public final void wait(long millis)public final native void wait(long millis, int nanos) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(2)Switch能否用string做参数?

在Java 7之前switch支持byte,short,int ,char,enum,在JAVA7之后加入了对string的支持

(3)equals与==的区别

‘==’:obj1==obj2:如果obj是基本数据类型,比较的obj的栈内存空间存储的值都存储在常量池中。所以就是单纯比较两个值是否相等。如果obj是引用类型,obj的栈内存区域存储的是对象在堆中的实例地址,所以只有是同一个对象两个值才会相等。

‘equals’:如果objec的equals方法没有被重写,在equals内部调用的是==去比较两个对象是否相等。如integer,string,date,boolean都重写了equals方法

object类的equals方法如下:

public boolean equals(Object o) {    return this == o;}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

(4)Hashcode的作用

1.用于查找的快捷性,如hashtable,hashmap—hashcode()方法用于在散列存储结构中确定对象存储地址

2.如果两个对象相同,适用于equals方法,那么两个对象的hashcode值一定相同

3.如果equals方法被重写,尽量也重写hashcode方法

4.hashcode值相同,不一定表示两个对象一定相同,可能equals方法不适应。只能说明在散列结构(hashtable)中存放在数组的同一个位置,链表节点不同(根据equals判断)

(5)ArrayList、LinkedList、Vector的区别

ArrayList:内部用数组的方式存储数据,数组的初始容量为10,当需要扩容时,新容量增加源容量的0.5倍(int newCapacity = (oldCapacity * 3)/2 + 1; 1.5倍 )。添加数据的时候涉及到内存的移动,查找的时候直接根据索引查找,所以添加慢查找快。适合存储写入少读取多的数据非线程安全

LinkedList:内部以双向链表的方式存储数据,添加数据的时候只需记录当前节点的左右节点,查询数据的时候需要遍历链表,所以添加数据快查找慢

Vector:存储结构和arraylist相同。初始容量为10,不同的是扩容的时候每次增加原油容量的1倍线程安全

(6)String、StringBuffer与StringBuilder的区别

string被定义为final(不可变),即每次对string修改都会新创建一个string变量,原来的会被gc回收

StringBuffer和StringBuilder是可变的,每次修改都是在一个对象上,所以多次修改更节省空间,stringbuffer是线程安全的

三者在执行速度方面:StringBuilder>StringBuffer>String

(7)Map、Set、List、Queue、Stack的特点与用法 
map:map是以键值对的方式 存储数据,键不能重复,一个键对应一个值,值可以重复。hashmap内部结构采用数组+链表的方式对数据进行存储。存储时:先对键计算hashcode值,在对数组大小取余,确定在数组中存储的位置,如果hashcode值相同,则在数组中以链表的形式存储。空key的数据存储在数组的第一个位置。 
set:可以方便地将需要的类型以集合类型保存在一个变量中.主要应用在显示列表.Set是一个不包含重复元素的 collection。更确切地讲, 
set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。 hashset内部存储结构:transient HashMap

   private static class HashtableEntry<K, V> implements Entry<K, V> {    final K key;    V value;    final int hash;    HashtableEntry<K, V> next;    HashtableEntry(K key, V value, int hash, HashtableEntry<K, V> next) {        this.key = key;        this.value = value;        this.hash = hash;        this.next = next;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
hashtable是线程安全的。继承自Dictionary。hashmap实现Cloneable和Serializable接口。

(9)HashMap和ConcurrentHashMap的区别,HashMap的底层源码 
hashmap源码:

    transient HashMapEntry<K, V>[] table;//存储数组    //数组内存储类型结构    static class HashMapEntry<K, V> implements Entry<K, V> {    final K key;    V value;    final int hash;    HashMapEntry<K, V> next;    HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {        this.key = key;        this.value = value;        this.hash = hash;        this.next = next;    }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
hashtable谁先线程安全时,是锁住整个整个结构,每次只能一个线程进入取操作结构数据。ConcurrentHashMap就是解决了hashtable的效率问题,写入数据时每次只锁住要操作的那一个桶(数组中操作的那个单元),这样就可以同时16(默认数组大小)个线程对结构数据进行操作,显著提升了效率。当读取时没有用到锁,完全并发的操作。在求size的时候会锁住整个结构。在进行数据迭代时,集合再发生改变不会抛出异常取而代之的是在改变时new新的数据从而不影响原有的数据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键  

(10)TreeMap、HashMap、LindedHashMap的区别 
LinkedHashMap设计思想:采用双向链表存储数据。

 transient LinkedEntry<K, V> header;static class LinkedEntry<K, V> extends HashMapEntry<K, V> {    LinkedEntry<K, V> nxt;    LinkedEntry<K, V> prv;    /** Create the header entry */    LinkedEntry() {        super(null, null, 0, null);        nxt = prv = this;    }    /** Create a normal entry */    LinkedEntry(K key, V value, int hash, HashMapEntry<K, V> next,                LinkedEntry<K, V> nxt, LinkedEntry<K, V> prv) {        super(key, value, hash, next);        this.nxt = nxt;        this.prv = prv;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

treemap设计思想:

Node<K, V> root;static class Node<K, V> implements Map.Entry<K, V> {    Node<K, V> parent;    Node<K, V> left;    Node<K, V> right;    final K key;    V value;    int height;    Node(Node<K, V> parent, K key) {        this.parent = parent;        this.key = key;        this.height = 1;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

(11)Collection包结构,与Collections的区别 
collection是集合的上级接口(存放单值),它的自接口包括set,list. 
collections是集合的帮助类,提供操作集合的工具方法。

(12)try catch finally,try里有return,finally还执行么? 
先执行try里面的语句,如果try代码块中有return,先计算出return后代码块的值,完成后将这个值保存在内存中。如果try代码块出现异常,则进入catch中。最后都会进入finally结构中。 
先执行完finally中语句才会执行try中的return语句,计算完return的值之后,无论在什么地方修改了参数的值,retnrn需要返回的值都是确定的,在执行finally前就已经确定了,不会改变。

(13)Override和Overload的含义去区别。

Override 特点 
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果; 
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致; 
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类; 
4、方法被定义为final不能被重写。 
5、对于继承来说,如果某一方法在父类中是访问权限是private,那么就不能在子类对其进行重写覆盖,如果定义的话,也只是定义了一个新方法,而不会达到重写覆盖的效果。(通常存在于父类和子类之间。)

Overload 特点 
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int)); 
2、不能通过访问权限、返回类型、抛出的异常进行重载; 
3、方法的异常类型和数目不会对重载造成影响; 
4、重载事件通常发生在同一个类中,不同方法之间的现象。 
5、存在于同一类中,但是只有虚方法和抽象方法才能被覆写。

(14)Interface与abstract类的区别 
1.abstract class 在Java中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。 
2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的方法都是public abstract的。 
3.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。接口中定义的变量默认是public static final 型,且必须给其赋初值,所以实现类中不能重新定义,也不能改变其值。 
4.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是”is-a”关系,interface表示的是”like-a”关系。 
5.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法

(15)ThreadLocal的设计理念与作用 
Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。

threadlocal的set方法:

public void set(T value) {    Thread currentThread = Thread.currentThread();    Values values = values(currentThread);    if (values == null) {        values = initializeValues(currentThread);    }    values.put(this, value);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

threadlocal的get方法:

public T get() {// Optimized for the fast path.Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values != null) {Object[] table = values.table;int index = hash & values.mask;if (this.reference == table[index]) {return (T) table[index + 1];}} else {values = initializeValues(currentThread);}return (T) values.getAfterMiss(this);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上面提到的values是创建在threadlocal中的values实例,其结构如下:

static class Values {    /**     * Size must always be a power of 2.     */    private static final int INITIAL_SIZE = 16;    /**     * Placeholder for deleted entries.     */    private static final Object TOMBSTONE = new Object();    /**     * Map entries. Contains alternating keys (ThreadLocal) and values.     * The length is always a power of 2.     */    private Object[] table;    /** Used to turn hashes into indices. */    private int mask;    /** Number of live entries. */    private int size;    /** Number of tombstones. */    private int tombstones;    /** Maximum number of live entries and tombstones. */    private int maximumLoad;    /** Points to the next cell to clean up. */    private int clean;    /**     * Constructs a new, empty instance.     */    Values() {        initializeTable(INITIAL_SIZE);        this.size = 0;        this.tombstones = 0;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

实际上threadlocal 存储数据就是将数据添加到一个指定好的数组(Object[] table;)上。每个线程都有一个localvalues对象实例,用于存储数据。 
values存储数据的put方法核心代码:

void put(ThreadLocal<?> key, Object value) table[index] = key.reference;//threadlocal的引用table[index + 1] = value;
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

前一个是存放key的引用,后一个存储值(一定是成双出现的)。

set完整逻辑: 
->实例化threadlocal对象实例(调用set方法) 
->获取到当前线程的threadlocal的localValues对象实例(即Values实例) 
->向values中写入数据

values.put(this, value);void put(ThreadLocal<?> key, Object value)
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

->左后将数据保存到数组中

table[index] = key.reference;table[index + 1] = value;
  • 1
  • 2
  • 1
  • 2

(16)Static class 与non static class的区别 
内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

很形象的例子:Static class 与non static class的区别的案例

(17)ThreadPool用法与优势 
线程池:合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

线程池的创建:

ThreadPoolExecutor executor =new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
  • 1
  • 1

参数的作用: 
corePoolSize:线程池的基本大小,有任务来时就创建新线程,当到达这个容量时,就不再创建新线程,如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。maximumPoolSize:程池允许创建的最大线程数 
keepAliveTime:线程池的工作线程空闲后,保持存活的时间。 
unit:线程活动保持时间的单位 
workQueue:用于保存等待执行的任务的阻塞队列,有一下几种类型: 
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。 
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。 
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。 
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

(18)wait()和sleep()的区别 
1.wait方法是object类中的方法,使用object方法时会释放对象资源锁。进入等待被唤醒的线程池,需要notify方法区唤醒,才会继续执行。 
2.sleep方法是thread类的方法,使用时不会释放资源锁,会让出cpu给其它线程,睡眠时间到达后自动恢复运行状态。

(19)foreach与正常for循环效率对比 
•for循环中的循环条件中的变量只求一次值!如for (int i = 0; i < names.length; i++),names.length只求一次,如果在遍历期间数组发 生改变,会出现问题。 
•foreach语句是java5新增,在遍历数组、集合的时候,foreach拥有不错的性能。 
•foreach是for语句的简化,但是foreach并不能替代for循环。可以这么说,任何foreach都能改写为for循环,但是反之则行不通。 
•foreach不是java中的关键字。foreach的循环对象一般是一个集合,List、ArrayList、LinkedList、Vector、数组等。

(20)java IO与NIO 
Java IO与NIO

(21)反射的作用于原理 
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法; 
在运行时调用任意一个对象的方法;生成动态代理。

(22)泛型常用特点,List能否转为List

范型即是参数化类型,有如下优点:提高 Java 程序的类型安全、消除强制类型转换、潜在的性能收益 
Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。 
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 
3、泛型的类型参数可以有多个。 
4、泛型的参数类型可以使用extends语句,例如。习惯上成为“有界类型”。 
5、泛型的参数类型还可以是通配符类型。例如Class

原创粉丝点击