集合的概念:对象的容器,实现了对对象常用的操作,类似数组的功能。
集合与数组的区别:数组长度固定,集合长度不固定;数组可以存储基本类型与引用类型,集合只能存储引用类型,存储基本类型需要采用“装箱”操作。
collection体系集合:
ArrayList:数据结构实现,查询快,增删慢;JDK1.2版本,运行效率快,线程不安全。
Vector:数据结构实现,查询快,增删慢。JDK1.0版本,运行效率慢,线程安全。
LinkedList:链表实现,增删快,查询慢。
collection常用方法:
collection集合再添加对象时,添加的是对象的地址,因此,collection调用clear或者remove方法时,只是将对象从集合中移除出去,但是对象依旧存在。
collection的demo如下:
package CollectionDemo;
import Student.Student;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemoFunction {
public static void listFunction1() {
Collection collection = new ArrayList();
collection.add("苹果0");
collection.add("苹果1");
collection.add("苹果2");
collection.add("苹果3");
System.out.println("元素个数" + collection.size());
System.out.println(collection);
System.out.println("~~~~~~增强for~~~~~~");
for (Object o: collection) {
System.out.println(o);
}
System.out.println("~~~~~~迭代器~~~~~~");
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("元素个数" + collection.size());
System.out.println("~~~~~~迭代器删除~~~~~~");
Iterator iterator1 = collection.iterator();
while(iterator1.hasNext()) {
iterator1.next(); // 迭代器得先取出来,再删除
// collection.remove("苹果0"); // 迭代器中不能中collection的方法
iterator1.remove();
}
System.out.println("元素个数" + collection.size());
}
public static void listFunction2() {
Collection collection = new ArrayList();
Student s1 = new Student("张三1",16);
Student s2 = new Student("张三2",17);
Student s3 = new Student("张三3",18);
Student s4 = new Student("张三4",19);
collection.add(s1);
collection.add(s2);
collection.add(s3);
collection.add(s4);
System.out.println("元素个数:" + collection.size());
System.out.println(collection.toString());
collection.remove(s1);
System.out.println("删除一个元素后的元素个数:" + collection.size());
System.out.println(collection.toString());
System.out.println("~~~~~~~~~~增强for~~~~~~~~~");
for(Object o : collection) {
Student s = (Student)o;
System.out.println(s.toString());
}
System.out.println("~~~~~~~~~~迭代器~~~~~~~~~");
Iterator iterator = collection.iterator();
while(iterator.hasNext()) { // 迭代器中不能使用clooection的删除方法,迭代器中的remove方法的前面要有next方法
Student s = (Student)iterator.next();
System.out.println(s.toString());
}
System.out.println("s2是否存在?" + collection.contains(s2));
}
}
ArrayList是一个连续地址空间,它的demo如下:
package List;
import Student.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class ArrayListFunction {
public static void ArrayListTest1() {
ArrayList arrayList = new ArrayList();
Student s1 = new Student("路的话0", 160);
Student s2 = new Student("路的话1", 161);
Student s3 = new Student("路的话2", 162);
Student s4 = new Student("路的话3", 163);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
System.out.println("元素个数:" + arrayList.size());
System.out.println(arrayList.toString());
arrayList.remove(new Student("路的话0", 160));
System.out.println("元素个数:" + arrayList.size());
System.out.println(arrayList.toString());
System.out.println("~~~~~~~迭代器~~~~~~~~");
Iterator iterator = arrayList.iterator();
while(iterator.hasNext()) {
Student s = (Student) iterator.next();
System.out.println(s.toString());
}
System.out.println("~~~~~~~列表迭代器:顺序执行~~~~~~~~");
ListIterator listIterator = arrayList.listIterator();
while(listIterator.hasNext()) {
Student s = (Student) listIterator.next();
System.out.println(s.toString());
}
System.out.println("~~~~~~~列表迭代器:逆序执行~~~~~~~~");
while(listIterator.hasPrevious()) {
Student s = (Student) listIterator.previous();
System.out.println(s.toString());
}
System.out.println("s2的位置:" + arrayList.indexOf(s2));
}
}
Vector是线程安全的,它的添加,移除,判空操作和上面是一样的,但是他除了可以用for,iterator来遍历外,也可以用如下方式进行遍历:
public class VectorTest {
public static void main(String[] args) {
Vector t =new Vector();
t.add("H");
t.add("k");
t.add("q");
System.out.println("元素个数:" + t.size());
System.out.println("元素:" + t.toString());
// 遍历
System.out.println("~~~~~~~~~~~~~~遍历~~~~~~~~~~~");
Enumeration enumeration = t.elements();
while(enumeration.hasMoreElements()) {
String s = (String)enumeration.nextElement();
System.out.println(s);
}
}
}
linklist是一个双向链表,遍历时可以采用ListIterator进行从前往后,从后往前的遍历,demo如下:
public static void main(String[] args) {
LinkedList<Student> linkedList = new LinkedList<Student>();
Student s1 = new Student("张三", 16);
Student s2 = new Student("李四", 17);
Student s3 = new Student("王五", 18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:" + linkedList.size());
System.out.println("~~~~~~~~~~~for循环遍历:~~~~~~~~~~");
for (int i = 0; i < linkedList.size(); i++) {
Student s = (Student)linkedList.get(i);
System.out.println("名字:"+ s.getName() + "; 年龄: "+ s.getAge());
}
System.out.println("~~~~~~~~~~~增强for循环遍历:~~~~~~~~~~");
for (Object l: linkedList) {
Student s = (Student)l;
System.out.println(s.toString());
}
System.out.println("~~~~~~~~~~~迭代遍历:~~~~~~~~~~");
Iterator iterator = linkedList.iterator();
while(iterator.hasNext()) {
Student s = (Student)iterator.next();
System.out.println("名字:"+ s.getName() + "; 年龄: "+ s.getAge());
}
System.out.println("~~~~~~~~~~~list迭代遍历:~~~~~~~~~~");
System.out.println("first-->last:");
ListIterator listIterator = linkedList.listIterator();
while(listIterator.hasNext()) {
Student s = (Student)listIterator.next();
System.out.println(s.toString());
}
System.out.println("last-->first:");
while(listIterator.hasPrevious()) {
Student s = (Student)listIterator.previous();
System.out.println(s.toString());
}
System.out.println("是否包含张三?"+linkedList.contains(s1));
System.out.println("是否为空?"+linkedList.isEmpty());
}
泛型的本质:参数化类型,把类型作为参数传递,语法是<T...>,T称为类型占位符,表示一种引用类型。好处是:提高代码的重用性;防止装换异常,提高代码使用的安全性。有三种类型:
泛型类:
public class myGeneric<T> {
T t;
public void show(T t) {
System.out.println(t);
}
public T getT() {
return t;
}
}
泛型接口:
public interface myInterface<T> {
T server(T t);
}
泛型方法:
public class myMethod {
public <T> T show(T t) {
System.out.println("泛型方法的使用:" + t);
return t;
}
}
泛型集合:参数化类型,类型安全的集合,强制集合元素的类型必须一致。
public static void main(String[] args) {
LinkedList<Student> linkedList = new LinkedList<Student>();
Student s1 = new Student("张三", 16);
Student s2 = new Student("李四", 17);
Student s3 = new Student("王五", 18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:" + linkedList.size());
System.out.println("~~~~~~~~~~~for循环遍历:~~~~~~~~~~");
for (int i = 0; i < linkedList.size(); i++) {
Student s = (Student)linkedList.get(i);
System.out.println("名字:"+ s.getName() + "; 年龄: "+ s.getAge());
}
System.out.println("~~~~~~~~~~~增强for循环遍历:~~~~~~~~~~");
for (Object l: linkedList) {
Student s = (Student)l;
System.out.println(s.toString());
}
System.out.println("~~~~~~~~~~~迭代遍历:~~~~~~~~~~");
Iterator iterator = linkedList.iterator();
while(iterator.hasNext()) {
Student s = (Student)iterator.next();
System.out.println("名字:"+ s.getName() + "; 年龄: "+ s.getAge());
}
System.out.println("~~~~~~~~~~~list迭代遍历:~~~~~~~~~~");
System.out.println("first-->last:");
ListIterator<Student> listIterator = linkedList.listIterator();
while(listIterator.hasNext()) {
Student s = listIterator.next();
System.out.println(s.toString());
}
System.out.println("last-->first:");
while(listIterator.hasPrevious()) {
Student s = listIterator.previous();
System.out.println(s.toString());
}
System.out.println("是否包含张三?"+linkedList.contains(s1));
System.out.println("是否为空?"+linkedList.isEmpty());
}
特点:
编译时即可检查,而非运行时抛出异常。
访问时,不必类型转换(拆箱)。
不同泛型之间的引用不能相互赋值,泛型不存在多态。
HashSet的Demo如下,hashSet是中用到了hashcode,它是由数组+链表+红黑树组成,其中有用到一个数31,用到这个数的原因有两个:一是它数一个质数,能减少散列冲突;其次,31*i = (i<<5)-1,将乘法转为移位运算与减法,减少计算量。
public static void hashSetDemo() {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("苹果");
hashSet.add("栗子");
hashSet.add("香蕉");
hashSet.add("哈密瓜");
System.out.println("元素个数:" + hashSet.size());
System.out.println("元素:" + hashSet.toString());
System.out.println("迭代:");
Iterator<String> it = hashSet.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
TreeSet的结构是红黑树,认为是重复元素的依据是compareTo()方法,因此元素需要自己实现Comparable接口。我定义一个Person类,继承了Comparable接口,并实现compareTo()方法,然后在demoh中添加Person元素,如果不继承并实现这个方法,则无法添加成功:
package SetDemo;
import java.util.Objects;
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Person o) {
int n = this.getName().compareTo(o.getName());
int m = this.age - o.age;
return n == 0 ? m : n;
}
}
demo:
public static void treeSetDemo1() {
TreeSet<Person> treeSet = new TreeSet<>();
Person p1 = new Person("张三", 10);
Person p2 = new Person("张si", 9);
Person p3 = new Person("张w", 12);
Person p4 = new Person("张lui", 8);
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
treeSet.add(p4);
System.out.println("元素个数:" + treeSet.size());
System.out.println("元素:" + treeSet.toString());
Iterator<Person> iterator = treeSet.iterator();
while(iterator.hasNext()) {
Person p = iterator.next();
System.out.println("人名:"+ p.getName() + "年龄:" + p.getAge());
}
}
当然,也可以不采用继承的方式,而是采用匿名内部类的方式实现:
public static void treeSetDemo2() {
TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n = o1.getAge() - o2.getAge();
int m = o1.getName().compareTo(o2.getName());
return n == 0 ? m : n;
}
});
Person p1 = new Person("张sam", 10);
Person p2 = new Person("张si", 9);
Person p3 = new Person("张w", 12);
Person p4 = new Person("张lui", 8);
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
treeSet.add(p4);
System.out.println("元素个数:" + treeSet.size());
System.out.println("元素:" + treeSet.toString());
Iterator<Person> iterator = treeSet.iterator();
while(iterator.hasNext()) {
Person p = iterator.next();
System.out.println("人名:"+ p.getName() + "年龄:" + p.getAge());
}
}
Map的特点:存储键值对,键不能重复,值可以重复;无序。
map的简单demo:
// 创建Map集合
Map<String, String> map = new HashMap<String, String>();
// 添加元素
map.put("cn", "中国");
map.put("uk", "英国");
map.put("usa", "美国");
map.put("cn", "zhongguo");
System.out.println("元素个数:" + map.size());
System.out.println("~~~~~~~~~~~~~增强for~~~~~~~~~~~~");
for(String key : map.keySet()) {
System.out.println(key + "-------------" + map.get(key));
}
System.out.println("~~~~~~~~~~~~entrySet~~~~~~~~~~~~");
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() +"------------"+ entry.getValue());
}
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("美国"));
}
HashMap的存储结构是数组+链表+红黑树,通过判断key不可重复,重复的依据是hashcode与equals函数,其demo如下:
public static void haspMapDemo2() {
HashMap<Student, String> students = new HashMap<Student, String>();
Student s1 = new Student("孙1",1);
Student s2 = new Student("朱2",2);
Student s3 = new Student("傻3",3);
students.put(s1, "昆仑");
students.put(s2, "蓬莱");
students.put(s3, "泰山");
students.put(new Student("傻3",3), "泰山");
System.out.println("元素个数:" + students.size());
System.out.println("元素:" + students.toString());
System.out.println("~~~~~~~~~KeySet遍历~~~~~~~");
Set<Student> s = students.keySet();
for(Student student : s) {
System.out.println(student + "----------" + students.get(student));
}
System.out.println("~~~~~~~~~entrySet遍历~~~~~~~");
Set<Map.Entry<Student,String>> entrys = students.entrySet();
for(Map.Entry<Student,String> entry : entrys) {
System.out.println(entry.getKey() + "-----------------" + entry.getValue());
}
}
TreeMap的存储结构是红黑树,因此,也需要引用Comparable类,需要重写compareTo接口:
public static void treeMapDemo1() {
TreeMap<Student, String> treeMap = new TreeMap<Student, String>();
Student s1 = new Student("孙1",1);
Student s2 = new Student("朱2",2);
Student s3 = new Student("傻3",3);
treeMap.put(s1, "长沙");
treeMap.put(s2, "墨西哥");
treeMap.put(s3, "纽约");
System.out.println("元素个数:" + treeMap.size());
System.out.println("元素:" + treeMap);
System.out.println("------KeySet---------");
Set<Student> set = treeMap.keySet();
for(Student s : set) {
System.out.println(s + "-----" + treeMap.get(s));
}
System.out.println("------entrySet---------");
Set<Map.Entry<Student,String>> entries = treeMap.entrySet();
for (Map.Entry<Student,String> entry : entries) {
System.out.println(entry.getKey() +"----------"+ entry.getValue());
}
}
Student类,这个类也是上面HashMap的demo中用到的类:
public class Student implements Comparable<Student>{
private String name;
private int stuNo;
public Student() {
}
public Student(String name, int stuNo) {
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public int getStuNo() {
return stuNo;
}
public void setName(String name) {
this.name = name;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (this instanceof Student) {
Student s = (Student)o;
if (this.name.equals(s.name) && this.stuNo == s.stuNo) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
int n = this.name.hashCode();
int m = this.stuNo + 31;
return n == 0 ? m : n;
}
public int compareTo(Student o) {
int n = this.getStuNo() - o.getStuNo();
return n;
}
}
collections工具类的使用:
public static void CollectionsToolsDemo1() {
List<Integer> list = new ArrayList<Integer>();
list.add(12);
list.add(23);
list.add(1);
list.add(5);
list.add(34);
System.out.println("排序之前:" + list.toString());
Collections.sort(list);
System.out.println("排序之后:" + list.toString());
// 二分查找,找到元素在表中的位置,找不到就返回小于0的值
int i = Collections.binarySearch(list, 5);
System.out.println("5所在的位置:" + i);
// 拷贝
List<Integer> dest = new ArrayList<Integer>();
for (i = 0; i < list.size(); i++) {
dest.add(0);
}
Collections.copy(dest, list);
System.out.println("dest: " + dest.toString());
// 反转
Collections.reverse(list);
System.out.println("反转之后:" + list.toString());
// 打乱
Collections.shuffle(list);
System.out.println("打乱之后:" + list.toString());
// list转为数组
System.out.println("--------list转为数组--------");
Integer[] arr = list.toArray(new Integer[0]);
System.out.println("数组长度:" + arr.length);
System.out.println("数组:" + Arrays.toString(arr));
// 数组转为list,但是此时的集合是一个受限集合,无法做添加与删除操作
System.out.println("--------数组转为list--------");
String[] strings = {"张三", "里斯", "王武"};
List<String> list1 = Arrays.asList(strings);
System.out.println("list1 :" + list1);
// 在进行转换时,不能用基本类型int,只能用包装类型
System.out.println("--------integer转换--------");
Integer[] nums = {100,200,300,400,500};
List<Integer> list2 = Arrays.asList(nums);
System.out.println(list2);
}