Collection
collection是单个集合保存的最大父亲接口,他与子接口的关系
List接口使用频率占集合的80%,List有两个重要的扩展方法:
E get(int index) 根据索引取得元素
E set(int index,E element)修改数据
ArrayList,LinkedList,Vector的区别:
ArrayList,Vector的底层由数组实现,链表由双链表实现的。ArrayList是非线程安全的,而Vector是线程安全的,故ArrayList的异步处理,效率更高,Vector同步处理,性能较低。
输出形式:
ArrayList的支持迭代器,ListIterator,foreach;
Vector支持迭代器,ListIterator,foreach,枚举。
设置实现的两个子类:HashSet的(无序存储),TreeSet的(有序存储)
需要注意的是:当我们使用TreeSet存放自定义的类时,该自定义类需要实现Comparable接口,否则会报错java.lang.ClassCastException :Serch.Person不能转换为java.lang.Comparable
import java.util.*;
class Person implements Comparable<Person>{
private String name;
private Integer age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
if(o.age<this.age) {
return 1;
}else if(o.age>this.age) {
return -1;
}else {
return this.name.compareTo(o.name);
}
}
}
public class Test{
public static void main(String[] args) {
Set<Person> set = new TreeSet<>();
set.add(new Person("A", 25));
set.add(new Person("B", 20));
Iterator<Person> iterator = set.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
HashSet判断重复元素并不是实现Comparable接口来完成的,而是使用hashCode()和equals()方法来实现,如果要想标识出对象的唯一性,一定需要equals()与hashCode()方法共同调用。即:只有当equals()与hashCode()都判断为相同时才可以判断这两个元素是重复的,将此消除。
哈希的作用好比分桶,比如我们给一堆数据通过取模3运算来分桶,那么1 4 7 10分在第一个桶,2 5 5 8分在第二个桶,3 6 9分在第三个桶,我们可以得出这样的结论,不同的元素可能分在一个桶(hash),即
a)equals不同,hashCode可能相同,
b)hashCode相同,equals不一定相同,
c)equals相同,hashCode一定相同(我们在第二个桶放了两个5,注意,相同的元素在Set里是会被消除的,我这里只是举个栗子)
集合的四中输出形式:Iterator、ListIterator、Enumeration、foreach。
1)Iterator
JDK1.5之前,在Collection接口中就定义有iterator()方法,通过此方法可以取得Iterator接口的实例化对象;而在JDK1.5之后,将此方法提升为Iterable接口中的方法。无论你如何提升,只要Collection有这个方法,那么List、Set也一定有此方法
使用方法如下:
Iterator<集合类型> iterator = 集合实例化对象.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
2)ListIterator(双向迭代接口)
他是Iterator的子接口,比Iterator多了可以从后向前迭代处理
1. 判断是否有上一个元素:public boolean hasPrevious();
2. 取得上一个元素: public E previous();
注意:要实现从前向后输出,应该先从前向后输出一次,否则无法实现。
3)foreach
与数组的使用方式一致:
for(对象类型 对象实例 : 集合实例){
Syso(对象实例);
}
4) Enumeration(不常用)
使用方式:
Vector<Person> vector = new Vector<>();
vector.add(new Person("A", 20));
vector.add(new Person("B", 20));
vector.add(new Person("C", 20));
vector.add(new Person("A", 20));
Enumeration<Person> enumeration = vector.elements();
while(enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
运行结果:
Map接口
Map<K key, V value>接口一次保存两对象,Map接口存储的对应关系,Key:Value;Map接口的常用子类有如下四个: HashMap、Hashtable、TreeMap、ConcurrentHashMap。
Map接口的常用方法:
特点:
在JDK1.8前,HashMap底层存储使用的是拉链法(数组+链表)JDK8后加入了红黑树。
Map的key用Set存放,故key不能重复。
允许空键和空值(但空键只有一个,且放在第一位)
默认初始容量:16
默认加载因子:0.75 结合时间和空间效率考虑得到的,若加载因子太大,引起冲突的可能增大;加载因子太小,频繁的进行扩容,且浪费空间。
扩容时:
新初始化哈希表时,容量为默认容量,阈值为 容量*加载因子。
已有哈希表扩容时,容量、阈值均翻倍。
JDK1.8后加入红黑树。为什么要加入红黑树?
Hash虽然尽可能提高了查询的效率,但也有可能存在一些极端的可能性,若大量数据存在同一个桶内,那么执行该链表也是需要大量的操作,在上述的讲解拉链法中,当链表的元素足够多时,JDK1.8为此加入了红黑树,我们知道,红黑树是一种比链表查询更高效的数据结构.JDK1 0.8默认链表节点达到8个时进行链表- >红黑树转化。
红黑树的三个关键参数:
TREEIFY_THRESHOLD (默认为8)
。当链表数量为8时进行转化
UNTREEIFY_THRESHOLD (默认为6)
当扩容时,桶内的元素进过再哈希可能会分到别的桶,桶中元素若原来为红黑树,当数量减少为6,则把红黑树还原为链表结构。
MIN_TREEIFY_CAPACITY (默认为64)
为了避免进行扩容,树形化还有一次判断机会,即,如果哈希表中的元素大于64,才进行扩容。
如下图(数据不做任何考证,只做参考)
HashMap中与哈希表的区别:
Properties(资源文件)
*.properties文件,在这种文件里面其内容的保存形式为"key =value",通过ResourceBundle类读取的时候只能读取内容,要想编辑其内容则需要通过Properties类来完成,这个类是专门做属性处理的。
Properties是Hashtable的子类:public class Properties extends Hashtable<Object,Object>
方法:
1. 设置属性 : public synchronized Object setProperty(String key, String value)
2. 取得属性 : public String getProperty(String key),如果没有指定的key则返回null
3. 取得属性 : public String getProperty(String key, String defaultValue),如果没有指定的key则返回默认值
支持IO方法:
1. 保存属性: public void store(OutputStream out, String comments) throws IOException
2. 读取属性: public synchronized void load(InputStream inStream) throws IOException
public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties properties = new Properties();
properties.setProperty("a", "This is A");
properties.setProperty("b", "This is B");
System.out.println(properties.getProperty("a"));
System.out.println(properties.getProperty("b","C"));
System.out.println(properties.getProperty("c","This is C"));//返回设置的形参,并不会给其赋值
System.out.println(properties.getProperty("c"));
File file = new File("C:\\Users\\Administrator\\Desktop\\test1.properties");
properties.store(new FileOutputStream(file), "testproperties");
}
}
public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties properties = new Properties();
// properties.setProperty("a", "This is A");
// properties.setProperty(“b”,“This is B”);
// System.out.println(properties.getProperty(“a”));
// System.out.println(properties.getProperty(“b”,“C”));
// System.out.println(properties.getProperty(“c”,“This is C”)); //返回设置的形参,并不会给它的赋值
// System.out.println(properties.getProperty(“c”));
File file = new File(“C:\\ Users \\ Administrator \\ Desktop \\ test1.properties”);
properties.load(new FileInputStream(file));
的System.out.println(properties.getProperty( “A”));
}
}