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

来源:互联网 发布:zepto.js 滑动 编辑:程序博客网 时间:2024/05/17 22:08

(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) 

(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;}

(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;    }
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;    }    }
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;    }}

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;    }

(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);}

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);}

上面提到的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;    }

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

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

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

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

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

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

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

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

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

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

线程池的创建:

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

参数的作用:
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

2 0