1 collection集合
集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection
和双列集合java.util.Map。
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法和举例如下:
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /* java.util.Collection接口 所有单列集合的最顶层的接口,里边定义了所有单列集合共性的方法 任意的单列集合都可以使用Collection接口中的方法 共性的方法: public boolean add(E e): 把给定的对象添加到当前集合中 。 public void clear() :清空集合中所有的元素。 public boolean remove(E e): 把给定的对象在当前集合中删除。 public boolean contains(E e): 判断当前集合中是否包含给定的对象。 public boolean isEmpty(): 判断当前集合是否为空。 public int size(): 返回集合中元素的个数。 public Object[] toArray(): 把集合中的元素,存储到数组中。 */ public class Demo01Collection { public static void main(String[] args) { //创建集合对象,可以使用多态 Collection<String> coll = new ArrayList<>(); Collection<String> coll = new HashSet<>(); System.out.println(coll);//重写了toString方法 [] /* public boolean add(E e): 把给定的对象添加到当前集合中 。 返回值是一个boolean值,一般都返回true,所以可以不用接收 */ boolean b1 = coll.add("张三"); System.out.println("b1:"+b1);//b1:true System.out.println(coll);//[张三] coll.add("李四"); coll.add("李四"); coll.add("赵六"); coll.add("田七"); System.out.println(coll);//[张三, 李四, 赵六, 田七] /* public boolean remove(E e): 把给定的对象在当前集合中删除。 返回值是一个boolean值,集合中存在元素,删除元素,返回true 集合中不存在元素,删除失败,返回false */ boolean b2 = coll.remove("赵六"); System.out.println("b2:"+b2);//b2:true boolean b3 = coll.remove("赵四"); System.out.println("b3:"+b3);//b3:false System.out.println(coll);//[张三, 李四, 田七] /* public boolean contains(E e): 判断当前集合中是否包含给定的对象。 包含返回true 不包含返回false */ boolean b4 = coll.contains("李四"); System.out.println("b4:"+b4);//b4:true boolean b5 = coll.contains("赵四"); System.out.println("b5:"+b5);//b5:false //public boolean isEmpty(): 判断当前集合是否为空。 集合为空返回true,集合不为空返回false boolean b6 = coll.isEmpty(); System.out.println("b6:"+b6);//b6:false //public int size(): 返回集合中元素的个数。 int size = coll.size(); System.out.println("size:"+size);//size:3 //public Object[] toArray(): 把集合中的元素,存储到数组中。 Object[] arr = coll.toArray(); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]);//张三 李四 田七 } //public void clear() :清空集合中所有的元素。但是不删除集合,集合还存在 coll.clear(); System.out.println(coll);//[] System.out.println(coll.isEmpty());//true } }
2 Iterator迭代器
2.1 Iterator接口
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。
Iterator接口的常用方法如下:
public E next()
:返回迭代的下一个元素。public boolean hasNext()
:如果仍有元素可以迭代,则返回 true。
迭代器的代码实现:
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /* java.util.Iterator接口:迭代器(对集合进行遍历) 有两个常用的方法 boolean hasNext() 如果仍有元素可以迭代,则返回 true。 判断集合中还有没有下一个元素,有就返回true,没有就返回false E next() 返回迭代的下一个元素。 取出集合中的下一个元素 Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊 Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象 Iterator<E> iterator() 返回在此 collection 的元素上进行迭代的迭代器。 迭代器的使用步骤: 1.使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态) 2.使用Iterator接口中的方法hasNext判断还有没有下一个元素 3.使用Iterator接口中的方法next取出集合中的下一个元素 */ public class Demo01Iterator { public static void main(String[] args) { //创建一个集合对象 Collection<String> coll = new ArrayList<>(); //往集合中添加元素 coll.add("姚明"); coll.add("科比"); coll.add("麦迪"); coll.add("詹姆斯"); coll.add("艾弗森"); /* 1.使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态) 注意: Iterator<E>接口也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型 */ //1. 多态 接口 实现类对象 Iterator<String> it = coll.iterator(); //2.使用Iterator接口中的方法hasNext判断还有没有下一个元素 boolean b = it.hasNext(); System.out.println(b);//true //3.使用Iterator接口中的方法next取出集合中的下一个元素 String s = it.next(); System.out.println(s);//姚明 b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b);//没有元素,返回false s = it.next();//没有元素,再取出元素会抛出NoSuchElementException没有元素异常 System.out.println(s);*/
/*
发现使用迭代器取出集合中元素的代码,是一个重复的过程
所以可以使用循环优化
不知道集合中有多少元素,使用while循环
循环结束的条件,hasNext方法返回false
*/
while(it.hasNext()){
String e = it.next();
System.out.println(e);
}
System.out.println("----------------------");
for(Iterator<String> it2 = coll.iterator();it2.hasNext();){
String e = it2.next(); System.out.println(e); }
}
}
迭代器的实现原理:
3 泛型
3.1 泛型的概念:
3.2 泛型的定义和使用
3.2.1 定义和使用含有泛型的类
//定义一个泛型 public class GenericClass<g> {//g随便改成一个字母都行,主要是尖括号 private g name; public g getName() { return name; } public void setName(g name) { this.name = name; } } //测试 public class GenericClassTest { public static void main(String[] args) { GenericClass<Integer> gc = new GenericClass<>();//创建对象的时候才确定泛型的实际类型,这里使用的是Integer gc.setName(1); System.out.println(gc.getName()); GenericClass<String> gc1 = new GenericClass<>();//也可以使用String类型 gc1.setName("小明明"); System.out.println(gc1.getName()); } }
3.2.2 定义和使用含有泛型的方法
//创建一个含有泛型方法的类 public class GenericMethod { public <e> void gmMethod(e ele){ System.out.println(ele); } public static <m> void staticGm(m mm){ System.out.println(mm); } }
//测试 public class GenericMethodTest { public static void main(String[] args) { GenericMethod method1 = new GenericMethod(); method1.gmMethod(1); method1.gmMethod("aaaaaaa"); method1.gmMethod(true); GenericMethod method2 = new GenericMethod(); method2.staticGm(222); GenericMethod.staticGm("静态方法建议用类名.静态方法名调用"); } }
3.2.3 定义和使用含有泛型的接口
//创建一个含有泛型的接口 public interface GenericInterface<e> { void method(e m); } //第一个方法:创建实现类的时候就指明实现类的类型 public class GenericInterfaceImp implements GenericInterface<String > { @Override public void method(String m) { System.out.println("重写了抽象类的方法"); System.out.println(m); } } //第二个方法:创建实现类的时候,泛型跟着接口的泛型走,创建对象的时候才指明泛型的具体类型 public class GenericInterfaceImp2<e> implements GenericInterface<e> {//注意这两个地方都需要加尖括号<>,而且里面的类型与接口的泛型一致 @Override public void method(e m) { System.out.println(m); } } //测试 public class GenericInterfaceImpTest { public static void main(String[] args) { GenericInterfaceImp imp = new GenericInterfaceImp(); imp.method("传递的参数就是这个" ); GenericInterfaceImp2<Integer> imp2 = new GenericInterfaceImp2<Integer>();//注意要在这里创建时指明泛型的具体类型, //否则下面的方法调用的参数会是Object类型 imp2.method(1111); } }
3.2.4 泛型的通配符
import java.util.ArrayList; import java.util.Iterator; public class GenericInterfaceImpTest { public static void main(String[] args) { GenericInterfaceImp imp = new GenericInterfaceImp(); imp.method("传递的参数就是这个" ); GenericInterfaceImp2<Integer> imp2 = new GenericInterfaceImp2<Integer>(); imp2.method(1111); System.out.println("====测试通配符===="); ArrayList<String> list1 = new ArrayList<>(); list1.add("aaa"); list1.add("bbb"); ArrayList<Integer> list2 = new ArrayList<>(); list2.add(123); list2.add(456); printArrayList(list1); printArrayList(list2); } public static void printArrayList(ArrayList<?> list){ //Iterator iterator = new Iterator();//Iterator是一个接口,不能直接new, Iterator<?> it = list.iterator();//集合list是什么类型,迭代器就是什么类型。测试中发现,问号不写也不会报错 //Iterator it = list.iterator();//需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊: // Collection对象(可以换成具体的如ArrayList对象,也可以就用Collection对象)有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象 while (it.hasNext()){ System.out.println(it.next()); } } }
//Output
重写了抽象类的方法
传递的参数就是这个
1111
====测试通配符====
aaa
bbb
123
456
3 list集合
3.1 List接口概述
Collection中的常用几个子类包括( java.util.List 集合、java.util.Set 集合)
List接口特点:
1. 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、
22、33的顺序完成的)。
2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
3.2 ArrayList集合
java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为
查询数据、遍历数据,所以ArrayList 是最常用的集合。
ArrayList底层是数组结构(所以名字带Array)。
ArrayList不是同步的,多线程的(快)。
1.0版本中的Vector是同步的,单线程(慢)。
1.2以后,Vector被ArrayList代替。
3.2 LinkedList集合
LinkedList是双向链表。由于底层是一个链表结构:元素增删快,查找慢。
4 Set接口
Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
没有索引,没有带索引的方法,不能使用普通的带for循环的遍历。
tips:Set集合取出元素的方式可以采用:迭代器、增强for。
4.1 HashSet集合介绍
java.util.HashSet 是Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序
不一致)。java.util.HashSet 底层的实现其实是一个java.util.HashMap 支持。
4.1.1 哈希值
/* 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址) 在Object类有一个方法,可以获取对象的哈希值 int hashCode() 返回该对象的哈希码值。 hashCode方法的源码: public native int hashCode(); native:代表该方法调用的是本地操作系统的方法 */ public class Demo01HashCode { public static void main(String[] args) { //Person类继承了Object类,所以可以使用Object类的hashCode方法 Person p1 = new Person(); int h1 = p1.hashCode(); System.out.println(h1);//1967205423 Person p2 = new Person(); int h2 = p2.hashCode(); System.out.println(h2);//42121758 /* toString方法的源码: return getClass().getName() + "@" + Integer.toHexString(hashCode()); */ System.out.println(p1);//@75412c2f System.out.println(p2);//@282ba1e System.out.println(p1==p2);//false /* String类的哈希值 String类重写了Obejct类的hashCode方法 */ String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1.hashCode());//96354 System.out.println(s2.hashCode());//96354 System.out.println("重地".hashCode());//1179395 巧合 System.out.println("通话".hashCode());//1179395 } }
4.1.2 HashSet集合存储数据的结构(哈希表)
Set集合(如java.util.HashSet 、java.util.LinkedHashSet 这两个集合)不允许存储重复元素的原理: