问题:
集合和数组的区别?
集合:
* 1:长度可以发生改变。
* 2:只能存储对象类型(引用类型)。
* 3:可以存储任意类型的对象。
* 数组:
* 1:长度固定。
* 2:可以存储基本类型,也可以存储对象类型。
* 3:只能存储同一种类型的元素。
* 由于数据结构不同,java对应的提供了多种集合。
* 但是,不管你是哪种集合,你都应该具备存储功能,获取功能,删除功能等功能。
* 把这些相似的功能进行提取,就最终形成了集合的继承体系结构。
* Collection接口:
Collection接口没有具体的实现:主要功能:
1:添加功能
boolean add(Object e):往集合中添加一个元素。
boolean addAll(Collection c):往集合中添加一个集合的元素。
2:删除功能
void clear():移除集合中的所有元素。
boolean remove(Object o):移除集合中指定的一个元素。
boolean removeAll(Collection c):移除集合中指定的一个集合的元素。
a.removeAll(b);删除a中存在的b元素
3:判断功能
boolean contains(Object o):判断集合中是否包含指定的元素。
boolean containsAll(Collection c):判断集合中是否包含指定的一个集合的元素。
boolean isEmpty():判断集合是否为空。
- 4:遍历功能
Iterator iterator() 迭代器。用于获取集合中的元素。`
5:长度功能
`int size():获取集合中元素的个数。`
- 6:移除功能
boolean retainAll(Collection c)
移除此collection 中未包含在指定 collection 中的所有元素。
保留相同的
如果此 collection 由于调用而发生更改,则返回 true
- 7:集合转数组
Object[] toArray():把集合转换为数组返回Object[]。
- Colletion接口的常用子接口:
1)List接口: - List接口的特有的方法:
List的特有功能:
A:添加功能
* void add(int index,Object element):在指定的位置添加元素。
//指定位置添加是防止出现越界的情况
* B:获取功能
* Object get(int index):根据给定的索引,获取元素。
* C:列表迭代器
* ListIterator listIterator()
* D:删除功能
* Object remove(int index):删除指定索引位置的元素,并返回该元素。
* E:修改功能
* Object set(int index,Object element):用指定的元素修改指定位置的元素,并把修改前的元素返回。
- List的三个儿子:
ArrayList: 底层数据结构是数组。查询快。增删慢 。线程不安全。效率高
Vector (用的非常少 ): 底层数据结构是数组。查询快。增删慢 。线程安全。效率低
LinkedList: 底层数据结构是链表。查询慢。增删快 。线程不安全。效率高
查询多:用ArrayList 增删多:用LinkedList
LinkedList的特有功能:
A:添加元素
* public void addFirst(Object e)
* public void addLast(Object e)
* B:删除元素
* public Object removeFirst()
* public Object removeLast()
* C:获取元素
* public Object getFirst()
* public Object getLast()
*用LinkedList模拟栈数据结构的集合:(先进后出,后进先出)
public class MyStack {
private LinkedList link;
public MyStack() {
link = new LinkedList();
}
public void add(Object obj) {
link.addFirst(obj);
}
public Object get() {
// return link.getFirst();
return link .removeFirst();
}
public boolean isEmpty() {
return link .isEmpty();
}
}
2)Set接口:
Set接口的实现:
A.HashSet:
//创建HashSet集合对象
HashSet<String> hs = new HashSet<String>();
//将元素写入HashSet对象
hs.add( "hello");
hs.add( "world");
hs.add( "java");
hs.add( "hello");
hs.add( "java");
//遍历元素
Iterator it = hs.iterator();
while(it .hasNext()){
System. out.println(it .next());
//输出 hello world java
}
我们发现HashSet不能保存重复的String元素,那么问题来了。HashSet是如何保证元素的的唯一性的呢?
我们来试一试用HashSet保存自定义对象,是否能做到元素唯一呢?ps:如果两个自定义对象的成员变量全部相同。则我们说明它们是同一个对象。
//创建HashSet集合对象
HashSet<Student> hs = new HashSet<Student>();
//创建Student类的实例
Student s1 = new Student("hello" ,23);
Student s2 = new Student("world" ,21);
Student s3 = new Student("java" ,13);
Student s4 = new Student("hello" ,23);
//将Student元素写入HashSet对象
hs.add( s1);
hs.add( s2);
hs.add( s3);
hs.add( s4);
//遍历元素
for(Student s : hs ){
System. out.println(s );
//我们发现 相同的 s1和s4都被写入到集合中
}
如果两个自定义对象的成员变量全部相同,它们不一定是一个对象。只不过我们的需求是要去成员变量全部相同的就是同一个对象。。。于是,我们重写object类的equals()方法
但结果是,我们重写了equals()方法后却发现并没有去掉重复的元素.
结论:HashSet的底层其实是HashMap.
HashSet集合的底层数据结构是哈希表。
哈希表结构是一个元素是链表的数组。存储的时候是以对象哈希值为数组索引进行存储的
* 哈哈希表的存储依赖两个方法:
* hashCode()和equals()。
* 执行顺序:
* 首先判断对象的哈希值是否相同,
* 如果相同,就继续执行equals()方法。
* 如果equals()方法返回true,说明元素重复了。新添加的value覆盖掉原来的value。返回原来的value。。。key不变
* 如果equals()方法返回false,说明元素没有重复的,就添加到集合中,但与此元素位于同一个bucket中。形成Entry链,最早放入在bucket中的Entry则位于其Entry链的最底层。遍历的时候遍历这个Entry链,位于最底层的最后被找到
* 如果不同,就直接添加到集合中。
*
* 以后你看到HashXxx结构的集合,要知道,这种结构底层是哈希表。(是一个元素是链表的数组)
* 它依赖hashCode()和equals()方法。
* 自动生成即可。
* TreeSet:
无序,唯一。但它可以按照某些规则进行排序。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,
* 具体取决于使用的构造方法。
*
* 无参构造方法,默认采用的是自然排序。
TreeSet如何保证元素的唯一性和排序的呢???
默认情况下,要想实现自然排序,元素所属的类(String已经实现了)就必须实现Comparable接口。(注意:Comparable接口后面的泛型要写入要比较的对象类型,默认的是Object)
Comparable的方法 compareTo(Student o)
{String的compareTo方法compareTo()的返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的
差值,如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至比较的字符或被比较的字符有一方 全比较完,这时就比较字符的长度. }
唯一:根据次方法的返回值是否是0来决定。如果返回值是0,说明元素重复,就不再添加元素。
排序:
* 正:说明数据大,往后放。
* 0:说明重复。不添加。
* 负:说明数据小,往前放。
TreeSet采用无参构造时,就要让ThreeSet保存的对象继承Compareable并实现下面的方法
public int compareTo(Student o) {
int num1 =this.age - o.age;
int num2 = num1==0?this .name .compareTo(o.name):num1;
return num2 ;
}
当使用TreeSet的另一个构造方法时public TreeSet(Comparator comparator)
自己定义一个类实现Comparator接口。此时其中的 compare方法的参数是两个,其他的与comparable的compareTo一模一样
Set小结:
* |–HashSet 无序,唯一。
* |–LinkedHashSet 有序,唯一。
* 底层数据结构是链表和哈希表组成。
* 由链表保证元素有序。
* 由哈希表保证元素唯一。
* Map集合:
Map和Collection集合的区别?
* Map:
* a:存储的是键值对元素。
* b:键是唯一的。
* c:值是可重复的。
* Collection:
* a:存储的是单个的元素。
* b:Collection的儿子Set集合是唯一的。
* c:Collection的儿子List集合可以重复。
Map集合的数据结构和Set集合是一致的。
但是,这种数据结构只针对Map集合的键有效,跟值无关。
Map集合的主要功能:
Map集合的功能:
*
A:添加功能
* V put(K key,V value):如果键不存在,就是添加功能。如果键存在,就是修改功能。返 回的是被修改前的值。
* B:删除功能
* void clear():清空集合中的所有键值对元素。
* V remove(Object key):根据键删除键值对元素,并把值返回。
* C:判断功能
* boolean containsKey(Object key):判断集合中是否包含指定的键。
* boolean containsValue(Object value):判断集合中是否包含指定的值。
* boolean isEmpty():判断集合是否为空。
* D:获取功能
* Set<Map.Entry<K,V>> entrySet():???
* V get(Object key):根据键去集合中获取值。
* Set<K> keySet():返回的是集合中所有键的元素。
* Collection<V> values():返回的是集合中所有值的元素。
* E:长度功能
* int size():集合中的键值对元素的对数。
HashMap 与 TreeMap
HashMap遍历元素:
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(4, "d");
map.put(5, "e");
//遍历获取所有的值,使用 values()方法 返回Collection类型
Collection<String> col = map.values();
for(String s : col ){
System. out.println(s );
}
//遍历获取所有的健,使用 keySet()方法 返回Set类型
Set<Integer> set = map.keySet();
for(Integer s : set ){
System. out.println(s );
}
最终版的遍历:
Set<Integer> set = map.keySet();
for(Integer s : set ){
String value = map.get( s);
System. out.println(s +"--" +value );
}
TreeMap :
注意TreeMap保持的元素是有序的。注意健的类型要实现Comparable接口。或者参数传递Comparator的子类。
TreeMap的特殊遍历
map.put("as1" ,1);
map.put( "cs2",2);
map.put( "es3",3);
map.put( "bs4",4);
map.put( "ds5",5);
//Set<Map.Entry<K,V>> entrySet()
Set<Map.Entry<String, Integer>> set = map.entrySet();
for(Map.Entry<String, Integer> me : set){
System. out.println(me .getValue()+"--"+ me.getKey());
}
Hashtable与HashMap:
Hashtable:是Map接口的一个具体实现类。JDK1.0出现的。1.2之后改进为实现Map接口。
* HashMap是用来替换Hashtable。
* 问题:HashMap和Hashtable的区别?
* A:HashMap 线程不安全,效率高。允许null键和null值。
* B:Hashtable 线程安全, 效率低。不允许null键和null值。