目录
1.单列集合Collection
List系列特点:添加的元素是有序(存取顺序相同,不是排序)、值可重复、有索引
Set系列集合:添加的元素是无序、不重复(可用于去重)、无索引
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>(); //多态创建对象
coll.add("A");
coll.add("B");
coll.add("C");
System.out.println(coll);
}
//输出为[A, B, C]
在 Java 中,Collection
接口的很多实现类(如ArrayList
)都重写了Object
类的toString()
方法。
当你使用System.out.println(coll)
时,实际上调用的是coll
这个集合对象的toString()
方法。这个重写后的toString()
方法会遍历集合中的元素,并以特定的格式(如[元素1, 元素2,...]
)返回集合的内容字符串,而不是默认的对象地址值。
如果没有重写toString()
方法,那么打印对象时会输出对象的内存地址值,类似java.util.ArrayList@hashCode
这样的形式。
public static void main(String[] args) {
Collection<girlFriend> coll = new ArrayList<>();
girlFriend g1 = new girlFriend("1", 19, 1.68);
girlFriend g2 = new girlFriend("2", 19, 1.70);
girlFriend g3 = new girlFriend("3", 18, 1.78);
coll.add(g1);
coll.add(g2);
coll.add(g3);
girlFriend g4 = new girlFriend("3", 18, 1.78);
System.out.println(coll.contains(g4)); //false
}
因为contains方法在底层依赖equals方法判对象是否一致的。如果存的是自定义对象,没有重写equals方法,那么默认使用object类中的equals方法进行判断,而object类中equals方法,依赖地址值进行判断,比较String类型不用重写equals是因为Java已经重写好了。
1.1集合遍历
由于普通for循环的遍历方式是基于索引的,但是set类型的是没有索引的,所以需要其他通用遍历方式,有三种:
- 迭代器遍历
- 增强for遍历
- Lambda表达式遍历
public static void main(String[] args) {
Collection<girlFriend> coll = new ArrayList<>();
girlFriend g1 = new girlFriend("1", 19, 1.68);
girlFriend g2 = new girlFriend("2", 19, 1.70);
girlFriend g3 = new girlFriend("3", 18, 1.78);
coll.add(g1);
coll.add(g2);
coll.add(g3);
Iterator it = coll.iterator(); //创建指针
while (it.hasNext()) { //判断当前位置是否有元素
girlFriend g5 = it.next(); //获取元素并移动指针
System.out.println(g5);
}
}
//输出为:
//1 19 1.68
//2 19 1.7
//3 18 1.78
迭代器遍历注意事项:
- 指针指向最后仍然it.next()的话会报错NoSuchElementException
- 迭代器遍历完毕,指针不会复位
- 循环中只能用一次next方法迭代器,不然会在一次循环中出现报错NoSuchElementException
- 遍历时(while循环里),不能用集合的方法进行增加或删除,应该用迭代器的it.remove()方法或者创建列表迭代器ListItertor,调用它的add方法
增强for循环遍历
- 增强for的底层就是迭代器,为了简化迭代器的代码书写的
- 它是JDK5之后出现的,其内部原理就是一个Iterator迭代器
- 所有的单列集合和数组才能用增强for进行遍历
for(String s : list) { System.out.println(s); }
lambda表达式遍历
得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式
//匿名内部类格式
coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println();
}
});
//lambda表达式
coll.forEach(s -> System.out.println(s));
1.2 list特有的方法
由于list相比于set多了索引的特点,所以多了一些索引相关的方法,比如list.remove(1);优先是删除索引为1的元素,为什么呢?
因为在调用方法的时候,如果方法出现了重载现象,优先调用实参跟形参类型一致的那个方法。list.remove(1)中的1默认是基本数据类型int,所以优先调用remove(int i)方法,想要删除值为1的元素需要手动装箱。
Integer i = Integer.valueOf(1);
list.remove(i);
2.双列集合Map
- 双列集合一次需要存一对数据,分别为键和值
- 键不能重复,值可以重复
键和值是一一对应的,每一个键只能找到自己对应的值 - 键+值这个整体 我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
3.Arrays操作数组工具类
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
String s = Arrays.toString(arr);
System.out.println(s);
int a = Arrays.binarySearch(arr, 3);
System.out.println(a);
Integer[] arr2 = {2, 1, 3, 6, 5, 7, 8, 10, 4, 9};
Arrays.sort(arr2); //默认为升序排序
System.out.println(Arrays.toString(arr2));
Arrays.sort(arr2, new Comparator<Integer>() { //匿名内部类,重写接口方法改为降序
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; //o1 - o2升序;o2 - o1降序
}
});
System.out.println(Arrays.toString(arr2));
}
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//2
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
如果要使用Arrays.toString方法转换对象类型,需要重写toString方法,例如有一个girlFriend的Javabean类,像下面这样直接调用Arrays.toString()方法打印的是girlFriend[]数组中g1, g2, g3三个对象的地址值。
public static void main(String[] args) {
girlFriend g1 = new girlFriend("1", 19, 1.68);
girlFriend g2 = new girlFriend("2", 19, 1.70);
girlFriend g3 = new girlFriend("3", 18, 1.78);
girlFriend[] arr = {g1, g2, g3};
Arrays.sort(arr, (girlFriend o1, girlFriend o2)->{
double temp = o1.getAge() - o2.getAge();
temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
if(temp > 0){
return 1;
}else if(temp < 0){
return -1;
}else {
return 0;
}
});
System.out.println(Arrays.toString(arr));
}
class girlFriend{
@Override
public String toString() {
return this.name + " " + this.age + " " + this.height;
}
}
//在Javabean类中重写toString()方法再次调用输出为
//[3 18 1.78, 1 19 1.68, 2 19 1.7]
4.lambda表达式
在上面我们用匿名内部类实现接口,但是我们觉得这个写法太复杂了,所以发明了lambda表达式来简化匿名内部类的书写,Lambda表达式是JDK 8开始后的一种新语法形式,注意:
- Lambda表达式可以用来简化匿名内部类的书写
- Lambda表达式只能简化函数式接口的匿名内部类的写法
- 函数式接口:有且仅有一个抽象方法的接口叫做函数式接口,接口上方可以加@Functionalinterface注解
public static void main(String[] args) {
Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Arrays.sort(arr, new Comparator<Integer>() { //匿名内部类,重写接口方法改为降序
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; //o1 - o2升序;o2 - o1降序
}
});
//lambda表达式,把多余的部分都省略
Arrays.sort(arr, (Integer o1, Integer o2)->{
return o2 - o1;
});
//lambda表达式省略写法,大量简化代码
Arrays.sort(arr, (o1, o2)->o2 - o1);
}