学如逆水行舟,不进则退。——《增广贤文》
一、集合简介
这2天主要学了这两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。
集合框架体系如图所示:
接口: 是代表集合的抽象数据类型。
具体类: 是集合接口的具体实现。
算法: 是实现集合接口的对象里的方法执行的一些有用的计算。
之前已经简单了解过数组,那么数组和集合的区别在哪呢?
二、常用集合的分类
尽管 Map 不是集合,但是它们完全整合在集合中。
常用集合接口和具体类图:
-
Collection接口:
-
List接口: 有序,可重复,能存放null值
- ArrayList: 底层是数组,查询和修改比较快,线程不安全
- LinkedList: 底层是双向链表,增加和删除比较快,线程不安全
- Vector: 底层是数组,查询和修改比较快,线程安全(同步),但是效率低
- Stack: 栈模型先进后出
-
Set接口:
-
HashSet: 底层是哈希表,无序,不重复,能存放null
判断元素重复的方式:
1.判断hashcode值是否相同
2.如果相同,判断equals方法重写这两个方法时,尽量保证每个对象都有不同的hashcode值,这样会提高效率
-
TreeSet: 底层数据结构是红黑树,有序,不重复,元素类型要兼容,不能存放null
数据按照自然顺序排放(自然顺序:字母按字典,数字按大小,汉字自己顺序)类:必须实现comparable接口或者自定义个comparator比较器
判断元素重复的方式:比较返回值是否为0
-
-
-
Map接口: 以键对值来存放 key-value
- HashMap: 键和值都可以为null,效率高
- HashTable: 键和值都不可以为null,线程安全(方法同步)
- TreeMap: 键不能为null,值可以为null,按照键的自然顺序存放,而且需要类型兼容
三、实现方法
建议学习一定要看:JDK1.8中文手册(提取码:rqpr)
详细如图:
这里简单列举一些ArrayList类的增删改查的方法:
-
增加
add(E e):将指定的元素追加到此列表的末尾
add(int index, E e):在此列表中的指定位置插入指定的元素 -
删除
remove(int index):删除该列表中指定位置的元素
remove(Object o):删除指定元素的第一个出现(如果存在或存在多个)
clear() :从列表中删除所有元素 -
修改
set(int index, E element):用指定的元素替换此列表中指定位置的元素 -
查询
get(int index) :返回此列表中指定位置的元素
size() :返回此列表中的元素数
subList(int fromIndex, int toIndex) :返回此列表中指定的 fromIndex (包括)和 toIndex之间的独占视图
toArray() :以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组
3种遍历方法:
之前只学习了第一个简单的for循环,现在又学到了2种。
-
1:for循环
for(int i=0;i<a.size();i++){
System.out.println(a.get(i));
} -
2:增强型for循环
for (Object o:a) {
System.out.println(o);
} -
3:迭代器
Iterator i=a.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架。
迭代器可以遍历集合框架,而且你能够通过循环来得到或删除集合的元素。
四、实现类实践代码
1.ArrayList
实践代码,搓搓小手动起来(=!=):
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList a = new ArrayList();
//增加
a.add(1);
a.add(null);
a.add("hello");
a.add(true);
a.add('a');
a.add(1.2);
a.add(0,2);//在索引0的位置存放2,之前的数据后移
//遍历1:for循环
//a.size():长度;a.get(X):获取索引所对应元素
for(int i=0;i<a.size();i++){
System.out.println(a.get(i));
}
/*
//遍历2:增强型for循环
for (Object o:a) {
System.out.println(o);
}
//遍历3:迭代器
Iterator i=a.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
*/
//删除
a.remove(new Integer(1));
a.remove(new Integer(2));
a.remove(new Character('a'));
a.remove("hello");
// a.clear();//删除索引元素
//修改
a.set(0,33);
//查询
System.out.println(a.get(1));//true
System.out.println(a.size());//3
System.out.println(a.subList(0,3));//[33, true, 1.2]
System.out.println(a.toArray());//[Ljava.lang.Object;@1b6d3586
for (Object o:a.toArray()) {
System.out.println(o);
}
}
}
2.LinkedList
实践代码,搓搓小手动起来(=!=):
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList l=new LinkedList();
//与ArrayList方法大致相同,只是多了个头尾操作
l.add("ad");
l.add(null);
l.add(null);
l.add(null);
System.out.println(l.get(3));//null
System.out.println(l.size());//4
System.out.println(l.getFirst());//ad
}
}
3.Vector
实践代码,搓搓小手动起来(=!=):
import java.util.Vector;
public class VectorTest {
public static void main(String[] args) {
//与ArrayList大致相同,
//Vector 是线程安全的,ArrayList是线程不安全的
Vector v1=new Vector();
}
}
4.Stack
实践代码,搓搓小手动起来(=!=):
import java.util.Stack;
public class StackTest {
public static void main(String[] args) {
Stack s=new Stack();
//入栈
s.push("sss");
s.push(null);
s.push(15);
s.push("sas");
//遍历
for(Object o:s){
System.out.println(o);
}
System.out.println(s.search(null));//查看对象在栈中的位置
Object o=s.pop();//删除此栈顶部的对象,并将该对象作为此函数的值返回
System.out.println(o);
System.out.println(s.peek());//查看栈顶元素
}
}
5.HashSet
实践代码,搓搓小手动起来(=!=):
import java.util.HashSet;
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("a");
hs.add(null);
hs.add(true);
hs.add(1);
System.out.println(hs.size());//4
//hashset判断 元素重复的方式:
//1.比较两个元素的hashcode值
//2.如果相同,再比较equals方法
//3.如果相同,代表两个元素是相同的
Integer a = new Integer(5);
Integer b = new Integer(5);
System.out.println(a.hashCode());//5
System.out.println(b.hashCode());//5
System.out.println(a.equals(b));//true
hs.add(a);
hs.add(b);
//只增加了一个值为5的元素(HashSet元素有唯一性)
for (Object o:hs) {
System.out.println(o);
//null a 1 5 true
}
}
}
6.TreeSet
实践代码,搓搓小手动起来(=!=):
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
//创建集合的元素类型为Integer的集合a,并赋值
ArrayList<Integer> a = new ArrayList<Integer>();
a.add(0,0);
a.add(1,1);
a.add(2,2);
a.add(3,2);
a.add(4,3);
//自定义比较器
Comparator com=new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer a = (Integer) o1;
Integer b = (Integer) o2;
return a-b;
}
};
TreeSet ts = new TreeSet(com);
//把a中的元素遍历进ts中
Iterator i=a.iterator();
while (i.hasNext()) {
ts.add(i.next());
}
System.out.println(ts);//[0, 1, 2, 3]
}
}
7.HashMap
实践代码,搓搓小手动起来(=!=):
import java.util.Map.Entry;
import java.util.HashMap;
import java.util.Set;
public class HashMapTest {
public static void main(String[] args) {
HashMap hm = new HashMap();
hm.put(1,"张三");
hm.put(2,"李四");
hm.put(3,"王五");
hm.put(4,"王五");
System.out.println(hm);
//根据键获取值
System.out.println(hm.get(1));
//hm的长度
System.out.println(hm.size());
//获得全部的key
System.out.println(hm.keySet());
//获取全部的values
System.out.println(hm.values());
//全部键值对
System.out.println(hm.entrySet());
//遍历
Set s1 = hm.entrySet();//键不重复
for (Object o:s1) {
System.out.println(o);
}
//将键值对封装成一个接口
Set s2=hm.entrySet();
for(Object o:s2) {
Entry e=(Entry)o;
System.out.println(e.getKey()+" "+e.getValue());
}
}
}
8.HashTable
实践代码,搓搓小手动起来(=!=):
import java.util.Hashtable;
public class HashTableTest {
public static void main(String[] args) {
//与hashmap的区别:hashtable 是线程安全的
//键值都不能为null
Hashtable ht=new Hashtable();
ht.put("ss", null);
//空指针异常
System.out.println(ht.size());//java.lang.NullPointerException
}
}
9.TreeMap
实践代码,搓搓小手动起来(=!=):
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
//TreeMap中,元素按照键的自然顺序,而且需要 类型兼容
//当键为类时,那个类需要实现Comparable接口或者自定义比较器
//TreeMap 键不能为null 值可以 为null
TreeMap tm=new TreeMap();
tm.put("sss", "ss");
tm.put("sa", 10);
tm.put("s", null);
System.out.println(tm.size());//3
}
}
collections类:提供了对集合进行排序、遍历等多种算法实现
public class Student {
int age;
String name;
public Student(int age,String name) {
this.age=age;
this.name = name;
}
//重写toString方法
public String toString (){
return name+" "+age;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test {
public static void main(String[] args) {
//排序:指定比较器来排序,元素必须是类型兼容
//Arrays.sort()是给数组排序的
List l = new ArrayList();
l.add(new Student(10,"张三"));
l.add(new Student(5,"里斯"));
l.add(new Student(12,"王五"));
l.add(new Student(4,"蒋"));
for(Object o:l) {
System.out.println(o);
}
//比较器
Comparator c=new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Student s1=(Student)o1;
Student s2=(Student)o2;
return s1.age-s2.age;
}
};
Collections.sort(l,c);
for(Object o:l) {
System.out.println(o);
}
}
}
最后简单说一下泛型:
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
比如:ArrayList< integer > list = new ArrayList< integer > ();
有许多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类。
参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
好处:代码安全性,消除强制类型转换
今天学习分享的内容到此为止了,本是想要激励自己学下去,但发现快乐更是知识在于分享!
作为初学者对于Java的理解实在浅薄,如有错误请指正,万分感谢!