集合
1 集合
1.1 Vector(了解)
是JDK1.0出现,最早的集合。大部分方法都和list接口中的方法重复了。
- 内部的数据结构是数组
- 查询速度快
- 增删速度慢
- 线程安全
ArrayList 比 vector更先进,被 ArrayList 取代
默认的初始化容量是10,每次扩容都是原来容量的一倍
如果设置了容量增量,每次扩容是原来容量 + 容量增量
public static void main(String[] args) {
Vector<String> vector = new Vector<>(10,5);
vector.add("abc");
vector.add("ayy");
vector.add("awq");
vector.add("hjk");
// 获取的是迭代器 迭代器是用于遍历集合的
Enumeration<String> elements = vector.elements();
// 判断是否有更多的元素
while (elements.hasMoreElements()){
// 获取下一个元素
String s = elements.nextElement();
System.out.println(s);
}
// 获取容量
System.out.println(vector.capacity());
}
1.2 List接口中的sort方法
public static void main(String[] args) {
// 创建一个列表
List<String> list = new ArrayList<>();
list.add("adf");
list.add("defe");
list.add("gefr");
list.add("qrer");
list.add("jyjy");
list.add("fbgvrvr");
list.add("rruui");
// 匿名内部类
// 根据列表中的元素的首字母进行排序(升序)
// list.sort(new Comparator<String>() {
// /*
// 重写接口中的compare方法
// 返回值int如果是负值,那么参数o1排在o2前面
// 返回值int如果是正值,那么参数o1排在o2后面
// */
// @Override
// public int compare(String o1, String o2) {
// return o1.charAt(0) - o2.charAt(0);
// }
// });
// lambda表达式
list.sort((a,b)->a.charAt(0) - b.charAt(0));
System.out.println(list);
}
1.3 Stack实现类
Stack类是Vector类的子类,是线程安全的集合。底层使用数组。查询快,增删慢。
Stack表示栈结构。栈结构遵循LIFO原则
和栈结构对应的有一种队列结构,遵循FIFO
LIFO: last in first out 后进先出
FIFO:first in first out 先进先出
public static void main(String[] args) {
// 创建栈
Stack<String> stack = new Stack<>();
// 压栈
// stack.add("adf");
// stack.add("ios");
// stack.add("for");
// stack.add("pro");
// 打印顺序依然是正向
System.out.println(stack);
// 弹栈 --会直接将栈中元素弹出 栈中会缺少一个元素
// pop方法如果栈中没有元素,会抛出异常EmptyStackException
// System.out.println(stack.pop());
// System.out.println(stack);
// 弹栈 --只是把栈顶的元素查看出来,不会移除元素
// peek方法如果栈中没有元素,会抛出异常EmptyStackException
// empty是判断栈中是否为空
if (!stack.empty()) {
String peek = stack.peek();
System.out.println(peek);
}
// 入栈
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
System.out.println(stack);
// 是从栈顶到栈底来查找,并且是以1为基数
System.out.println(stack.search("b"));
}
1.3.1 练习–实现Stack类的常用方法
public class StackDemo {
private String[] data = new String[10];
// 栈的大小
private int size = 10;
/**
* 判断栈是否为空
*/
public boolean isEmpty(){
return size==0;
}
/**
* 返回栈顶元素
*/
public String peek(){
// 判断栈是否为空
if (size == 0){
throw new EmptyStackException();
}
return data[size - 1];
}
/**
* 返回和删除栈顶元素 pop
*/
public String pop(){
// 获取栈顶元素
String str = this.peek();
// 删除栈顶元素
size--;
return str;
}
/**
* 压栈
*/
public void push(String str){
// 判断是否需要扩容
if (size >= data.length){
data = Arrays.copyOf(data,data.length * 2);
}
// 添加元素
data[size] = str;
size++;
}
/**
* 从栈顶到栈底来搜索元素,并且从1开始
* 1 2 3 4 5
*/
public int search(String str){
// 方式一:
// for (int i = size - 1;i >= 0;i--){
// if (data[i] == str || data[i] != null && data[i].equals(str)){
// return size - i;
// }
// }
// 方式二:
for (int i = size - 1,j = 1;i >= 0;i--,j++){
if (Objects.equals(data[i], str)){
return j;
}
}
return -1;
}
}
1.4 Iterator接口
- hasNext:判断是否有下一个元素
- next:获取下一个元素
public static void main(String[] args) {
// 创建ArrayList对象
List<String> list = new ArrayList<>();
// 添加元素
list.add("a");
list.add("b");
list.add("c");
list.add("d");
// 获取迭代器对象
Iterator<String> iterator = list.iterator();
// 是否有下一个元素
while (iterator.hasNext()){
// 获取下一个元素
String str = iterator.next();
System.out.println(str);
}
}
增强for循环和迭代器都不可以一边遍历一边添加或者删除内容
普通for循环在添加或删除元素时,在循环过程中的size是会改变的
// 创建ArrayList对象
List<String> list = new ArrayList<>();
// 添加元素
list.add("a");
list.add("b");
list.add("c");
for (int i = 0; i < list.size(); i++) {
list.remove("d");
System.out.println(i);
}
1.5 Set接口
set存储结构决定元素不允许重复。可以存放null常量。
public static void main(String[] args) {
// 创建set接口 不允许重复元素
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
System.out.println(set);
set.remove("a");
System.out.println(set);
System.out.println(set.contains("b"));
set.add(null);
System.out.println(set);
}
1.5.1 HashSet
HashSet底层数据结构是基于HashMap.是存储不重复的元素,元素的位置不是一成不变的。是无序的。线程不安全的。
1.5.2 LinkedHashSet
LinkedHashSet 是 HashSet 的子类,并且是 Set 接口的实现类
LinkedHashSet 自身特点:
- 有序的集合,存储和取出是有顺序的
- 底层的数据结构是哈希表和双向链表
- 线程不安全的集合
LinkedHashSet的元素在确定放在哪个桶的同时,还会知道下一个数据在哪里。底层维持了两条链表,能够记录存入的顺序。
1.5.3 TreeSet
TreeSet常常用于对元素进行排序。
// 创建set接口 不允许重复元素
Set<String> set = new TreeSet<>();
set.add("d");
set.add("e");
set.add("a");
set.add("k");
System.out.println(set);
对于自定义类进行排序
public class TestDemo4 {
public static void main(String[] args) {
// 创建set接口 不允许重复元素
// 要求放入TreeSet中的元素所对应的类型的类必须实现Comparable接口
Set<Student> set = new TreeSet<>();
set.add(new Student("张无忌",18,100));
set.add(new Student("张三丰",100,300));
set.add(new Student("周芷若",20,19));
set.add(new Student("谢逊",40,40));
System.out.println(set);
}
}
class Student implements Comparable<Student>{
// 姓名
private String name;
// 年龄
private int age;
// 分数
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
/**
* 拿当前的对象和传入的对象进行比较
* 如果返回值是正值,那么当前对象放在传入对象的后面
* 如果返回值是负值,那么当前对象放在传入对象的前面
* @param o the object to be compared.
* @return
*/
@Override
public int compareTo(Student o) {
return this.score - o.score;
}
}
1.6 Queue接口
是一个队列接口,LinkedList是它的实现类。
队列结构是FIFO,先进先出
public static void main(String[] args) {
// 创建队列
Queue<String> queue = new LinkedList<>();
// 添加方法
// queue.add("abc");
// queue.offer("cbd");
// queue.offer("yyy");
// 删除队列头部元素的方法
// 如果集合中没有值时,会抛出异常NoSuchElementException
// queue.remove();
// 如果集合中没有值时,然后的是一个null
// String poll = queue.poll();
// System.out.println(poll);
// 获取队列头部的元素
// 如果集合中没有值时,返回null
String peek = queue.peek();
System.out.println(peek);
// 如果集合中没有值,会抛出异常NoSuchElementException
// String element = queue.element();
// System.out.println(element);
System.out.println(queue);
}
2 泛型
2.1 泛型介绍
- 泛型是Java中的一种安全机制
- JDK1.5的特性
- 保证了程序的安全性
- 减少了代码量
- 避免了类型的强制转换
public static void main(String[] args) {
/**
* 泛型是Java中的一种安全机制
* JDK1.5的特性
* 保证了程序的安全性
* 减少了代码量
* 避免了类型的强制转换
* 把运行时可能出现的错误提前到了编译阶段
*/
// 创建对象时不使用泛型
ArrayList arrayList = new ArrayList();
arrayList.add("abc");
arrayList.add(123);
Iterator iterator = arrayList.iterator();
// 遍历集合
while (iterator.hasNext()){
String next = (String)iterator.next();
System.out.println(next);
}
}
泛型使用格式:
类名/接口名<泛型的名称>
泛型在命名的时候只要是遵循标识符的命名规则就可以
习惯上是通过一个大写字母来表示泛型
E element 元素
T type 类型
R result 结果
K key 键
V value 值
泛型可以用在类/接口/方法上面
2.2 泛型类
可以在自己定义的类上面使用泛型
- 定义泛型类
// 泛型不能是基本数据类型
// 在类中使用泛型,需要在类名后添加<泛型名称>
// 如果泛型中有多个,在<>中使用,隔开
public class GenericClass<E,M> {
private E name;
private M age;
public M getAge() {
return age;
}
public void setAge(M age) {
this.age = age;
}
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
- 使用泛型类
public static void main(String[] args) {
// 泛型擦除
GenericClass<String,Integer> aClass = new GenericClass();
aClass.setName("tom");
aClass.setAge(18);
System.out.println(aClass.getName());
System.out.println(aClass.getAge());
}
2.3 接口中的泛型
2.3.1 接口使用方式一
- 实现接口时不实现泛型
public interface Inter<E> {
void show(E e);
}
// 实现接口时不实现泛型
public class InterImpl<E> implements Inter<E> {
@Override
public void show(E e) {
System.out.println(e);
}
}
- 使用泛型
public static void main(String[] args) {
Inter<String> inter = new InterImpl<>();
inter.show("abc");
}
2.3.2 接口使用方式二
在实现接口时直接实现泛型
// 实现接口时不实现泛型
public class InterImpl implements Inter<String> {
@Override
public void show(String s) {
System.out.println(s);
}
}
2.4 方法中的泛型
// 在方法的返回值前面添加<泛型名称> 来声明方法的泛型
public <K> K add(K k){
System.out.println(k.getClass());
return k;
}
使用方式
public static void main(String[] args) {
GenericClass<String,Integer> genericClass = new GenericClass<>();
// 方法泛型是在方法调用时使用泛型擦除
genericClass.add("abc");
genericClass.add(10);
genericClass.add(new Student("gg",16,90));
}