------- android培训、java培训、期待与您交流! ----------
集合类的由来: 对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定。就使用集合容器进行存储。
集合特点:
1,用于存储对象的容器。
2,集合的长度是可变的。
3,集合中不可以存储基本数据类型值。
集合容器因为内部的数据结构不同,有多种具体容器。不断的向上抽取,就形成了集合框架。
框架的顶层Collection接口:
Collection的常见方法:
1,添加。
boolean add(Object obj):
boolean addAll(Collection coll):
2,删除。
boolean remove(object obj):
boolean removeAll(Collection coll);
void clear();
3,判断:
boolean contains(object obj):
boolean containsAll(Colllection coll);
boolean isEmpty():判断集合中是否有元素。
4,获取:
int size():
Iteratoriterator():取出元素的方式:迭代器。 该对象必须依赖于具体容器,因为每一个容器的数据结构都不同。 所以该迭代器对象是在容器中进行内部实现的。
对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可, 也就是iterator方法。
Iterator接口就是对所有的Collection容器进行元素取出的公共接口。
5,其他:
boolean retainAll(Collection coll);取交集。
Object[] toArray():将集合转成数组。
List:有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复。
List:特有的常见方法:有一个共性特点就是都可以操作角标。
1,添加
void add(index,element);
void add(index,collection);
2,删除;
Object remove(index):
3,修改:
Object set(index,element);
4,获取:
Object get(index);
int indexOf(object);
int lastIndexOf(object);ListsubList(from,to);
list集合是可以完成对元素的增删改查。
List:
|--Vector:内部是数组数据结构,是同步的。增删,查询都很慢!
|--ArrayList:内部是数组数据结构,是不同步的。替代了Vector。查询的速度快。
|--LinkedList:内部是链表数据结构,是不同步的。增删元素的速度很快。
LinkedList:
addFirst();addLast():
jdk1.6 offerFirst(); offetLast();
getFirst();.//获取但不移除,如果链表为空,抛出NoSuchElementException. getLast();
jdk1.6 peekFirst();//获取但不移除,如果链表为空,返回null.peekLast():
removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException. removeLast();
jdk1.6 pollFirst();//获取并移除,如果链表为空,返回null. pollLast();
Set:元素不可以重复,是无序。
Set接口中的方法和Collection一致。
HashSet: 内部数据结构是哈希表 ,是不同步的。
如何保证该集合的元素唯一性呢?
是通过对象的hashCode和equals方法来完成对象唯一性的。如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。 如果对象的hashCode值相
同,那么要再次判断对象的equals方法是否为true。 如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。 一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,
hashCode方法建立对象判断是否相同的依据。
TreeSet:可以对Set集合中的元素进行排序。是不同步的。
判断元素唯一性的方式:就是根据比较方法的返回结果是否是0,是0,就是相同元素,不存。
TreeSet对元素进行排序的方式一:让元素自身具备比较功能,元就需要实现Comparable接口。覆盖compareTo方法。
如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。怎么办?
可以使用TreeSet集合第二种排序方式二:让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。 将该类对象作为参数传递给TreeSet集合的构
造函数。
哈希表确定元素是否相同 if(this.hashCode()== obj.hashCode() && this.equals(obj))
1,判断的是两个元素的哈希值是否相同。 如果相同,在判断两个对象的内容是否相同。
2,判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法。 注意:如果哈希值不同,是不需要判断equals。
TreeSet例子:
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">* 创建了一个根据Person类的name进行排序的比较器。
*/
public class ComparatorByName implements Comparator {
public int compare(Object o1, Object o2)
{
Person p1 = (Person) o1;
Person p2 = (Person) o2;
int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge():temp;
}
}</span></span></span>
比较的另一种方法即让对象实现Comparable接口,即让对象本身具备可比较性并重写compareTo()方法,但不如实现Comparator接口灵活。
如下例:
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">public class Person implements Comparable<Object> {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.age = age;
this.name = name;
}
public int hashCode() {
return name.hashCode() + age * 27;
}
// 两元素先后排序规则
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person) obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return name + ":" + age;
}
public int compareTo(Object o) {
Person p = (Person) o;
int temp = this.age - p.age;
return temp == 0 ? this.name.compareTo(p.name) : temp;
}
}</span></span></span>
泛型
在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。
当类中的操作的引用数据类型不确定的时候,就使用泛型来表示。其实<>就是一个用于接收具体引用数据类型的参数范围。
泛型技术是给编译器使用的技术,用于编译时期。运行时会将泛型去掉,生成的class文件不带泛型,即泛型的擦除(为了兼容运行的类加载器)
在运行时,通过获取元素的类型进行转换动作,不用使用者强制转换,即泛型的补偿。
好处:1.将运行时期的问题ClassCastException转到了编译时期。2.避免了强制转换的麻烦
可以对类型进行限定:
? extends E:接收E类型或者E的子类型对象。上限!
一般在存储元素的时候都是用上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患。
? superE :接收E类型或者E的父类型。下限!
通常对集合中的元素进行取出操作时,可以是用下限。比如比较器
集合的一些技巧:
需要唯一吗?
需要:Set
需要制定顺序:
需要: TreeSet
不需要:HashSet 但是想要一个和存储一致的顺序(有序):LinkedHashSet
不需要:List
需要频繁增删吗?
需要:LinkedList
不需要:ArrayList
array:就要想到数组,就要想到查询快,有角标.
link:就要想到链表,就要想到增删快,就要想要 add get remove+frist last的方法
hash:就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashcode方法和equals方法。
tree:就要想到二叉树,就要想要排序,就要想到两个接口Comparable,Comparator 。
Map:一次添加一对元素。Collection 一次添加一个元素。Map也称为双列集合,Collection集合称为单列集合。
其实map集合中存储的就是键值对。map集合中必须保证键的唯一性。
常用方法:
1,添加。
value put(key,value):返回前一个和key关联的值,如果没有返回null.
2,删除。
void clear():清空map集合。
valuere move(key):根据指定的key翻出这个键值对。
3,判断。
boolean containsKey(key):
boolean containsValue(value):
boolean isEmpty();
4,获取。
valueget(key):通过键获取值,如果没有该键返回null。
当然可以通过返回null,来判断是否包含指定键。
int size(): 获取键值对的个数。
Map常用的子类:
|--Hashtable :内部结构是哈希表,是同步的。不允许null作为键,null作为值。
|--Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。
|--HashMap: 内部结构是哈希表,不是同步的。允许null作为键,null作为值。
|--TreeMap: 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。
Map方法演示:
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">public class MapDemo {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
method_2(map);
}
public static void method_2(Map<Integer, String> map) {
map.put(8, "zhaoliu");
map.put(2, "zhaoliu");
map.put(2, "zhaoliu");
map.put(6, "wangcai");
/*
* 方法一:通过Map转成Set可以迭代
* 利用方法entrySet,将键和值的映射关系作为对象存储到Set集合中,其类型是Map.EntrySet
*/
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key + "::" + value);
}
/*
* 方法二:取出map中所有元素 通过keySet方法获取map中所有的键所在的Set集合,再通过Set的迭代器获取每个键值
* 再对每一个键通过map集合的get方法获取对应的值就可
*/
Set<Integer> keySet = map.keySet();
Iterator<Integer> it2 = keySet.iterator();
while (it2.hasNext()) {
Integer key = it2.next();
String value = map.get(key);
System.out.println(key + ":" + value);
}
}
}</span></span></span>
TreeMap实例:
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">/*
* 获取字符串中每一个字母出现的次数
* 思路:
* 字母和次数之间存在映射关系,考虑用Map集合
* 为保证顺序排列,用TreeMap集合
* 1.操作的是字符串的字母,先将字符串变成字符数组
* 2.遍历字符数组,用每个字母作为键去查Map集合
* 3.如果该字母键不存在,则将该字母作为键,值为1存储到Map集合
* 4.如果该字母键存在,则将该字母键对应值取出并+1,再将该字母和值存储到Map集合,键相同值会覆盖。
* 5.便利结束
*/
public class MapTest {
public static void main(String[] args) {
String str = "fdg+avAdc bs5dDa9c-dfs";
String s = getCharCount(str);
System.out.println(s);
}
public static String getCharCount(String str) {
char[] chs = str.toCharArray();
Map<Character, Integer> map = new TreeMap<Character, Integer>();
for (int i = 0; i < chs.length; i++) {
if (!(Character.toLowerCase(chs[i]) >= 'a' && Character
.toLowerCase(chs[i]) <= 'z'))
continue;
Integer value = map.get(chs[i]);
int count = 1;
if (value != null) {
count = value + 1;
}
map.put(chs[i], count);
}
return mapToString(map);
}
private static String mapToString(Map<Character, Integer> map) {
StringBuilder sb = new StringBuilder();
Iterator<Character> it = map.keySet().iterator();
while (it.hasNext()) {
Character key = it.next();
Integer value = map.get(key);
sb.append(key + "(" + value + ")");
}
return sb.toString();
}
}</span></span></span>
Map集合与Collection集合的区别:
1. Map中一次存储是键值对,Collection中一次存储是单个元素
2. Map的存储使用put方法,Collection存储使用的是add方法
3. Map的取出,得将Map转成Set,再使用迭代器取出,Collection的取出,直接使用迭代器
4. 如果对象很多,必须使用容器存储,如果元素存在映射关系,优先考虑使用Map存储或数组,没有映射关系,可以使用Collection存储。
Collections:它的出现给集合操作提供了更多的功能。这个类不需要创建对象,内部提供的都是静态方法。
sort方法:
Collections.sort(list);//list集合进行元素的自然顺序排序。
Collections.sort(list,new ComparatorByLen());//按指定的比较器方法排序。
public static <T extends Comparable <? super T>> void sort(List<T> list)
T必须是Comparable的子类,才具有比较性,实现comparator方法;Comparable泛型的类型可以是T的父类。
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">//Collections.sort(list, new ComparatorByLen());</span></span></span>
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">class ComparatorByLen implements Comparator<String>{
public int compare(String s1,String s2){
int temp = s1.length()—s2.length();
return temp==0?s1.compareTo(s2):temp;
}
}</span></span></span>
max方法:
Collections.max(list); //返回list中字典顺序最大的元素。
public static <T extends Object & Comparable<? super T>> T max (Collection<? extends T> coll) //根据元素的自然顺序,返回给定collections的最大元素
public static <T> T max(Collections<? extends T> coll, Comparator<? super T> comp) //根据指定比较起产生的顺序,返回给定Collections的最大元素
其他方法:
int index = Collections.binarySearch(list,"zz");//二分查找,返回角标。
Collections.reverseOrder();//逆向反转排序。
Collections.shuffle(list);//随机对list中的元素进行位置的置换。
将非同步集合转成同步集合的方法:
Collections中的 XXX synchronizedXXX(XXX);
List synchronizedList(list);
Map synchronizedMap(map);
原理:定义一个类,将集合所有的方法加同一把锁后返回。
Collection 和 Collections的区别:
Collections是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作。
Collection是个java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等。
Arrays数组工具类
数组转集合:集合框架的工具类,里面的方法都是静态的。
如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储。
如果数组中的元素是基本类型数值,那么会将该数组作为集合中的元素进行存储。
List asList(数组)将数组转成集合。如:List<String> list = Arrays.asList(arr);
好处:可以使用集合的方法操作数组中元素。注意:数组的长度是固定的,对于集合的增删方法是不可以使用的,否则会发生UnsupportedOperationExceptionn
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">//toString的经典实现
public static String myToString(int[] a)
{
int iMax = a.length - 1;
if(iMax == -1)
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for(int i=0; ;i++){
sb.append(a[i]);
if (i == iMax)
return sb.append(']').toString();
sb.append(", ");
}
}</span></span></span>
集合转数组:使用的是Collection接口的toArray方法。如:String[] arr = list.toArray(new String[list.size()]);
可以对集合中的元素操作的方法进行限定。
数组长度指定为集合的size。如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组。
如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为 null。
高级for循环
格式for(数据类型 变量名 : 被遍历的集合(Collection)或者数组){}
对集合进行遍历,只能获取集合元素,但是不能对集合进行操作。
迭代器除了遍历,还可以进行remove集合中元素的操作,如果是ListIterator,还可以在遍历过程中对集合进行增删改查的操作。
传统for循环和高级for循环区别:
传统for循环可以对语句执行很多次,因为可以定义控制循环的增量和条件
高级for循环局限(必须有被遍历的目标),建议在遍历数组时,仍然使用传统for循环,可以定义脚标。
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family: Arial;">public class ForEachDemo {</span></span></span>
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family: Arial;"> public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
for (String s : al) {
System.out.println(s);
}
HashMap<Integer, String> hm = new HashMap<Integer, String>();
hm.put(1, "a");
hm.put(2, "b");
hm.put(3, "c");
Set<Integer> keySet = hm.keySet();
for (Integer i : keySet) {
System.out.println(i + "::" + hm.get(i));
}
for (Map.Entry<Integer, String> me : hm.entrySet()) {
System.out.println(me.getKey() + "----------" + me.getValue());
}
}
}</span></span></span>
方法的可变参数:
数组参数的简写形式,不用每次都手动建立数组对象,只要将要操作的元素作为参数传递即可,隐式将这些参数封装成数组。注意,一定要定义在参数列表最后面。
静态导入:
其实导入的是类中的静态成员。
当类名重名时,需要指定具体的包名。当方法重名时,指定具备所属的对象或类
import Static java.util.Arrays.* //导入的是Arrays类的所有静态成员。
<span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:Arial;font-size:12px;">import static java.lang.System.*;
public class ParamMethodDemo {
public static void main(String[] args) {
show("go", 2, 3, 4, 8);
}
public static void show(String str, Integer... arr) {
out.println(str + ", " + arr.length);
}
}</span></span></span>
集合框架查补遍历集合:
<span style="font-size:12px;"><span style="font-size:12px;">//遍历List方法1,使用普通for循环
for(int i=0; i<list.size(); i++)
{
String temp = (String)list.get(i);
System.out.println(temp);
}
//遍历List方法2,使用增强for循环
for(String temp : list)
{
System.out.println(temp);
}
//遍历List方法3,使用Iterator迭代器
for(Iterator<String> it = list.iterator(); it.hasNext();)
{
String temp = (String)it.next();
System.out.println(temp);
}
//或者
Iterator it = list.iterator();
while(it.hasNext())
{
Object obj = it.next();
it.remove();//如果要遍历删除集合中的元素,建议使用这种方式
System.out.println(it);
}
//遍历Map
Map<Integer, Person> map = new HashMap<Integer, Person>();
Set<Integer> keySet = map.keySet();
for(Integer id : keySet)
{
System.out.println(map.get(id).name));
}</span></span>