集合,数组都是对多个数据进行存储操作的结构,简称Java容器。
注意的是:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt , .jpg , .avi , 数据库中)。
数组存储的特点:
集合存储的优点:
Collection接口继承树:
package com.holmes.java07;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
public class CollectionTest2 {
@Test
public void test(){
Collection coll = new ArrayList();
//1. add(Object e):将元素e添加到集合coll中
coll.add("AA");
coll.add("BB");
coll.add(123);
coll.add(new Date());
//2. size():获取添加的元素的个数
System.out.println(coll.size());
//addAll(Collection collName):将collName集合中的元素全部添加到当前的集合中。
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add("CC");
coll.addAll(coll1);
System.out.println(coll);
//3. isEmpty():判断当前集合是否为空(不是判断是null,是判断集合中是否有元素)
System.out.println(coll.isEmpty());//false
Collection coll2 = new ArrayList();
coll2.add(null);
System.out.println(coll2.isEmpty());//false
//4. clear():清空集合元素
coll.clear();
System.out.println(coll.isEmpty());
}
}
package com.holmes.java07;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionTest {
@Test
public void test1(){
Collection coll = new ArrayList();
//这里的123是一个对象
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(false);
coll.add(new Person("hello",22));
Person p = new Person("Jerry",20);
coll.add(p);
//1. contains(Object obj):判断当前集合中是否包含obj
boolean contains = coll.contains(123);
System.out.println(contains);//true
//当然contain()方法比较的不是地址,如创建了两个不同地址,相同内容的String,结果就返回了true。
//原因呢,就是因为String类中重写了equals方法,就是比较内容,所以这里返回true
//额外说一下,equals比较是从头到尾进行比较,比较多少次得看位置在哪里。
System.out.println(coll.contains(new String("Tom")));//true
//对于自己定义的类,如果自己没有重写equals方法,那么就是默认调用父类Object的方法,那就是用 == 判断 , 不是用equals判断, 那就比较的是地址。
System.out.println(coll.contains(new Person("hello",22)));//false
System.out.println(coll.contains(p));//true
//2. containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中。
//Arrays.asList的作用是将数组转化为list。
Collection coll1 = Arrays.asList(123,456);
System.out.println(coll.containsAll(coll1));
}
}
class 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 +
'}';
}
}
package com.holmes.java07;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionTest {
@Test
public void test2(){
//3. remove(Object obj):从当前集合中移除obj元素。
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(new Person("hello",22));
coll.add(false);
coll.remove(123);
System.out.println(coll);
//4. removeAll(Collection collName):从当前集合中移除collName中所有的元素
//意思就是:除去双方交集。
Collection coll1 = Arrays.asList(456, new String("Tom"));
coll.removeAll(coll1);
System.out.println(coll);
}
@Test
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(new Person("hello",22));
coll.add(false);
Collection coll1 = Arrays.asList(123,456,789);
//5. coll.retainAll(collName):取coll和collName的交集,并把交集返给当前集合(coll)
coll.retainAll(coll1);
System.out.println(coll);
//6. equals(Object obj):
Collection coll2 = new ArrayList();
coll2.add(new String("Tom"));
coll2.add(123);
Collection coll3 = new ArrayList();
coll3.add(new String("Tom"));
coll3.add(123);
System.out.println(coll2.equals(coll1));
//需要注意的是equals()方法对于String等类型,都是重写后的比较值,如果用的是Object类型的equals那就是比较地址。
//这样比较是要另外判断
System.out.println(coll3.equals(coll2));
}
}
集合转数组,数组转集合等等:
package com.holmes.java07;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class CollectionTest3 {
@Test
public void test(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(new Person("hello",22));
coll.add(false);
//7. hashCode():返回当前对象的哈希值。
System.out.println(coll.hashCode());
//8. 集合 ==》 数组 toArray():
Object[] arr = coll.toArray();
for (int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
//9. 数组 ==》 集合 Arrays.asList() 调用Arrays类的静态方法asList():
List<String> list = Arrays.asList(new String[]{
"AA", "BB", "CC"});
System.out.println(list);//[AA, BB, CC]
//int这种写法会将123,456整体认为是一个元素
List ints = Arrays.asList(new int[]{
123, 456});
System.out.println(ints);
System.out.println(ints.size());//1
//Integer包装类写法就不会
List ints2 = Arrays.asList(new Integer[]{
123, 456});
System.out.println(ints2.size());
//再个就是传入两个对象,那就是两个元素,不能混淆!
List ints4 = Arrays.asList(new String[]{
"abc","efg"},new String[]{
"hig","kml"});
System.out.println(ints4);
System.out.println(ints4.size());
List ints3 = Arrays.asList(123,456);
System.out.println(ints3);
//9. iterator(): 返回Iterator接口的实例,用于遍历集合元素。
System.out.println(coll.iterator());
}
}
Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,自然实现了Collection接口的结合都有一个iterator()方法,用来返回一个实现了Iterator接口的对象。
Iterator接口的方法有三个:
集合遍历一般如下:
package com.holmes.java07;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Testset {
@Test
public void test(){
Collection col = new ArrayList();
col.add(123);
col.add(456);
col.add(new String("江山如画"));
col.add(false);
//使用iterator遍历集合内容:
Iterator iterator = col.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//iterator的remove()方法:
Iterator iterator1= col.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
if ("江山如画".equals(obj)){
//iterator.remove()方法:也可以移除集合中的元素
iterator1.remove();
}
}
System.out.println(col);
}
}
迭代器remove的两种错误用法:
package com.holmes.java07;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Testset {
@Test
public void test(){
Collection col = new ArrayList();
col.add(123);
col.add(456);
col.add(new String("江山如画"));
col.add(false);
Iterator iterator= col.iterator();
//第一种情况:
//报错!java.lang.IllegalStateException
//while (iterator.hasNext()){
// iterator.remove();
// System.out.println(iterator.next());
//}
//第二种情况:
while (iterator.hasNext()){
iterator.remove();
System.out.println(iterator.next());
iterator.remove();//这里也是不对的!!报错!java.lang.IllegalStateException
}
}
}
list接口下,类定义下,元素存储有序,且可重复。
list接口下有三个类:
ArrayList类:作为List接口的主要实现类;线程不安全的,效率高。底层使用Object[] elementData存储。
ArrayList源码分析:
LinkedList类:底层使用双向链表存储,对于频繁的插入,删除操作,使用此类效率比ArrayList要高。
Vector类:作为List接口的古老实现类;线程安全的,效率低。底层使用Object[] elementData存储。
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class Testset {
@Test
public void test(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add(new String("江山如画"));
list.add(false);
//list.add(int index , Object element):在index位置插入element元素
list.add(1,"AAA");
System.out.println(list);
//list.addAll(int index , Collection elements):从index位置开始将elements中的所有元素添加刀集合中
List list2 = Arrays.asList(1,2,3,4);
list.addAll(3,list2);
System.out.println(list);
//list.indexOf(Object obj):查询obj在集合中的位置返回索引。
int index = list.indexOf(456);
System.out.println(index);
//list.lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置。
list.add(0,"江山如画");
int index2 = list.lastIndexOf("江山如画");
System.out.println(index2);
//list.remove(int index)方法:移除指定index位置的元素,并返回此元素。
Object obj = list.remove(2);
System.out.println(obj);
System.out.println(list);
//list.set(int index , Object element)方法:设置指定index位置的元素为element。
list.set(0,"三国演义");
System.out.println(list);
//list.subList(int fromIndex , int toIndex):返回从fromIndex到toIndex位置的子集合。
List list1 = list.subList(1, 3);
System.out.println(list1);
//list.size():返回当前集合长度
System.out.println(list.size());
//list.get(Int index):返回当前index位置的元素
System.out.println(list.get(0));
}
}
set接口是Colection的子接口,它不允许包含相同的元素,同时它是无序的。
Set接口的实现类:
Set接口中没有额外定义的新方法,使用的都是Collection中声明过的方法。
Set接口的无序性:
Set接口的不可重复性:
add()方法添加元素的原理如下:(重要)
它是先查看存放位置是否相同,不相同直接添加;位置相同的话,就比较hash值相同不相同,hash值不相同就添加;如果hash值相同的话,再比较equals想不想同,不想相同就添加。
Set实现类HashSet的扩容方式:
Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即 “相等的对象必须具有相等的散列码” 。
平时,我们创建的类,最好通过系统直接重写equals()和hashCode()方法:
class Person01 {
private String name;
private int age;
public Person01(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person01 person01 = (Person01) o;
return age == person01.age && Objects.equals(name, person01.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
HashSet:作为Set接口的主要实现类;线程不安全,可以存储null值。
LinkedHashSet:作为HashSet的子类,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据。
优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet。
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class SetTest {
@Test
public void test(){
Set set = new HashSet();
set.add(456);
set.add(123);
set.add("AA");
set.add("CC");
System.out.println(set);
Set set2 = new LinkedHashSet();
set2.add(456);
set2.add(123);
set2.add("AA");
set2.add("CC");
System.out.println(set2);
}
}
首先,TreeSet不能添加不同类的对象!不然报错java.lang.ClassCastException。只能添加相同类的属性。
TreeSet遍历要配合重写toString方法,不然返回的就是地址值。
自然排序就要对TreeSet中的类,让该类实现comparable接口,重写compareTo方法和toString()方法。
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class SetTest {
@Test
public void test(){
TreeSet set = new TreeSet();
set.add(new User("Tom",22));
set.add(new User("Aerry",24));
set.add(new User("Mim",49));
set.add(new User("Mim",36));
set.add(new User("Jack",12));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
class User implements Comparable{
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Object o) {
//按照姓名从小到大排序
if (o instanceof User){
User user = (User)o;
int compare = this.name.compareTo(user.name);
//如果姓名大小相同,则就比较年龄
if (compare != 0){
return compare;
}else {
//这里有Integer的compare比较方法牢记!!
return Integer.compare(this.age,user.age);
}
}else {
throw new RuntimeException("输入的类型不匹配");
}
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
定制排序就是定义comparator作为参数,传给TreeSet。
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class SetTest {
@Test
public void test2(){
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//按照年龄排序:
if (o1 instanceof User && o2 instanceof User){
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else {
throw new RuntimeException("输入的数据类型不匹配");
}
}
};
TreeSet set = new TreeSet(comparator);
set.add(new User("Tom",22));
set.add(new User("Aerry",24));
set.add(new User("Mim",49));
set.add(new User("Mim",36));
set.add(new User("Jack",12));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Map接口:双列数据,存储key-value对的数据 , 类似于数学中的y和x对应。
Map接口实现类:
HashMap:作为Map的主要实现类;线程不安全的,效率高;能存储null的key和value。
LinkedHashMap:它是HashMap的子类,在原有的HashMap底层结构基础上,添加一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap。
Hashtable:(注意这里时小写t) 作为古老的实现类;线程安全的,效率低;不能存储null的key和value。
Properties:常用来处理配置文件,key和value都是String类型。(例如jdbc的Properties文件)。
TreeMap:保证按照添加的key-value对进行排序,实现排序遍历此时要考虑key的自然排序或定制排序。
Map 的结构原理:
JDK 7:
扩容问题,既然涉及到数组,必然有扩容的问题,HashMap默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。
JDK 8:
Map的基本操作方法:
package com.holmes.java07;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class MapTest {
@Test
public void test(){
Map map = new HashMap();
//map.put(Object key , Object value)方法:添加和修改,key,value。
map.put("AA",123);
map.put("BB",456);
map.put("CC",789);
//修改
map.put("AA",342);
System.out.println(map);
Map map2 = new HashMap();
map2.put("KK",453);
map2.put("oo",2342);
//map.putAll(Map map)方法:将m中的所有key—value对存放到当前map中。
map.putAll(map2);
System.out.println(map);
//map.remove(Object key)方法:移除指定key的key-value对,并返回value。
Object value = map.remove("CC");
System.out.println(value);
System.out.println(map);
//map.clear()方法:清空当前map中的所有数据。
map.clear();//注意!清空后不是null
System.out.println(map);
}
@Test
public void test2(){
Map map = new HashMap();
map.put("AA",123);
map.put("BB",456);
map.put("CC",789);
//map.get(Object key)方法:获取指定key对应的value
System.out.println(map.get("CC"));
//map.containsKey(Object key)方法:是否包含指定的key
boolean isExist = map.containsKey("BB");
System.out.println(isExist);
//map.containsValue(Object value)方法:是否包含指定的value
boolean isExist2 = map.containsValue(456);
System.out.println(isExist2);
//map.size()方法:返回map中key-value对的个数
System.out.println(map.size());
//map.isEmpty()方法:判断当前map是否为空
System.out.println(map.isEmpty());
//map.equals(Object obj)方法:判断当前map和参数对象obj是否相等
}
}
元视图的方法:
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class MapTest {
@Test
public void test(){
Map map = new HashMap();
//map.put(Object key , Object value)方法:添加和修改,key,value。
map.put("AA",123);
map.put("BB",456);
map.put("CC",789);
//修改
map.put("AA",342);
System.out.println(map);
Map map2 = new HashMap();
map2.put("KK",453);
map2.put("oo",2342);
//map.putAll(Map map)方法:将m中的所有key—value对存放到当前map中。
map.putAll(map2);
System.out.println(map);
//map.remove(Object key)方法:移除指定key的key-value对,并返回value。
Object value = map.remove("CC");
System.out.println(value);
System.out.println(map);
//map.clear()方法:清空当前map中的所有数据。
map.clear();//注意!清空后不是null
System.out.println(map);
}
@Test
public void test2(){
Map map = new HashMap();
map.put("AA",123);
map.put("BB",456);
map.put("CC",789);
//map.get(Object key)方法:获取指定key对应的value
System.out.println(map.get("CC"));
//map.containsKey(Object key)方法:是否包含指定的key
boolean isExist = map.containsKey("BB");
System.out.println(isExist);
//map.containsValue(Object value)方法:是否包含指定的value
boolean isExist2 = map.containsValue(456);
System.out.println(isExist2);
//map.size()方法:返回map中key-value对的个数
System.out.println(map.size());
//map.isEmpty()方法:判断当前map是否为空
System.out.println(map.isEmpty());
//map.equals(Object obj)方法:判断当前map和参数对象obj是否相等
}
@Test
public void test03(){
Map map = new HashMap();
map.put("AA",123);
map.put("BB",456);
map.put("CC",789);
//遍历所有的key集:keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//遍历所有value集:values()
Collection values = map.values();
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
//遍历所有的key-value:entrySet()
Set entrySet = map.entrySet();
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()){
Object obj = iterator2.next();
//这里要强转一下!!!
//entrySet集合中的元素都是entry。
Map.Entry entry = (Map.Entry)obj;
System.out.println(entry.getKey() + "----->" + entry.getValue());
}
}
}
Set集合的遍历有两种方式:
同样,想TreeMap中添加key-value,要求key必须是由同一个类创建的对象。也要对key进行排序:自然排序 , 定制排序。
自然排序:
package com.holmes.java07;
import org.junit.Test;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
@Test
public void test(){
TreeMap treeMap = new TreeMap();
treeMap.put(new User2("Tom",22),50);
treeMap.put(new User2("Aerry",24),23);
treeMap.put(new User2("Mim",49),43);
treeMap.put(new User2("Mim",36),78);
treeMap.put(new User2("Jack",12),12);
Set entrySet = treeMap.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
Map.Entry entry = (Map.Entry)obj;
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
}
}
class User2 implements Comparable{
private String name;
private int age;
public User2(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public int compareTo(Object o) {
//按照姓名从小到大排序
if (o instanceof User2){
User2 user2 = (User2)o;
int compare = this.name.compareTo(user2.name);
//如果姓名大小相同,则就比较年龄
if (compare != 0){
return compare;
}else {
//这里有Integer的compare比较方法牢记!!
return Integer.compare(this.age,user2.age);
}
}else {
throw new RuntimeException("输入的类型不匹配");
}
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
定制排序:
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class TreeMapTest {
@Test
public void test(){
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User2 && o2 instanceof User2){
User2 u1 = (User2)o1;
User2 u2 = (User2)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else {
throw new RuntimeException("类型不匹配!");
}
}
};
TreeMap treeMap = new TreeMap(comparator);
treeMap.put(new User2("Tom",22),50);
treeMap.put(new User2("Aerry",24),23);
treeMap.put(new User2("Mim",49),43);
treeMap.put(new User2("Mim",36),78);
treeMap.put(new User2("Jack",12),12);
Set entrySet = treeMap.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
Map.Entry entry = (Map.Entry)obj;
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
}
}
class User2{
private String name;
private int age;
public User2(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
首先,Collections 和 Collection不同!Collection是创建集合的接口;而Collections是工具类,负责操作Collection,Map的工具类。
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class CollectionsTest {
@Test
public void test(){
List list = new ArrayList();
list.add(123);
list.add(233);
list.add(23);
list.add(23);
list.add(23);
list.add(73);
list.add(93);
list.add(0);
//查看出现多少次
int frequency = Collections.frequency(list,23);
System.out.println(frequency);
//copy方法会遇到一个异常:java.lang.IndexOutOfBoundsException: Source does not fit in dest
//该异常通过源码得知,它是dest的长度小于list。
List dest = Arrays.asList(new Object[list.size()]);//这种方式很好,相当于里面有list.size数量的null。
//将list的集合内容,复制到dest
Collections.copy(dest,list);
System.out.println(dest);
}
}
package com.holmes.java07;
import org.junit.Test;
import java.util.*;
public class CollectionsTest {
@Test
public void test(){
List list = new ArrayList();
list.add(123);
list.add(233);
list.add(73);
list.add(93);
list.add(0);
//返回的list1就是线程安全的List
List list1 = Collections.synchronizedList(list);
Map map = new HashMap();
map.put("AA",123);
map.put("BB",456);
map.put("CC",789);
//同样map也是一样,这map1就是线程安全的
Map map1 = Collections.synchronizedMap(map);
}
}