类加载器,List,map,set集合,线程
什么是类加载器
类加载器是一个用来加载类文件的类。Java源代码通过javac编译器编译成类文件。然后JVM来执行类文件中的字节码来执行程序。类加载器负责加载文件系统、网络或其他来源的类文件。有三种默认使用的类加载器:Bootstrap类加载器、Extension类加载器和System类加载器(或者叫作Application类加载器)。每种类加载器都有设定好从哪里加载类。
先说说数组Array和集合的区别:
(1)数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型)
(2)JAVA集合可以存储和操作数目不固定的一组数据。
(3)若程序时不知道究竟需要多少对象,需要在空间不足时自动扩增容量,则需要使用容器类库,array不适用。
FYI:使用相应的toArray()和Arrays.asList()方法可以相互转换。
一、集合
集合类存放于java.util包中。
集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对象的引用(reference)。
集合类型主要有3种:set(集)、list(列表)和map(映射)。
一、这三者什么关系呢
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
Collection接口
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个 Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。
如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); // 获得一个迭代子 while(it.hasNext()) { Object obj = it.next(); // 得到下一个元素 }
iterator接口:
由Collection接口派生的两个接口是List和Set。
2.Set
Set接口同样是Collection接口的一个子接口,它表示数学意义上的集合概念。Set中不包含重复的元素,即Set中不存两个这样的元素e1和e2,使得e1.equals(e2)为true。由于Set接口提供的数据结构是数学意义上集合概念的抽象,因此它需要支持对象的添加、删除,而不需提供随机访问。故Set接口与Collection的接口相同。
Set
接口继承Collection
接口,而且它不允许集合中存在重复项。所有原始方法都是现成的,没有引入新方法。具体的Set
实现类依赖添加的对象的equals()
方法来检查等同性。
HashSet: 使用HashMap的一个集的实现。虽然集定义成无序,但必须存在某种方法能相当高效地找到一个对象。使用一个HashMap对象实现集的存储和检索操作是在固定时间内实现的.
TreeSet: 在集中以升序对对象排序的集的实现。这意味着从一个TreeSet对象获得第一个迭代器将按升序提供对象。TreeSet类使用了一个TreeMap.
为优化 HashSet
空间的使用,您可以调优初始容量和负载因子。TreeSet
不包含调优选项,因为树总是平衡的,保证了插入、删除、查询的性能为log(n)
。
HashSet
和 TreeSet
都实现 Cloneable
接口。
当您要从集合中以有序的方式抽取元素时,TreeSet
实现会有用处。为了能顺利进行,添加到TreeSet
的元素必须是可排序的
List
List
接口继承了Collection
接口以定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。
实际上有两种List: 一种是基本的ArrayList,其优点在于随机访问元素,另一种是更强大的LinkedList,它并不是为快速随机访问设计的,而是具有一套更通用的方法。
List : 次序是List最重要的特点:它保证维护元素特定的顺序。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(这只推荐LinkedList使用。)一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和移除元素。 ArrayList : 由数组实现的List。允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和移除元素。因为那比LinkedList开销要大很多。
LinkedList : 对顺序访问进行了优化,向List中间插入与删除的开销并不大,随机访问则相对较慢。(使用ArrayList代替。)还具有下列方法:addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 这些方法 (没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。
Vector:实现一个类似数组一样的表,自动增加容量来容纳你所需的元素。使用下标存储和检索对象就象在一个标准的数组中一样。你也可以用一个迭代器从一个Vector中检索对象。Vector是唯一的同步容器类!!当两个或多个线程同时访问时也是性能良好的。
Stsck: 这个类从Vector派生而来,并且增加了方法实现栈!一种后进先出的存储结构。
面向位置的操作包括插入某个元素或 Collection
的功能,还包括获取、除去或更改元素的功能。在 List
中搜索元素可以从列表的头部或尾部开始,如果找到元素,还将报告元素所在的位置。
List和Set对比
Linked 改快读慢
Array 读快改慢
Hash 两都之间
Collection是集合接口
|————Set子接口:无序,不允许重复。
|————List子接口:有序,可以有重复元素。
区别:Collections是集合类
Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
Set和List具体子类:
Set
|————HashSet:以哈希表的形式存放元素,插入删除速度很快。
List
|————ArrayList:动态数组
|————LinkedList:链表、队列、堆栈。
Array和java.util.Vector
Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
Map
Map
接口不是Collection
接口的继承。而是从自己的用于维护键-值关联的接口层次结构入手。按定义,该接口描述了从不重复的键到值的映射。
我们可以把这个接口方法分成三组操作:改变、查询和提供可选视图。
改变操作允许您从映射中添加和除去键-值对。键和值都可以为null
。但是,您不能把Map
作为一个键或值添加给自身
Map.Entry 接口
Map
的entrySet()
方法返回一个实现Map.Entry
接口的对象集合。集合中每个对象都是底层Map
中一个特定的键-值对。
通过这个集合迭代,您可以获得每一条目的键或值并对值进行更改。但是,如果底层Map
在Map.Entry
接口的setValue()
方法外部被修改,此条目集就会变得无效,并导致迭代器行为未定义。
HashMap 类和 TreeMap 类
“集合框架”提供两种常规的Map
实现:HashMap
和TreeMap
。和所有的具体实现一样,使用哪种实现取决于您的特定需要。在Map
中插入、删除和定位元素,HashMap
是最好的选择。但如果您要按顺序遍历键,那么TreeMap
会更好。根据集合大小,先把元素添加到HashMap
,再把这种映射转换成一个用于有序键遍历的TreeMap
可能更快。使用HashMap
要求添加的键类明确定义了hashCode()
实现。有了TreeMap
实现,添加到映射的元素一定是可排序的。
为了优化HashMap
空间的使用,您可以调优初始容量和负载因子。这个TreeMap
没有调优选项,因为该树总处于平衡状态。
HashMap
和TreeMap
都实现Cloneable
接口。
Hashtable
类和Properties
类是Map
接口的历史实现。
HashTable: 实现一个映象,所有的键必须非空。为了能高效的工作,定义键的类必须实现hashcode()方法和equal()方法。这个类是前面java实现的一个继承,并且通常能在实现映象的其他类中更好的使用。
HashMap: 实现一个映象,允许存储空对象,而且允许键是空(由于键必须是唯一的,当然只能有一个)。
WeakHashMap: 实现这样一个映象:通常如果一个键对一个对象而言不再被引用,键/对象对将被舍弃。这与HashMap形成对照,映象中的键维持键/对象对的生命周期,尽管使用映象的程序不再有对键的引用,并且因此不能检索对象。
TreeMap: 实现这样一个映象,对象是按键升序排列的。
线程相关
什么是线程?什么是进程?
进程是运行着的一个应用程序,一个应用程序一旦运行就是一个进程,进程是分配cpu的最小单位。
线程是进程的一个实体,是进程的一条执行路经,线程是程序执行的最小单位。
线程和进程的区别?
- 进程是资源分配的最小单位,线程是程序运行的最小单位。
- 一个进程可以包含多个线程,但至少有一个线程,所有的线程共享进程的资源。
- 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。
④进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
创建线程的几种方式?
- 继承Thread类
- 实现Runnable接口的run方法
- 实现Callable接口
线程的优先级?
我们在公交车站乘坐公交车,如果有2人同时上车,只有一个座位,但是这个时候其中一个是孕妇,那自然是她优先坐了,这就是优先级的概念。在线程中,谁的优先级高,谁执行的次数就会提高。在代码中可以给线程设置优先级,支持的3个级别的优先级是1、5、10。
线程的生命周期?
线程一共有5种状态。
新建、就绪、运行、堵塞、死亡。
新建:当我们去新建了一个Thread类的实例的时候,该线程就进入了新建状态。此时,此时可以调用start方法进入就绪状态。
就绪:该状态下的线程会等待cpu分配资源,准备进入运行状态。
运行:线程获得cpu正在执行任务,除非此线程主动放弃cpu资源(yelid)或者有优先级更高的线程介入,否则线程将一直执行结束。
堵塞:由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
死亡:当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行run()方法后终止
异常终止:调用stop()方法让一个线程终止运行
什么是线程池?
什么是线程的同步和异步?
线程同步是多个线程同时访问同一资源,等待资源访问结束,浪费时间,效率低
线程异步:访问资源时在空闲等待时同时访问其他资源,实现多线程机制
什么是线程安全?
出现线程安全问题主要是由于多个线程同时访问共享资源,并且操作共享数据的代码有多条。
本地线程:ThreadLocal: