实训笔记6.16
6.16
一、座右铭
我的故事你说,我的文字我落,我值几两你定,我去何方我挑。
二、知识回顾
2.1 Java泛型
2.1.1 泛型是用来提高代码效率,解决多态中向下转型的ClassCastException
2.1.2 泛型都是引用数据类型的,如果使用泛型的时候没有指定泛型的类型,泛型会当作Object类型来处理
2.1.3 泛型的声明语法和使用语法
- 类上的泛型
public class ClassName<T> {类中的任何一个位置去使用}
使用两种方式
1.1 创建类的对象的时候指定泛型的类型
ClassName<Integer> c = new ClassName<integer>();
ClassName<integer> c = new ClassName<>();
1.2 子类继承父类的时候去使用
class Son extends ClassName <integer>{}
1.3 带有泛型的类当作方法的形参或者返回值的时候也可以使用
public ClassName<Integer> demp(ClassName<Double> d){}
如果泛型当作方法的形参或者返回值时候,还是无法确定泛型的类型,那么我们也可以通过泛型的通配符、泛型上限和下限限制泛型的类型
- 方法上的泛型
使用场景
一个类中只有这个方法的返回值类型或者是形参列表不确定,那么我们按道理可以给类来声明泛型,然后让方法来使用,但是没必要……浪费,Java就专门为这种特殊情况提供了一个方法的泛型
public <T,V> T methodName (T t,V v) {}
使用:methodName(1,2)
- 接口上的泛型
tips:类上的的泛型和接口上的泛型不能使用在静态内容
三、Java集合体系
3.1 概念
Java集合和数组一样,都是存放一组相同类型数的容器,Java集合和数组的不同在于以下几点
-
虽然Java和数组都是存放一组相同类型的数据,但是数组是任何一种类型都可以存储,集合只能存放引用数据类型的数据(集合底层使用泛型来定义存储的数据类型)
-
数组有一个长度,长度一旦确定不可改变,Java集合容量没有限制-自动扩容的
【补充】StringBuffer、StringBuilder底层也可以自动扩容:借助Arrays.copyof(),底层又借助了System.arrayCopy()
3.2 集合分类-java.util
3.2.1 在Java当中,提供了各种各样的集合用来满足不同的业务需求
3.2.2单列集合——一条数据只有一列
所有的单列集合都是Collection接口的子类,Collection封装了很多单列集合共有的方法,只不过这些方法基本上都是抽象方法
Collection接口给我们提供的单列集合常用的方法
方法名 | 作用 |
---|---|
size():int | 获取集合存放的元素个数 |
isEmpty():boolean | 判断集合是否为空集合 |
contains(Object):boolean | 判断集合是否包含该元素 |
iterator():Iterator<E> |
获取集合的迭代器,用于遍历集合 |
toArray():Object[] | 将集合转换为数组 |
toArray(T[]):T[] | 讲集合转换为指定类型的数组 |
add(E):boolean | 将元素加到集合当中 |
remove(object) | 移除某个元素 |
clear() | 清空集合 |
代码示例
public class Demo {
public static void main(String[] args) {
Collection<Integer> col = new ArrayList<>();
System.out.println(col.size());//0
System.out.println(col.isEmpty());//true
col.add(1);
System.out.println(col.contains(1));//true
col.add(2);
/**
* 遍历集合:两种遍历方式
* 1、增强的for循环
* 2、迭代器也可以遍历: 获取迭代器 借助迭代器的hasNext判断有没有下一条数据 然后再借助next获取下一条数据
*/
for(Integer ele : col) {
System.out.println(ele);//1
}
Iterator<Integer> iterator = col.iterator();
while(iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next);//2 1 2
}
col.remove(1);
System.out.println(col);//[2]
col.clear();
System.out.println(col);//[]
// Object[] array = col.toArray();
// System.out.println(Arrays.toString(array));//[]
// Integer[] array = new Integer[col.size()];
// col.toArray(array);
// System.out.println(Arrays.toString(array));//[]
}
}
单列集合又细分为两种
-
List接口类型的集合:List接口类型的集合:所有数据可以重复,而且是有序的–加入有序
代码示例
List<Integer> list = new ArrayList<>(); list.add(1); list.set(0,1); System.out.println(list);//[1] for (int i = 0; i < list.size(); i++) { Integer integer = list.get(i); System.out.println(integer);//1 }
-
Vector:一般扩容为原先的2倍,如果有扩容因子,那么就是扩容为原先的长度+扩容因子
List的实现类: list的实现类除了LinkedList增加了几个特殊方法以外,Vector和ArrayList基本没在接口之上再增加新的方法。
Vector底层扩容的时候默认扩容为原先的一倍,但是如果扩容因子不为0的话,那么扩容为旧数组长度+扩容因子
方法名 说明 Vector<>(): 无参构造器底层调用this(10),
底层先给你创建一个容量为10的数组存放元素,
扩容因子也是0Vector(int initialCapacity): 有参构造器底层调用this(initialCapacity,0):
底层给你创建一个指定长度的数组,
顺序再指定一个扩容因子为0Vector(int initialCapacity,
int capacityIncrement):底层创建一个指定长度的数组,
指定数值的扩容因子代码示例
Vector<Integer> vec = new Vector<>(); vec.add(1); vec.add(1,2); vec.add(3); vec.add(1); System.out.println(vec);//[1, 2, 3, 1]
-
ArrayList:一般扩容为原先的1.5倍
ArrayList创建:ArrayList(): 底层会创建一个长度为10的数组存放数据,但是一定要注意,长度为10的数组并不是再构造器中直接创建的,而是再集合第一次增加元素的时候创建的
-
ArrayList(int capacity)
-
ArrayList(Collection)
-
底层借助数组实现,数据可以重复,而且有序…加入有序
代码示例
ArrayList<Integer> list = new ArrayList<>(); list.addAll(new ArrayList<Integer>(20));
-
LinkedList:扩容是通过Node内部类完成
LinkedList也是JavaList集合体系的一个实现类,只不过LinkedList底层不是借助数组来存储数据的而是借助双向链表去存储数据,而且通过双向链表维护数据的加入顺序。
LinkedList因为使用双向链表来存储数据,在类中提前把链表的头部节点和尾部节点已经提前定义出来了,因此LinkedList在Collection、List接口之上提供了四个比较特殊的方法,可以直接对集合的头部节点和尾节点进行操作
方法名 addFirst(E) addLast(E) add(E)–默认在尾部增加数据 removeFirst() removeLast() LinkedList一般用在频繁的修改和数据变更下。ArrayList更适合使用在频繁的数据查找下。
底层借助双向链表来实现,数据可以重复,而且加入有序
代码示例
LinkedList<Integer> list = new LinkedList<>(); list.add(1);
-
-
set接口类型的集合:数据不允许重复,而且数据不一定有序
Set集合也是一个单列集合,是Collection的子接口。
Set接口集合体系没有提供任何的多余的方法,使用的集合增加数据方法都是Collection提供的
Set接口集合虽然没有提供多余的方法,但是提供了存储数据的特性:元素不能重复
Set集合判断两个元素是否重复借助Java的两个方法来完成的:
方法名 说明 hashCode 返回一个整数类型的值,默认返回的是这个对象在堆区的地址 equals方法 比较两个对象是否值相等的,默认情况下比较两个对象的地址相等 代码示例
Set<Integer> set = new TreeSet<>(); set.add(1); set.add(1); set.add(1); set.add(10); set.add(19); set.add(8); set.add(7); System.out.println(set);//[1, 7, 8, 10, 19]
【注意】:在Java当中有要求的,如果两个对象通过equals返回比较为true的话,那么两个对象的hashCode方法必须返回相同的值。
如果两个对象的hashCode值不一样那么两个对象一定不相等,如果两个对象的hashCode值一样的,不一定相等。
判断规则:
(1)set集合在添加元素时,先通过待添加元素的hashCode值和集合中的每一个元素的hashCode值做比较,如果hashCode值都不一样,那么认为元素 不重复 ,直接添加到集合当中了
(2)如果hashCode值重复了,那么调用equals方法看返回结果,返回结果为true那么 重复 不添加如果返回结果为false那么就是 不重复 添加-
HashSet:不允许重复,元素是无序的
代码示例
Set<Student> set = new HashSet<>(); Student stu = new Student("zs", 18, "s001"); Student stu1 = new Student("zs", 18, "s001"); set.add(stu); set.add(stu1); System.out.println(set);//[Student [name=zs, age=18, sno=s001]]
-
LinkedHashSet:不允许重复,但是元素是有序的,加入有序
-
TreeSet:不允许重复,但是元素有序的,大小有序,treeset集合中元素必须有比较器
代码示例
Set<Student> set = new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { if(o1.getAge()>o2.getAge()) { return 1; }else if(o1.getAge()<o2.getAge()) { return -1; }else { return 0; } } }); Student stu = new Student("zs", 18, "s001"); Student stu1 = new Student("ls", 20, "s002"); Student stu2 = new Student("ww", 15, "s003"); set.add(stu); set.add(stu1); set.add(stu2); System.out.println(set);//[Student [name=ww, age=15, sno=s003], Student [name=zs, age=18, sno=s001], Student [name=ls, age=20, sno=s002]]
-
List接口、set接口:都是Collection接口的一个子接口
3.2.3 双列集合——一条数据有两列
所有的双列集合都是Map接口的子类