1.集合详解
数组⻓度不能改变,若元素数量不定,使用数组不便,可以使用集合。集合类也叫容器类。容器用来装载数据,集合为对象而生,存储多个对象一般用集合。Java集合框架位于java.util包中,提供了一套性能优良、使用方便的接口和类。数组元素可以存放基本类型的值 和对象;集合只能保存对象。Java集合类型:Callection和Map
⻩色块表示集合的接口,蓝色表示集合的实现类。
接口名称 | 作用 |
Iterator接口 | 集合的迭代接口,用于集合的遍历 |
Collection接口 | 是单值集合的顶级接口。是LIst、set、Queue的父接口 |
Queue接口 | 是用来实现队列的 |
LIst接口 | 最常用的接口。有序集合,允许有相同元素 |
Set接口 | 无序集合,不能包含重复元素 |
Map接口 | 存放键值对的顶级接口。 |
2.List接口
List 接口存储一组可重复,有序的集合。主要有两个实现类:ArrayList和Linkedlist
2.1.ArrayList类
实现了动态可变数组,随机访问速度快,插入和删除元素的速度慢。可以插入null,初始容量为10,每次动态扩容的⻓度是当前⻓度的50%。常用方法如下:
方法 | 返回值 | 描述 |
add(E e) | boolean | 将元素e追加到列表的末尾 |
add(int index, E e) | Void | 将元素e追加到列表的index位置 |
addAll(Collction c) | Boolean | 将集合c追加到集合的末尾 |
clear() | Void | 清空列表 |
contains(Object obj) | Boolean | 判断列表中是否包含元素obj |
get(int index) | E | 获取index位置的元素 |
indexOf(Object obj) | Int | 返回obj第一次出现在列表中的位置,如果列表中没有obj, 则返回-1 |
isEmpty() | boolean | 判断列表是不是空的 |
remove(int index) | E | 删除指定位置的元素 |
set(int index,E e) | E | 将index位置的元素替换为e |
size() | int | 返回列表中元素的个数 |
Iterator迭代器
Iterator接口表示对集合进行迭代的迭代器,专门实现集合的遍历。方法:HasNext():判断是否存在另一个可采访的元素;next()返回要访问的下一个元素。
public class ArrayList01 {
public static void main(String[] args) {
// 第一种声明方式
// ArrayList a1 = new ArrayList();
// 第二种声明方式,多态的应用
List list = new ArrayList();
// 增加
list.add("a");
list.add("b");
list.add("c");
list.add("a");
// list.add(1, "hh");// 向指定的位置添加元素
// 遍历元素,普通for循环
for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);// get(i)获取指定下标的元素值
System.out.println(str);
}
System.out.println("----------增强for循环-------------");
// 遍历元素,高级|增强for循环
for (Object object : list) {
String str = (String) object;
System.out.println(str);
}
System.out.println("----------迭代器遍历-------------");
Iterator it = list.iterator();// 得到迭代器为集合的遍历而生
while (it.hasNext()) {// hasNext()判断是否有下一个元素
Object object = it.next();// next()是返回下一个元素
String str = (String) object;// 强制类型转换
System.out.println(str);
}
System.out.println("元素个数:" + list.size());
// 删去
// list.remove(1);// 删去指定位置索引的元素
// list.remove("b");// 删去指定元素
// System.out.println("删去后元素个数:" + list.size());
// 查询
// 查找指定元素第一次出现位置的下标
System.out.println("值为a元素下标为:" + list.indexOf("a"));
// 查找指定元素第一次出现位置的下标
System.out.println("值为a从后往前找下标为:" + list.lastIndexOf("a"));
// 修改
int index = list.lastIndexOf("a");
list.set(3, "d");
for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);// get(i)获取指定下标的元素值
System.out.println(str);
}
// 判断
System.out.println("集合是否为空: " + list.isEmpty());
System.out.println("集合是否包含a元素: " + list.contains("a"));
}
}
2.2.LinkedList实现类
存储有序、可重复的对象;底层存储结构为链表结构;随机访问速度低,插入删除性能高。
常用方法:
方法 | 说明 |
addFirst(E e) | 将指定元素插入到次集合的开头 |
addLast(E e) | 将指定元素插入到次集合的末尾 |
getFirst() | 获取此集合的第一个元素 |
getLast() | 获取此集合的最后一个元素 |
removeFirst() | 删除此集合中的第一个元素 |
removeLast() | 删除此集合中的最后一个元素 |
public class LinkedList01 {
public static void main(String[] args) {
// 第二种声明方式,多态的应用
LinkedList list = new LinkedList();
// 增加
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.addFirst("fitst");// 向开头位置添加元素LinkedList的特有方法
list.addLast("last");// 向末尾位置添加元素
// list.add(1, "hh");// 向指定的位置添加元素
// 遍历元素,普通for循环
for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);// get(i)获取指定下标的元素值
System.out.println(str);
}
System.out.println("----------增强for循环-------------");
// 遍历元素,高级|增强for循环
for (Object object : list) {
String str = (String) object;
System.out.println(str);
}
System.out.println("----------迭代器遍历-------------");
Iterator it = list.iterator();// 得到迭代器为集合的遍历而生
while (it.hasNext()) {// hasNext()判断是否有下一个元素
Object object = it.next();// next()是返回下一个元素
String str = (String) object;
System.out.println(str);// 强制类型转换
}
System.out.println("元素个数:" + list.size());
// 删去
// list.remove(1);// 删去指定位置索引的元素
// list.remove("b");// 删去指定元素
// System.out.println("删去后元素个数:" + list.size());
list.removeFirst();// 删去第一个元素LinkedList的特有方法
list.removeLast();// 删去最后一个元素
// 查询
// 查找指定元素第一次出现位置的下标
System.out.println("值为a元素下标为:" + list.indexOf("a"));
// 查找指定元素第一次出现位置的下标
System.out.println("值为a从后往前找下标为:" + list.lastIndexOf("a"));
// 修改
int index = list.lastIndexOf("a");
list.set(index, "d");
for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);// get(i)获取指定下标的元素值
System.out.println(str);
}
// 判断
System.out.println("集合是否为空: " + list.isEmpty());
System.out.println("集合是否包含a元素: " + list.contains("a"));
// 获取
System.out.println("获取下标为2的元素值: " + list.get(2));
// 获取第一个和最后一个元素的值,LinedList特有的方法
System.out.println("获取第1个元素值: " + list.getFirst());
System.out.println("获取最后1个元素值: " + list.getLast());
}
}
2.3.ArrayList和linkedList区别
ArrayList基于动态数组方式实现。LinkedList基于链表实现;对于快速访问对象,使用arraylist。需要频繁向集合中插入删除元素使用linkedlist。
3.Set集合
set集合是无序的(插入顺序和存储顺序不一致);set集合不允许包含重复元素;两个比较常用的实现类:HashSet、TressSet。
3.1.HashSet
按照哈希算法来存储元素,具有很好的存取和查找性能。HashSet的特点:不能保证元素的排列顺序,顺序可能与添加顺序不同;HashSet不是同步的,线程不安全;集合元素值可以是null,但最多只能有一个null。注意:set集合不能有重复元素,即使再一次追加“java”,也不会出现两个Java,后面的会覆盖前面的。
public static void main(String[] args) {
HashSet<String> courseSet = new HashSet<String>();// 创建一个空的set集合
courseSet.add("Java");
courseSet.add("Python");
courseSet.add("C语言");
courseSet.add("C++");
System.out.println("您追加的课程有:");
System.out.println(courseSet);//[Java, C++, C语言, Python]
// 迭代操作
Iterator<String> it = courseSet.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(next);
}
System.out.println("---------我是优雅的分隔符------------");
for (String s : courseSet) {
System.out.println(s);
}
}
HashSet基本操作方法同list,区别是它没有get()方法,所以HashSet遍历不能用for循环,但可以用高级|增强for循环,也可以使用迭代器进行迭代。Set集合是怎样保证元素的唯一性的:通过HashCode()和equals()2个方法来进行控制元素的唯一性;如果HashCode()不一样,证明不是同一个对象;如果HashCode一样,证明是同一个对象,然后比较equals方法,这两个方法都是Set集合底层调用的,如果要往Set集合中存储自定义对象,需要重写2个方法。
3.2.TressSet
TreeSet可以实现对集合进行自然排序(按照升序)
TreeSet<Integer> treeSet = new TreeSet<Integer>();
treeSet.add(12);
treeSet.add(1);
treeSet.add(14);
treeSet.add(2);
treeSet.add(9);
System.out.println(treeSet);
注意:只有实现了Comparable接口的类才可以进行排序。反例:
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
// 测试类
public static void main(String[] args) {
TreeSet<Person> treeSet = new TreeSet<Person>();
treeSet.add(new Person(12, "zxs"));
treeSet.add(new Person(8, "lxs"));
treeSet.add(new Person(18, "wxw"));
System.out.println(treeSet);
}
// 输出:Exception in thread "main" java.lang.ClassCastException: com.lee.test3.Person
//cannot be cast to java.lang.Comparable
// 修改
public class Person implements Comparable<Person> {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public int compareTo(Person p) {
if (this.age > p.age ) {
return 1;
}else if (this.age < p.age) {
return -1;
}
return 0;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
}
// 测试
public static void main(String[] args) {
TreeSet<Person> treeSet = new TreeSet<Person>();
treeSet.add(new Person(12, "zxs"));
treeSet.add(new Person(1, "lxs"));
treeSet.add(new Person(18, "wxw"));
for (Person person : treeSet) {
System.out.println(person);
}
}
4.Map集合
存储另一种格式的信息:【1001:zs,2002:ls,3003:ww】用双值集合 Map。Map是一种键值对集合,Map集合中的每一个元素都包含一个键(key)和一个值(value)。
要求:key不允许重复,可以为null,最多只能有一个null;value允许重复,可以为null,可以有多个null;如果添加key-valuemap中已经存在重复的key,则新添加的value会覆盖原来key对应的value。Map接口主要有三个实现类:HashMap、HashTable、TreeMap。
4.1.HashMap
存取效率高,线程不安全。①常用方法
方法 | 返回值 | 描述 |
clear() | Void | 清空集合 |
put(K key,V vlue) | V | 将指定的键值对添加到集合中 |
remove(Object key) | boolean | 从集合中移除指定的键值对 |
replace(K key, V value) | V | 存取效率高,线程不安全。 |
size() | int | 返回集合中键值对的数量 |
containsKey(Object obj) | Boolean | 查看集合中是否包含指定的ke |
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<String, String>();
// 1. put
hashMap.put("s01", "张三");
hashMap.put("s02", "李四");
hashMap.put("s03", "王五");
System.out.println(hashMap);// {s02=李四, s01=张三, s03=王五}
// 2. remove
hashMap.remove("s01");
System.out.println(hashMap);//{s02=李四, s03=王五}
// 3. repalce
hashMap.replace("s02", "李小四");
System.out.println(hashMap);// {s02=李小四, s03=王五}
// 4. size
int size = hashMap.size();
System.out.println(size);// 2
// 5. 获取map集合里面所有的value值,把这些值存在Collection中
Collection<String> values = hashMap.values();
System.out.println(values);// [李小四, 王五]
// 6. 获取map集合中的所有key,把key值放在set集合里面
Set<String> keySet = hashMap.keySet();
System.out.println(keySet);// [s02, s03]
// 7. 查看集合中是否包含指定的key
boolean containsKey = hashMap.containsKey("s02");
System.out.println(containsKey);// true
// 8. 查看集合 中是否包含指定的value
boolean containsValue = hashMap.containsValue("王xiao五");
System.out.println(containsValue);//false
}
例子2合并泛型:
// Map类
public class MapDemo {
public static void main(String[] args) {
Map<String, Person> map = new HashMap<String, Person>();
Person p1 = new Person("小梅", 34, "女");
Person p2 = new Person("大梅", 34, "女");
Person p3 = new Person("红梅", 34, "女");
Person p4 = new Person("紫梅", 34, "女");
// 添加
map.put("军长", p1);
map.put("师长", p2);
map.put("旅长", p3);
map.put("团长", p4);
// map.put("团长", new Person("小红",28,"女"));// 如果key一致的清空心智覆盖旧值
System.out.println(map.size() + "元素:" + map);
System.out.println("----------------");
// 删去
map.remove("军长");
// map.clear();// 清空
System.out.println(map.values());// 获取所有的值
System.out.println("----------------");
// 修改
Person person = map.get("团长");
person.setName("红爱国");
System.out.println("根据key获取对应对象的值:" + person.getName());
System.out.println("----------------");
// 获取
System.out.println(map.keySet());// 获取所有的key
System.out.println(map.get("团长"));
System.out.println(map.values());// 获取所有的值
System.out.println("------遍历----------");
// 遍历
Set<String> set = map.keySet();// 获取所有的key
Iterator<String> kIterator = set.iterator();// 获取迭代器
while (kIterator.hasNext()) {
String key = kIterator.next();
Person person2 = map.get(key);
System.out.println("姓名:" + person2.getName() + ",年龄:" + person2.getAge() + ",性别:" + person2.getSex());
}
// 高级for循环
for (Person p5 : map.values()) {
System.out.println("姓名:" + p5.getName() + ",年龄:" + p5.getAge());
}
System.out.println("--------判断--------");
// 判断
System.out.println(map.containsKey("军长"));// 判断是否包含军长这个key
System.out.println(map.containsValue("随便"));// 判断是否包含随便这个值
System.out.println(map.isEmpty());
}
}
②map集合遍历:
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("百度", "www.baidu.com");
map.put("京东", "www.jd.com");
//方法一:用for循环来遍历
for( Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println( key + ":" + value);
}
// 方法二,通过key查找value
Set<String> keySet = map.keySet();
for (String key : keySet) {
String value = map.get(key);
System.out.println(key + ":" + value);
}
// 方法三,使用迭代器
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
String value = map.get(key);
System.out.println(key + ":" + value);
}
// 方法四
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key);
}
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
}
5.泛型
jdk1.5以后就加了反省提高了集合安全性能。将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性;本质时参数化类型。泛型本质上是提供类型的”类型参数“,也就是参数化类型
6.泛型集合
泛型集合可约束集合内的元素类型;典型泛型集合ArrayList<E>、HashMap<K,V>。其中<E>、<K,V>表示该泛型集合中的数据不再转换为Object。除了指定了集合中的元素类型外,泛型集合和之前血丝的集合的用法完全一样。泛型的好处:1.把运行时期的错误转换到编译时期;2.不用强制类型转换;3.帮我们检查数据类型。
// 主类
public class Person {
private String name;
private int age;
private String sex;
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public Person() {
super();
}
@Override
public String toString() {
return "name:" + this.name + ", age:" + this.age + ", sex:" + this.sex;
}
@Override
public int hashCode() {
return this.getName().hashCode() + age * 28;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person)) {
return false;
}
Person p = (Person) obj;
return this.getName() == p.getName() && this.getAge() == p.getAge();
}
}
// 泛型类
public class FanXinList {
// 非泛型
public void noFanxin() {
List list = new ArrayList();
list.add(new Person("小梅", 34, "女"));
list.add(new Person("小风", 30, "男"));
// list.add("a");//编译通过,--运行出错ClassCastException
for (Object object : list) {
Person person = (Person) object;
System.out.println(person.getName());
}
}
// 泛型,以后用这种
public void fanxin() {
List<Person> list = new ArrayList<Person>();
list.add(new Person("小梅", 34, "女"));
list.add(new Person("小风", 30, "男"));
// list.add("a");//编译不通过
for (Person p : list) {
// Person person = (Person) object;
System.out.println(p);
}
}
public static void main(String[] args) {
FanXinList list = new FanXinList();
list.noFanxin();
System.out.println("------------------");
list.fanxin();
}
}
// HashMap测试
public static void main(String[] args) {
Book book1 = new Book(1, "面向对象程序设计", 8);
Book book2 = new Book(2, "Html从入⻔到放弃", 12);
Book book3 = new Book(3, "数据结构", 30);
HashMap<Integer, Book> books = new HashMap<Integer, Book>();//定义map集合
books.put(1001, book1);
books.put(1002, book2);
books.put(1003, book3);
System.out.println("图书如下:");
System.out.println(books);
ArrayList<Book> bookList = new ArrayList<Book>();//定义一个list集合
bookList.add(book1);
bookList.add(book2);
bookList.add(book3);
System.out.println("图书如下:");
System.out.println(bookList);
}
7.泛型类
泛型类一般用于类中的属性类型不确定的情况。
// Student类
public class Student<N,A,S> {
private N name;//姓名
private A age;//年龄
private S sex;//性别
public Student() {
}
public Student(N name, A age, S sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
// 测试
public static void main(String[] args) {
Student<String, Integer, String> student = new Student<String, Integer,String>("rose", 21, "女");
System.out.println(student);
Student<String, Integer, Character> student2 = new Student<String, Integer,Character>("肉丝", 80, '女');
System.out.println(student2);
Student<Integer, String, String> student3 = new Student<Integer, String,String>(290, "13", "男");
System.out.println(student3);
}
8.泛型方法
一般来说编写Java泛型方法,其返回值类型至少有一个参数类型应该是泛型,而且类型应该是一致的,如果只有返回值类型和参数类型之一使用泛型,那么这个泛型方法的作用意义也就不大了。
public static void main(String[] args) {
Person person = new Person(12, "张三");
Person p = Test.show(person);
System.out.println(p);
Student<String, Integer, String> student = new Student<String, Integer,
String>("zxs", 23, "男");
Student<String, Integer, String> s = Test.show(student);
System.out.println(s);
}
public static<T> T show(T t) {
if ( t != null) {
return t;
}
return null;
}