Java 核心类库---总结

Java 核心类库---总结

1. 数组(Array) 和列表(ArrayList) 有什么区别?

1.1、存储内容比较:

Array 数组可以包含基本类型和对象类型,
ArrayList 却只能包含对象类型。
Array 数组在存放的时候是(除object)是同种类型的元素。ArrayList 就不一定了 。

1.2、空间大小比较:

Array 数组的空间大小是固定的,所以需要事前确定合适的空间大小。
ArrayList 的空间是动态增长的,而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。

1.3、方法上的比较:

ArrayList 方法上比 Array 更多样化,比如添加全部 addAll()、删除全部 removeAll()、返回迭代器 iterator() 等。

适用场景:
如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里, 但是如果我们单纯只是想要以数组的形式保存数据,而不对数据进行增加等操作,只是方便我们进行查找的话,那么,我们就选择 ArrayList。
如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,那么,使用 ArrayList 就真的不是一个好的选择,因为它的效率很低,使用数组进行这样的动作就很麻烦,那么,我们可以考虑选择 LinkedList。

本部分参考自该作者(点击此处访问)

2. ArrayList 和 Vector 的区别

首先两个类都实现了List接口。他们都是有序不唯一的集合,说白了就是存储元素的位置是有序的(每一个元素都以一个对应的索引),相当于一个动态数组

ArrayList和Vector的区别,主要包括两个方面

2.1、同步性:

Vector是线程安全的,也就是说它的方法直线是线程同步的,而ArrayList是线程不安全的,它的方法之间是线程不同步的

如果只有一个线程去访问集合那么使用ArrayList,他不考虑线程安全的问题,所以效率会高一些

如果是多个线程去访问集合,那么使用Vector

2.2、数据增长性:

ArrayList和Vector集合都有一个初始容量的大小,当元素的个数超过存储容量是,就需要增加ArrayList和Vector的存储空间,每次增加不是

增加一个而是增加多个,Vector是增加原来的两倍,ArrayList没有明文规定,但是从源码中可以看出增长原来的1.5倍

ArrayList和Vector可以设置初始的存储空间的大小,Vector还以设置增长空间大小,而ArrayList不可以。

本部分参考自该作者(点击此处访问)

3. HashMap,TreeMap,HashTable 的区别?

3.1、HashMap的用法

HashMap实现了Map接口,继承AbstractMap,它是基于哈希表的 Map 接口的实现(保证键的唯一性),

以key-value的形式存在

HashMap是引用数据类型
通过 new 关键字在 Heap 堆中申请空间
保存其中元素的空间,按照hash码,预设好一个个的空间
这个空间就是 Hash Bucket(哈希桶)
每个桶有自己的Hash编号
一开始有少量的 Hash Bucket,
当程序试图将一个 key-value(Entry) 放入 HashMap 中时,
程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的Bucket位置,
如果该Bucket为空,直接存放入该Bucket;

如果该Bucket不为空,使用 equals 比较两个Entry 的 Key;
if(true){新 value 将覆盖 Entry 原 value,key 不变}
if(false){新 Entry 将与 Bucket中原 Entry 形成 Entry 链,
而且新 Entry 位于 Entry 链的头部}

Java 核心类库---总结

Map集合的遍历:

Map集合的遍历:
1、通过内部类Entry进行遍历
2、通过迭代器进行遍历,先获得Entry的Set集合
3、通过keySet方法获得键的Set集合,通过遍历键取值
4、通过map.values()获得所有值,但是不能获得键

3.2、Hashtable的用法

Hashtable:是Map接口的另外一个实现类,和HashMap用法类似,亦有区别

Hashtable出现于JDK1.0,HashTable基于Dictionary类
HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null

Hashtable的方法是同步的,而HashMap的方法不是同步的。

有人建议,涉及多线程使用时候,就使用Hashtable,没有涉及时候就用HashMap.但是在Collections中有一个静态方法

SynchronizedMap(),该方法创建了一个线程安全的Map对象,并且作为一个封装对象返回。所以通过Collections类中的

SynchronizedMap()的方法,我们是可以同步访问潜在的HashMap的。

Java 核心类库---总结

3.3、 treeMap用法

TreeMap:基于红黑树(Red-Black tree)的 NavigableMap实现。该映射根据其键的自然顺序进行排序,

或者根据创建映射时提供的 Comparator进行排序,具体取决于使用的构造方法。

TreeMap 是一个有序的key-value集合,它是通过红黑树实现的
TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合
TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法,比如返回有序的key集合
TreeMap 实现了Cloneable接口,意味着它能被克隆

TreeMap 实现了Java.io.Serializable接口,意味着它支持序列化

构造方法:

TreeMap支持排序:

3.3.1、TreeMap默认按键的自然顺序升序进行排序

Java 核心类库---总结

3.3.2、TreeMap按降序排列

Java 核心类库---总结

3.3.3、注意:在进行降序排序时,要在构造集合时候传递一个比较器

HashMap Hashtable treeMap的原理以及区别

1.这三个都对Map接口进行了实现

2.HashMap是不安全的线程,他允许Key值出现一次null Value值出现无数次的Null

3.Hashtable是安全的线程,他不仅实现了Map接口也实现了Dictionary接口,他的key值与Value值都不允许出现Null

4.treeMap是可以进行排序的,默认按照键的自然顺序进行升序排序,若要进行降序排序则需要在构造集合时候传递一个比较器

本部分参考自该作者(点击此处访问)

4.HashMap 的工作原理是什么?

可以参考下面两篇大能文章

10分钟拿下 HashMap

Java集合之一 — HashMap

5.什么是序列化,如何实现序列化?

可以参考下面文章

点击此处进入该文章

6.进程和线程有什么区别?

进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于:

简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

线程的划分尺度小于进程,使得多线程程序的并发性高。

另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

7.java 当中如何实现线程呢?

可以参考下我自己总结的

点击此处进入文章

8.说说线程的生命周期

1.线程的生命周期
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

(1)生命周期的五种状态

新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();

就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();

运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

自然终止:正常运行run()方法后终止

异常终止:调用stop()方法让一个线程终止运行

堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

正在等待:调用wait()方法。(调用motify()方法回到就绪状态)

被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)

2.常用方法

void run() 创建该类的子类时必须实现的方法

void start() 开启线程的方法

static void sleep(long t) 释放CPU的执行权,不释放锁

static void sleep(long millis,int nanos)

final void wait()释放CPU的执行权,释放锁

final void notify()

static void yied()可以对当前线程进行临时暂停(让线程将资源释放出来)

3.(1)结束线程原理:就是让run方法结束。而run方法中通常会定义循环结构,所以只要控制住循环即可

(2)方法----可以boolean标记的形式完成,只要在某一情况下将标记改变,让循环停止即可让线程结束

(3)public final void join()//让线程加入执行,执行某一线程join方法的线程会被冻结,等待某一线程执行结束,该线程才会恢复到可运行状态

  1. 临界资源:多个线程间共享的数据称为临界资源

(1)互斥锁

a.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

b.Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。

c.关键字synchronized用来与对象的互斥锁联系

d.当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。

本部分参考自该作者(点击此处访问)

9.多线程并发或线程安全问题如何解决?

想要解决线程并发安全问题,那首先要弄清楚什么是并发?

  • 线程的并发原理:
    我们先举一个例子,在你做数学题的时候能不能同时背课文,有些同学说可以一心二用啥的,咱就说正常人好吧!你会发现一个正常人是没有办法在做数学题的同时背课文的,如果你非要同时做这个两件事情,那么结果是什么样呢?我们来模拟一下:1)写个题目,背一句课文2)先做完数学题,再背语文课文。当然了,具体怎么做要看你的心情,并没有固定的方式。但是你会发现不可能出现一种情况就是在同一时刻写数学题并且背课文,问什么呢,因为你就一个大脑!
  • 就像你的大脑一样,它不能同时做两件不相关的事情。同样的,电脑的CPU也不能同时处理两个及以上的线程,如果有多个任务则多个任务是轮流占用CPU的,所有实际上多个线程并不是同时运行的,而每个线程都是走走停停的(就像你写一下题目,再看一下课文一样。当然我们说并发都是针对一个一个CPU而言的,现在的双核或四核CPU是可以同时处理多个任务的)。
  • 下面我们用代码来验证线程的并发性
class Two extends Thread{
    public void run(){
        for(int i=1;i<=50;i++){
            System.out.println(i);
        }
    }
}
public class TestThread{
        public static void main(String[] args) {
        //创建了t1线程
        Thread t1=new Two();
        //创建t2线程
        Thread t2=new Two();
        t1.start();
        t2.start();
    }
}

多次运行上述代码你会得到线程并发性的结果。

然而多个线程同时运行就会引发一些问题
咱们举个例子
创建一个卖票程序
3个线程并发运行

public class Demo4 {
    public static void main(String[] args) {
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    /**
     *   创建了 游乐园买票 线程
     */
    static  class  Ticket implements Runnable{

       private int cout = 10;//定义总票数
        @Override
        public void run() {
            while(cout>0){
                System.out.println("正在进行卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                cout--;

                System.out.println("出票成功"+"  票数剩余:"+cout);
            }
        }
    }
}

单看程序来说程序运行到票数为0时,程序应该停止运行
咱来看运行结果
Java 核心类库---总结

结果出现了 -1,这就是线程的的安全问题

下面时我自己总结的线程的知识点 可参考 六 解决线程的安全问题

线程的总结(点击此处进入该文章)

10.synchronized 和 ReentrantLock 的区别

可以参入下面两篇大能文章

java的两种同步方式, Synchronized与ReentrantLock的区别

ReentrantLock和Synchronized的区别和原理

至此,本文完成
如有总结错误的地方还请诸位朋友多多指教ovo

上一篇:算法题:统计一个字符串中各个字符出现的个数


下一篇:Java 集合深入理解 (十七) :TreeMap源码研究如何达到快速排序和高效查找