一、Collection单列集合
(一)List接口的实现类
1、ArrayList
(1)构造函数:
ArrayList arr = new ArrayList(); //创建一个初始容量为10的空列表
ArrayList arr1 = new ArrayList(int x); //创建初始容量为指定大小x的空列表
(2)常用方法:
add(Object obj); //向集合中存入元素
get(int index); //获取指定角标位置的元素
size( ); //返回集合中元素的个数
(3)集合的迭代:借助迭代器对象
List<String> list = new ArrayList<String>(); //创建集合
list.add("aa"); //向集合中添加元素
list.add("bb");
Iterator<String>iter = list.iterator(); //获得与集合对象匹配的迭代器
while(iter.hasNext()) { //判断是否有下一个元素
String string= iter.next(); //迭代出下一个元素
System.out.println(string);
}
next()方法:让迭代器指向下一个元素,并返回当前指向的元素。
注意:集合在迭代期间,不能调用集合的方法增删元素,否则会并发访问异常:(ConcurrentModificationException)。如果要增删元素,需用迭代器的方法。
a.删除元素:Iterator的remove方法。
ArrayList<String> arr = new ArrayList<String>();
arr.add("aa");
arr.add("bb");
arr.add("cc");
Iterator<String> iter = arr.iterator();
while (iter.hasNext()) {
String s = iter.next();
if("bb".equals(s)) //常量写在equlas前面,防止空指针异常
iter.remove();
}
System.out.println(arr);
b.增加元素:使用ListIterator的add方法
ArrayList<String> arr = new ArrayList<String>();
arr.add("aa");
arr.add("bb");
arr.add("cc");
ListIterator<String> listiter = arr.listIterator();
while (listiter.hasNext()) {
String s = listiter.next();
if("bb".equals(s))
listiter.add("xxx");
}
System.out.println(arr);
2、Vector
线程安全,但是效率低。且集合对象不会用作成员变量,而对象作为方法的局部变量不会有线程安全的问题,所以已被ArrayList淘汰。
迭代:Enumeration,只适用于Vector集合
Vector<String> v = new Vector<String>();
v.add("aa");
v.add("bb");
Enumeration<String> e = v.elements();
while(e.hasMoreElements()) {
String str = e.nextElement();
System.out.println(str);
}
3、LinkedList集合
addFirst(“aa”); (效率高) add(0, ”aa”);
removeFirst(); (效率高) remove(0);
addLast(“dd”); add(“dd”);
removeLast(); remove(角标);
(二)Set接口的实现类
1、HashSet:通过哈希算法保证无重复元素
HashSet<Person> hashSet = newHashSet<Person>();
a.重复元素的hashCode()返回的哈希值必须一样。
保证重复元素的存储位置在同一区间,有机会进行equals比较。
为此,需要重写hashCode()方法。如果不重写hashCode()方法,不同对象,即
使属性相同,默认返回的哈希值也不一样,存储位置不在同一区间,无法进行
equals比较。
@Override
publicint hashCode() {
returnthis.name.hashCode() +this.age*31;//避免x+y与y+x得出的值相同
}
b.重复元素进行equals()比较返回的值为true。
因此,必须重写equals()方法。
子类:LinkedHashSet。元素有序的HashSet
LinkedHashSet<String> linked = new LinkedHashSet<String>();
Collection<String>c = new ArrayList<String>();
c.add("aa");
c.add("bb");
linked.addAll(c); //特殊方法。addAll(Collection c)
2、TreeSet:
新存的元素与原来的元素比较,如果比原来的元素打,存入右边;如果比原来的元素小,存入左边;如果与原来的一样,不存。
实现排序的方法:
(1)按照自然顺序进行排序,元素实现Comparable接口的compareTo()方法。
publicclass PersonimplementsComparable {
private Stringname;
privateintage;
@Override
publicint compareTo(Object o) {
Person p = (Person)o;
//先按照名字比较
int num =this.name.compareTo(p.name);
if(num != 0)
return num;
//如果名字相同,按照年龄比较
returnthis.age - p.age;
}
}
(2)按照比较器排序,实现Comparator接口的compare()方法。
在创建TreeSet对象时,传入比较器对象
TreeSet<Person> treeSet =new TreeSet<Person>(new MyComparator());
class MyComparatorimplementsComparator {
@Override
publicint compare(Object o1, Object o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
//先比较年龄
int num = p1.getAge() - p2.getAge();
if (num != 0)
return num;
//如果年龄相同,比较名字
return p1.getName().compareTo(p2.getName());
}
}
注意:如果两种方式都实现,则以比较器的排序规则为准。
二、Map双列集合
Map存储了一系列的键值的映射关系。put(key,value)
(一)HashMap:哈希算法实现
HashMap<String , Person> hashMap = newHashMap<String, Person>();
1、向HashMap中存入元素:put(key, value)
如果向HashMap中存入相同的key,新存入的value值会覆盖之前的value值。
2、获取HashMap中的元素
a.获得所有的key: Set<String> keys =hashMap.keySet();
b.获得所有的value: Collection<Person> values =hashMap.values();
c.通过key获得value: Person value = hashMap.get(key);
3、迭代HashMap集合的元素
(1)获得所有的key组成的Set集合,遍历集合,根据key获得value
HashMap<String, Person> hashMap = new HashMap<String, Person>();
Set<String> keys = hashMap.keySet(); //获得所有的key
for (String key : keys) {
Person value =hashMap.get(key); //根据key获得value
System.out.println(key +":" + value);
}
(2)获得所有的Entry(键值对)对象组成的Set集合,遍历,分别获得key和value
Set<Entry<String, Person>> entrys = hashMap.entrySet();
for (Entry<String, Person> entry : entrys) {
String key = entry.getKey();
Person value = entry.getValue();
System.out.println(key +":" + value);
}
子类:LinkedHashMap.元素有序的HashMap。
(二)TreeMap:二叉树实现,按照key排序
(三)HashTable:哈希算法实现,线程安全,已被HashMap淘汰
子类:Properties:操作配置项。
此集合没有泛型。由于配置文件都是String类型的,Properties的key和value都是String类型的。
1、向Properties中存入元素:
setProperty(String key, String value)
2、取出Properties集合中的元素:
getProperty(String key);
3、返回该属性列表中所有键的枚举
propertyNames( );
例子:
Properties props = new Properties();
props.setProperty("a", "aaaaaa"); //向集合中存入元素
props.setProperty("b","bbbbbb");
props.setProperty("c","cccccc"); //返回该属性列表中所有键的枚举
Enumeration<String> names=(Enumeration<String>)props.propertyNames();
while(names.hasMoreElements()) {
String name =names.nextElement();
String value = props.getProperty(name); //根据key获得value值
System.out.println(name+":"+value);
}
三、Iterator 迭代器:用来迭代集合中的元素
Iterator:在迭代的过程中可以调用remove()方法删除元素,移除迭代器指向的集合被迭代的最后一个元素。
子类:ListIterator:在迭代的过程中可调用add()方法增加元素
四、增强for循环
用于遍历集合中的元素,不能用于修改集合中的元素。
循环次数就是容器中元素的个数,每次循环迭代容器中的一个元素,将元素赋值给变量。
五、可变参数
定义:类型...变量
理解:可变参数对调用者来说可以传入0~多个参数。
可变参数对方法而言就是一个数组,JVM将调用者传入的参数封装成一个数组传递给方法
//求n个参数的和
privatestaticint sum(int...nums) {
int sum = 0;
for(int i=0;i<nums.length;i++) {
sum+=nums[i];
}
return sum;
}
注意事项:
(1)可变参数必须位于方法的最后一个参数,一个方法只能有一个可变参数
(2)使用可变参数会有版本冲突问题,此时会向下兼容jdk1.4
String[] s1 = {"aa","bb"};
String[] s2 = {"a","b"};
a.
List<String[]> list1 = Arrays.asList(s1,s2);
// 只符合jdk1.5的语法,将数组存入集合,2个元素
System.out.println(list1); //打印出两个数组的首地址
b.
List<String> list2 = Arrays.asList(s1);
//同时符合jdk1.4和jdk1.5的语法,向下兼容jdk1.4,拆分数组,将s1数组的两个元素存入集合 asList(Object[]arr) asList(T...t)
将arr中的元素作为一个列表 将T类型的t作为列表
System.out.println(list2); //打印 [aa,bb]
c.
List<Object> list2 =Arrays.asList((Object)s1);//数组向上提升为Object对象
System.out.println(list2); //打印s1对象的首地址
List<Object> list2 =Arrays.asList(new Object[]{s1});
//按照jdk1.4的语法,将s1对象作为数组的一个元素
System.out.println(list2); //打印 s1对象的首地址
六、泛型
1、泛型在集合中使用:
在集合中使用泛型,实际上就是为集合贴了一个标签,限定了存入集合的对象的类型,可以提高安全性,不必进行类型强转。
List<String>list = new ArrayList<String>();
注意事项:
(1)等式两边的泛型必须保持一致。
编译器在检查语法是看等式左边变量的类型。
程序运行期间,对象的类型取决于等式右边。
(2)可以只在等式一边定义泛型。原因是泛型是JDK1.5的新特性,为了实现向下兼容。
2、泛型的概念:
(1)在类上使用泛型
需求:一个类的多个方法用到的类型可以使任意类型,但是必须是同一种类型。
泛型可以解决上述问题。泛型是一种不确定的变化的类型。
泛型可以理解为一种类型变量,形参只能传入类型。
正常情况下使用泛型应该传入参数,但是由于泛型是在JDK1.5之后出现的,为了实现向下兼容,泛型允许不传参,如果不传参,JVM在编译时传入参数Object。
class Demo {
publicstaticvoid main(String[] args) {
QQFarm<Gua> farm = new QQFarm<Gua>();
farm.plant(new Gua());
Gua gua = farm.get();
}
}
class Gua { //定义一个类型
}
//可以种植任何东西,也可以收获任何东西,但种植和收获的必须是一种东西
class QQFarm<T>{
//种植
publicvoid plant(T obj) {
}
//收获
public T get() {
returnnull;
}
}
(2)泛型方法
在类上声明的泛型对类的静态成员无效。如果在静态方法中所需要使用泛型,泛型要在方法的返回值前面,紧挨着返回值的地方加以声明。
publicstatic<T>T sum(T x, T y){
//判断x是否具备自然顺序
if(!(xinstanceof Comparable))
thrownew RuntimeException("不具备自然顺序,不能比较");
Comparable com = (Comparable)x;
return com.compareTo(y)>0?x:y;
}