知识体系结构
容器概念
容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。
- 容器,就是可以容纳其他Java对象的对象。Java Collections Framework(JCF)为Java开发者提供了通用的容器,其始于JDK 1.2,优点是:
- 降低编程难度
- 提高程序性能
- 提高API间的互操作性
- 降低学习难度
- 降低设计和实现相关API的难度
- 增加程序的重用性
Java容器里只能放对象,对于基本类型(int, long, float, double等),需要将其包装成对象类型后(Integer, Long, Float, Double等)才能放到容器里。很多时候拆包装和解包装能够自动完成。这虽然会导致额外的性能和空间开销,但简化了设计和编程
常见集合框架解读
Collection接口:
Collection是所有集合的顶级接口,Collection下面有多种实现类,因此我们有更多的数据结构可供选择。
Collection常见子接口:
1.java.util.List:线性表.是可重复集合,并且有序。
2.java.util.Set:不可重复的集合,大部分实现类是无序的。
注意:这里可重复指的是集合中的元素是否可以重复,而判定重复元素的标准是依靠元素自身equals比较的结果.为true就认为是重复元素.Collection内的常用方法
1.boolean add(E e) :向当前集合中添加一个元素.当元素成功添加后返回true
2.int size():返回当前集合的元素个数
3.boolean isEmpty():判断当前集合是否为空集(不含有任何元素)
4.void clear():清空集合public static void main(String[] args){
Collection c = new ArrayList();
c.add("one");
c.add("two");
c.add("three");
c.add("four");
c.add("five");
System.out.println(c);
int size = c.size();
System.out.println("size:"+size);
boolean isEmpty = c.isEmpty();
System.out.println("是否为空集:"+isEmpty);
c.clear();
System.out.println(c);
System.out.println("size:"+c.size());//0
System.out.println("是否为空集:"+c.isEmpty());
}
- 集合与元素equals方法相关的方法
4.boolean contains(Object o) :
判断集合是否包含给定元素.判断依据是看给定元素是否存在与集合元素存在equals比较为true的情况,存在则认为包含。
5.boolean remove(Object o):
remove方法是从集合中删除给定元素.删除也是删除与给定元素equals比较为true的元素.如果集合中存在多个重复的元素,那么仅删除第一个
public static void main(String[] args){
Collection c = new ArrayList();
c.add(new Point(1,2));
c.add(new Point(3,4));
c.add(new Point(5,6));
c.add(new Point(7,8));
c.add(new Point(9,0));
System.out.println(c);
Point p = new Point(1,2);
boolean contains = c.contains(p);
System.out.println("是否包含p对象:"+contains);
c.remove(p);
System.out.println(c);
}
集合元素的修改
集合只能存放引用类型元素,并且存放的是元素的引用
public static void main(String[] args){ Point p = new Point(1,2); Collection c = new ArrayList(); c.add(p); System.out.println("p:"+p);//(1,2) System.out.println("c:"+c);//[(1,2)] p.setX(2); System.out.println("p:"+p);//(2,2) System.out.println("c:"+c);//[(2,2)] }
集合间的操作
- boolean addAll(Collection c):将给定集合中的所有元素添加到当前集合中.当前集合发生了改变就返回true.
- boolean containsAll(Collection c):判断当前集合是否包含给定集合中的所有元素
- boolean removeAll(Collection c):删除当前集合中与给定集合的共有元素(删交集),并且返回一个boolean
- new HashSet():HashSet是无序集,并且不可以存放重复元素.
集合的遍历
Collection提供了统一的遍历集合方式:迭代器模式 Iterator iterator( ):该方法会获取一个用于遍历当前集合元素的迭代器.
Iterator接口
- 迭代器接口,定义了迭代器遍历集合的相关操作.
- 不同的集合都实现了一个用于遍历自身元素的迭代器实现类,我们无需记住它们的名字,用多态的角度把他们看做为Iterator即可.
- 迭代器遍历集合遵循的步骤为:问,取,删.其中删除元素不是必要操作
- 迭代器遍历过程中不得通过集合的方法增删元素
public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); //获取遍历该集合的迭代器 Iterator it = c.iterator(); //问,是否有下一个 while(it.hasNext()){ //取 String str = (String)it.next(); System.out.println(str); //删 if("#".equals(str)){ //迭代器要求遍历的过程中不得通过集合的方法增删元素,否则会 //抛出异常:java.util.ConcurrentModificationException //c.remove(str);会报错 //迭代器提供了remove方法,将next方法得到的元素从集合中删除. it.remove(); } } }
增强型for循环
增强型for循环:也称为新循环,使得我们可以使用相同的语法遍历集合或数组。 foreach:
for(元素类型 变量名 : 集合或数组){
循环体
}
//新循环的语法是编译器认可的,而不是虚拟机.编译器在编译代码时会把新循环遍历
//数组改为普通的for循环遍历.
//新循环遍历集合就是迭代器遍历.编译器会改为迭代器.
//所以注意!不要在使用新循环遍历集合的过程中使用集合的方法增删元素,否则会抛出异常!
for(String str : array){
System.out.println(str);
}
List集合
- List接口,继承自Collection.
- List集合是可重复集,并且有序,提供了一套可以通过下标操作元素的方法
- 常用实现类:
ArrayList:内部使用数组实现,查询性能更好.
LinkedList:内部使用链表实现,首尾增删元素性能更好.
List集合常见方法
1. get( )与set( )
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// List<String> list = new LinkedList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);
/*
E get(int index)
获取当前List集合中指定下标处对应的元素
*/
//获取集合中第三个元素
String str = list.get(2);//arr[2]
System.out.println(str);
//for循环遍历List集合
for(int i=0;i<list.size();i++){
str = list.get(i);
System.out.println(str);
}
/*
E set(int index,E e)
将给定元素设置到指定位置上,返回值为该位置原来对应的元素.
替换操作
*/
//将下标为1的元素换成six
String old = list.set(1,"six");//[one,six,three,four,five]
System.out.println(list);
System.out.println("被替换的元素是:"+old);
/*
将集合反转
*/
for(int i=0;i<list.size()/2;i++){
//获取正数位置上的元素
String e = list.get(i);
//将正数位置的元素放到倒数位置上
e = list.set(list.size()-1-i,e);
//再将原倒数位置上的元素设置到正数位置上
list.set(i,e);
}
System.out.println(list);//[five,four,three,six,one]
/*
java.util.Collections是集合的工具类,里面提供很多静态方法,可以方便
操作集合.
*/
Collections.reverse(list);//反转List集合
System.out.println(list);
}
2. add()和remove()
原数组:[one,two,three,four,five]
/*
void add(int index,E e)
将给定元素插入到指定位置
*/
list.add(2,"six");
System.out.println(list);//[one,two,six,three,four,five]
/*
E remove(int index)
删除并返回给定位置上的元素
*/
String old = list.remove(3);//[one,two,six,four,five] 删除集合中第四个元素
System.out.println(list);
System.out.println("被删除的元素是:"+old);
3. subList()方法
:::success List subList(int start,int end):获取当前集合中指定范围内的子集,两个数字表示下标范围,含头不含尾。 ::: 注意:对子集的操作就是对原集合对应元素的操作!!!
原集合:[0,1,2,3,4,5,6,7,8,9]
//获取[3-7](含头不含尾)
List<Integer> subList = list.subList(3,8);
System.out.println(subList);
//将子集元素扩大10倍,遍历
for(int i=0;i<subList.size();i++){
int n = subList.get(i);
n = n * 10;
subList.set(i,n);
}
//[30,40,50,60,70]
System.out.println(subList);
//对子集的操作就是对原集合对应元素的操作!!!
System.out.println(list);
//删除list集合中[2-8]
list.subList(2,9).clear();
System.out.println(list);
集合与数组的转换
集合转换为数组
Collection提供了一个方法:toArray,可以将当前集合转换为一个数组
public static void main(String[] args) { Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); System.out.println(c); // Object[] array = c.toArray();//不常用 /* 该toArray方法要求传入一个数组.方法内部会将给定元素存入该数组并将其返回. 如果给定的数组长度小于集合的size,则该方法会根据给定的数组类型自行创建一个 与集合size一致的数组并将元素存入后返回. */ String[] array = c.toArray(new String[c.size()]); System.out.println(array.length); System.out.println(Arrays.toString(array)); }
数组转换为List集合
数组的工具类Arrays提供了一个静态方法asList(),可以将一个数组转换为一个List集合,
- 这个集合是跟数组绑定的,
- 数组转换出来的集合,对其元素操作就是对原数组对应元素的操作
- 由于数组定长,所以集合会改变元素个数的操作都不支持:UnsupportedOperationException。
若希望对元素做增删操作,则需要自行再创建一个集合,并包含数组转换的集合中的所有元素即可。
public static void main(String[] args) { String[] array = {"one","two","three","four"}; List<String> list = Arrays.asList(array); System.out.println(list); //修改集合现有元素 list.set(1,"six"); System.out.println(list); //数组转换出来的集合,对其元素操作就是对原数组对应元素的操作 System.out.println(Arrays.toString(array)); //list.add("five"); /* 所有的集合都支持一个参数为Collection类型的构造方法,该构造方法的作用是创建 当前集合的同时包含给定集合中的所有元素 */ //创建一个ArrayList的同时包含给定的集合"list"中的所有元素 List<String> list2 = new ArrayList<>(list); System.out.println(list2); list2.add("five"); System.out.println(list2); }
集合的排序
:::success Collections类:Collections是集合的工具类,里面定义了很多静态方法用于操作集合.
Collections.sort(List list)方法:可以对List集合进行自然排序(从小到大) :::public static void main(String[] args) { List<Integer> list = new ArrayList<>(); Random random = new Random(); for(int i=0;i<10;i++){ list.add(random.nextInt(100)); } System.out.println(list); //排序 Collections.sort(list); System.out.println(list); //乱序 Collections.shuffle(list); System.out.println(list); }
侵入性解读:
实际开发中,我们并不会让我们自己定义的类(如果该类作为集合元素使用)去实现Comparable接口,因为这对我们的程序有侵入性.
侵入性:当我们调用某个API功能时,其要求我们为其修改其他额外的代码,这个现象就是侵入性.侵入性越强的API越不利于程序的后期可维护性.应当尽量避免. ```java import java.util.ArrayList; import java.util.Collections; import java.util.List;
/**
- 排序自定义类型元素
*/
public class SortListDemo2 {
public static void main(String[] args) {
} } ```List<Point> list = new ArrayList<>(); list.add(new Point(3,5)); list.add(new Point(7,9)); list.add(new Point(1,1)); list.add(new Point(8,3)); list.add(new Point(2,6)); System.out.println(list); /* 编译不通过的原因: Collections.sort(List list)该方法要求集合中的元素类型必须实现接口:Comparable, 该接口中有一个抽象方法compareTo,这个方法用来定义元素之间比较大小的规则. 所以只有实现了该接口的元素才能利用这个方法比较出大小进而实现排序 操作. */ Collections.sort(list);//编译不通过 compare比较 comparable可以比较的 System.out.println(list);
重载的Collections.sort(List list,Comparator c)方法
```java import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List;
/**
排序自定义类型元素 */ public class SortListDemo2 { public static void main(String[] args) {
List<Point> list = new ArrayList<>(); list.add(new Point(3,5)); list.add(new Point(7,9)); list.add(new Point(1,1)); list.add(new Point(8,3)); list.add(new Point(2,6)); System.out.println(list); //Collections.sort(list);//编译不通过 compare比较 comparable可以比较的 /* Collections.sort(List list,Comparator c) 重载的sort方法要求我们再传入一个Comparator"比较器",该比较器用来为集合元素 临时定义一种比较规则,从而将List集合中的元素通过该比较器比较大小后进行排序. Comparator是一个接口,实际应用中我们需要实现该接口为集合元素提供比较规则. */ Comparator<Point> c = new Comparator<Point>() { /** * compare方法用来定义两个参数o1,o2的大小关系 * 返回值用来表示o1与o2的大小关系 * 当返回值>0时,应当表示的含义是o1>o2 * 当返回值<0时,表示o1<o2 * 当返回值=0时,表示o1与o2相等 */ public int compare(Point o1, Point o2) { int olen1 = o1.getX()*o1.getX()+o1.getY()*o1.getY(); int olen2 = o2.getX()*o2.getX()+o2.getY()*o2.getY(); return olen1-olen2; } }; Collections.sort(list,c); System.out.println(list);
最终没有侵入性的写法
```java import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List;
/**
排序自定义类型元素 */ public class SortListDemo2 { public static void main(String[] args) {
List<Point> list = new ArrayList<>(); list.add(new Point(3,5)); list.add(new Point(7,9)); list.add(new Point(1,1)); list.add(new Point(8,3)); list.add(new Point(2,6)); System.out.println(list); Collections.sort(list,new Comparator<Point>() { public int compare(Point o1, Point o2) { int olen1 = o1.getX()*o1.getX()+o1.getY()*o1.getY(); int olen2 = o2.getX()*o2.getX()+o2.getY()*o2.getY(); return olen1-olen2; } }); System.out.println(list);
排序字符串
java中提供的类,如:String,包装类都实现了Comparable接口,但有时候这些比较规则不能满足我们的排序需求时,同样可以临时提供一种比较规则来进行排序. ```java import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List;
public class SortListDemo3 {
public static void main(String[] args) {
List
System.out.println(list);
Collections.sort(list);
//使用重载的sort方法,定义一个比较器,按照字数多少排序。
Collections.sort(list,(s1,s2)->s1.length()-s2.length());
// Collections.sort(list, Comparator.comparingInt(String::length));超纲写法 System.out.println(list); } }
<a name="k9vzQ"></a>
## Map 查找表
<a name="qXEiJ"></a>
### 定义:
:::success
- Map体现的结构是一个多行两列的表格,其中左列称为key,右列称为value.
:::
1. Map总是成对保存数据,并且总是根据key获取对应的value.因此我们可以将查询的条件作为key查询对应的结果作为value保存到Map中.
1. Map有一个要求:key不允许重复(equals比较的结果)
<a name="mfKOL"></a>
### Map接口:
> Map接口,是所有Map的顶级接口,规定了Map的相关功能.有以下常用实现类:
1. HashMap:称为散列表,使用散列算法实现的Map,当今查询速度最快的数据结构.
1. TreeMap:使用二叉树实现的Map
<a name="WhH86"></a>
### 常用方法:
<a name="fswlz"></a>
#### V put(K k ,V v)
将给定的键值对存入Map中.由于Map要求key不允许重复,若使用已有的key存入value<br /> 时则为替换value操作.返回值为原value.否则返回值为null<br />** 注:**<br /> 如果Map的value是包装类类型时,在接受value值的时候一定用包装类类型的变量<br /> 接受,避免因为自动拆箱出现空指针.
<a name="joZtz"></a>
#### V get(Object key)
根据给定的key获取对应的value,如果给定的key不存在则返回值为null
<a name="pwgtP"></a>
#### V remove(Object key)
删除给定的key所对应的键值对,返回值为该key对应的value
<a name="JDDJp"></a>
#### boolean containsKey(Object key)
判断当前Map是否包含给定的key
<a name="Z2yT3"></a>
#### boolean containsValue(Object value)
判断当前Map是否包含给定的value
```java
import java.util.HashMap;
import java.util.Map;
/**
* Map 查找表
*/
public class MapDemo {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
/*
V put(K k ,V v)
将给定的键值对存入Map中.由于Map要求key不允许重复,若使用已有的key存入value
时则为替换value操作.返回值为原value.否则返回值为null
注:
如果Map的value是包装类类型时,在接受value值的时候一定用包装类类型的变量
接受,避免因为自动拆箱出现空指针.
*/
Integer num = map.put("语文",99);
System.out.println(num);
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);
System.out.println(map);
num = map.put("数学",60);//替换了value
System.out.println(map);
System.out.println("被替换的value:"+num);
/*
V get(Object key)
根据给定的key获取对应的value,如果给定的key不存在则返回值为null
*/
num = map.get("语文");
System.out.println("语文:"+num);
num = map.get("体育");
System.out.println("体育:"+num);
/*
V remove(Object key)
删除给定的key所对应的键值对,返回值为该key对应的value
*/
num = map.remove("英语");
System.out.println(map);
System.out.println("被删除的英语对应的value:"+num);
//每组键值对算一个元素
int size = map.size();
System.out.println("size:"+size);
/*
boolean containsKey(Object key)
判断当前Map是否包含给定的key
boolean containsValue(Object value)
判断当前Map是否包含给定的value
*/
boolean ck = map.containsKey("语文");//判断Map是否包含key:"语文"
boolean cv = map.containsValue(97);//判断Map是否包含value:97
System.out.println("包含key:"+ck);
System.out.println("包含value:"+cv);
}
}
遍历方式:
- 遍历所有的key
- 遍历所有的键值对
- 遍历所有的value(相对不常用)
Set keySet():遍历所有的key
将当前Map中所有的key以一个Set集合形式返回.遍历该集合等同于遍历所有的key
Set entrySet():遍历每一组键值对
将当前Map中每一组键值对以一个Entry实例保存并最终存入Set集合后返回.<br /> java.util.Map.Entry<br /> Entry的每一个实例表示一组键值对.提供了两个常用方法:<br /> K getKey() V getValue
forEach方法
map.forEach((k,v)-> System.out.println(k+”:”+v));
Collection values()
将当前Map中所有的value以一个集合形式返回
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的遍历
*/
public class MapDemo2 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("语文",99);
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);
System.out.println(map);
/*
遍历所有的key
Set<K> keySet()
将当前Map中所有的key以一个Set集合形式返回.遍历该集合等同于遍历所有的key
*/
Set<String> keySet = map.keySet();
// for(String key : keySet){
// System.out.println("key:"+key);
// }
keySet.forEach(k-> System.out.println(k));
/*
遍历每一组键值对
Set<Entry> entrySet()
将当前Map中每一组键值对以一个Entry实例保存并最终存入Set集合后返回.
java.util.Map.Entry
Entry的每一个实例表示一组键值对.提供了两个常用方法:
K getKey() V getValue()
*/
Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
for(Map.Entry<String,Integer> e : entrySet){
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key+":"+value);
}
/*
JDK8之后,Map也提供了forEach方法,用lambda表达式遍历
*/
map.forEach((k,v)-> System.out.println(k+":"+v));
/*
遍历所有的value
Collection<V> values()
将当前Map中所有的value以一个集合形式返回
*/
Collection<Integer> values = map.values();
values.forEach(v-> System.out.println("value:"+v));
}
}