1、泛型
当做一些集合的统一操作的时候,需要保证集合的类型的统一性,此时需要泛型进行限制
优点:
1、数据的安全
2、获取数据的效率比较高
给集合中的元素设置相同类型是泛型的基本需求
使用:
在定义对象的时候,通过<>中设置合理的类型来进行实现
泛型的高阶运用
1、泛型类
在定义类的时候,在类名的后面添加<T,E,K,V>,起到占位的作用,类中的方法的返回类型和属性的类型都可以使用
类的声明
package com.yfbill.test; public class Bill<E>{ //这里的E是表示实例化的时候指定的泛型 private String name; private E prop; //这里的E是表示类名后的那个E类型 public Bill(E prop, String name) { this.name = name; this.prop = prop; } public E getProp() { return this.prop; } }
类的调用
public class Test { public static void main(String[] args) { //可以是一个字符串 Bill<String> b = new Bill<>("this is test", "bill"); System.out.println(b.getProp()); //也可以是一个对象 Bill<Dog> d = new Bill<>(new Dog("aa", 2), "unKnown"); System.out.println(d.getProp()); } }
2、泛型接口
在定义接口的时候,在接口的名称后面添加<T,E,K,V>
public interface ICheck<E> { //这里的E相当需要继承的时候指定 public E getProp(); public void showProp(E obj);
<K> K show(K test); //这里的K是接口的泛型 }
1、子类在实现接口的时候,可以不填写泛型类型,只填写占位符,此时在创建具体子类对象的时候才决定使用什么类型
类的声明
public class Bill<E> implements ICheck<E>{ //需要在调用的时候外部指定 private E prop; public Bill (E prop) { this.prop = prop; } @Override public E getProp() { return this.prop; } @Override public void showProp(E obj) { System.out.println(obj); } }
类的调用
public class Test { public static void main(String[] args) { //可以是一个字符串 Bill<String> b = new Bill<>("this is test"); System.out.println(b.getProp()); //也可以是一个对象 Bill<Dog> d = new Bill<>(new Dog("aa", 2)); d.showProp(new Dog("bbb", 1)); } }
2、子类在实现泛型接口的时候,只在实现父类的接口的时候指定父类的泛型类即可,此时,测试方法中的泛型类型必须要跟子类保持一致
类的声明
public class Bill implements ICheck<String>{ //这里的String表示具体的类型的,而不是占位符,那么默认外部调用就全部是String类型了 @Override public String getProp() { return "are you ok???"; } @Override public void showProp(String str) { System.out.println(str); } }
类的调用
public class Test { public static void main(String[] args) { //这里默认是字符串了 Bill b = new Bill(); System.out.println(b.getProp()); } }
3、泛型方法
在定义方法的时候,指定方法的返回值或参数是自定义的占位符,可以是父类类名中的E也可以是自定义的Q,只不过在使用Q的时候,需要使用<Q>定义在返回值的前面。(这里的Q可以用其他字母替代)
类的声明
public class Bill<E>{ public E prop; public Bill (E prop) { this.prop = prop; } /** * 调用的是类上声明的泛型类型 * @return */ public E take() { return this.prop; } /** * 传入一个与类上的声明不一样的泛型类型 * @param other * @param <T> */ public <T> void show (T other) { System.out.println(other); } }
类的调用
public class Test { public static void main(String[] args) { //这里默认是字符串了 Bill<String> b = new Bill<>("this is test"); System.out.println(b.take()); b.show(new Dog("aa", 12)); } }
4、泛型的类型通配符
类型通配符<?> 一般用于接受使用, 不能够做添加
List<?>: 表示元素类型未知的list, 它的元素可以匹配任何类型
带通配符的List仅表示它是各种泛型List的父类, 并不能把元素添加到其中
package site.ieven;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FirstJava {
public static void main(String[] args) {
List<?> list = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));
list.forEach((count) -> System.out.println("count:" + count));
// 可以执行取数据的操作,但是取出的是Object类型
System.out.println(list.get(1));
System.out.println(list.get(2));
// list.add(1); //不可以执行添加操作,无法界定类型
}
}
5、泛型的上限(工作中用的不多,但是查询API的时候会经常用到)
如果父类确定了,所有的子类都可以直接使用 <? extends ParentClass>: 它表示的类型是ParentClass或者子类型
6、泛型的下限
如果父类确定了,子类的所有父类都可以直接传递使用 <? super ParentClass>: 它表示的类型是 ParentClass或者其父类型
7、可变参数
package site.ieven;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FirstJava {
/**
* 通常来讲,如果可变参数与不可变参数混合使用的话,那么不可变参数会放在第一位,可变参数会放在最后一位
* @param first
* @param second
*/
public static void check(int first, int ...second) {
System.out.println(first);
System.out.println(Arrays.toString(second));
}
public static void main(String[] args) {
check(1,2,3,4,5);
}
}
2、Map类型
特点:key-value映射
1、HashMap
key 无序,唯一
value 无序,不唯一
2、LinkedHashMap
有序的HashMap,速度快
3、TreeMap
有序,速度没有hash快
HashMap与Hashtable的区别
1、HashMap线程不安全,效率比较高,hashtable线程安全,效率低
2、HashMap中key和value都可以为空,hashtable不允许为空
HashMap相关的api
public class Test { public static void main(String[] args) { HashMap<Integer, String> map = new HashMap<>(); HashMap<Integer, String> list = new HashMap<>(Map.of(10, "first", 11, "second", 12, "third")); //添加数据 map.put(1, "this is first"); map.put(2, "this is second"); map.putIfAbsent(3, "what are you doing");//如果已有数据,那么返回对应键值的值,否则添加对应的关联,并且返回null map.putAll(list); //查询数据 System.out.println(map.size()); System.out.println(map.isEmpty()); System.out.println(map.keySet()); System.out.println(map.values()); System.out.println(map.containsKey(3)); System.out.println(map.containsValue("third")); System.out.println(map.get(2)); System.out.println(map.getOrDefault(5, "undefined")); //遍历操作 System.out.println("-------------------------------------"); for(Integer item: map.keySet()) { System.out.println("key的值:" + item + ", value的值是:" + map.get(item)); } for(String item: map.values()) { System.out.println(item); } Set<Map.Entry<Integer, String>> entries = map.entrySet(); for(Map.Entry<Integer, String> iter: entries) { System.out.println("key的值:" + iter.getKey() + ", value的值:" + iter.getValue()); } map.forEach((Integer key, String val) -> System.out.println("key:" + key + ", val:" + val)); System.out.println("==============================="); //修改数据 HashMap<Integer, String> arr = new HashMap<>(){{ this.put(1, "aaaa"); this.put(2, "bbbb"); }}; // ArrayList<Integer> abc = new ArrayList<>(){{ this.add(1); this.add(2); this.add(12); }}; System.out.println(arr.merge(12,"ok", (String a, String b) -> a + b)); //如果有值则进行替换,否则为新增 arr.compute(2, (Integer k, String v) -> v + "yes"); //根据已知的 k v 算出新的v并put。返回值为新值, 如果无此key,那么oldVal为null,lambda中涉及到oldVal的计算会报空指针 arr.computeIfAbsent(100, (Integer k) -> k + "haha"); //当key不存在的时候才执行表达式, 如果存在,那么不执行put,返回现有的值 arr.computeIfPresent(1000, (Integer k, String v) -> "this is test, ok????"); //当key值存在才执行,如果不存在则返回null map.replace(1, "my name is good"); map.replace(2, "this is second", "haha"); //只有值匹配正确才能进行替换 map.replaceAll((Integer key, String val) -> { if(key <= 3) { return "this is test"; } return val; }); //删除数据 map.remove(1); map.remove(2, "this is test"); map.clear(); } }
hashMap的遍历
public static <K, V> void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("aaa", "Aaa"); map.put("bbb", "Abb"); map.put("ccc", "Acc"); for(Map.Entry<String, String> t: map.entrySet()) { System.out.println(t.getKey()); System.out.println(t.getValue()); } map.forEach((String key, String item) -> { System.out.println(item); }); }
TreeMap独有的一些api
public class Test { public static void main(String[] args) { TreeMap<Integer, String> map = new TreeMap<>(Map.of(1, "first", 2, "second", 3, "third", 4, "four")); System.out.println(map.ceilingEntry(2));//比指定大的最小值 含本身 System.out.println(map.floorEntry(2)); //比指定小的最大值 含本身 System.out.println(map.higherEntry(2)); //比指定大的最小值 不含本身 System.out.println(map.lowerEntry(2)); //比指定小的最大值 不含本身 System.out.println(map.higherKey(2)); System.out.println(map.lowerKey(2)); System.out.println(map.headMap(3)); System.out.println(map.headMap(3, true)); //如为true表示包含本身 System.out.println(map.descendingKeySet()); //提取key然后再进行倒序排列 System.out.println(map.descendingMap()); //进行倒序排列 System.out.println(map.subMap(2, true, 4, true)); //对map进行截取,如果为true则包含本身 System.out.println(map.tailMap(2, true)); } }
集合总结
名称 | 存储结构 | 顺序 | 唯一性 | 查询效率 | 添加/删除效率 |
ArrayList | 顺序表 | 有序(添加) | 不唯一 | 索引查询效率高 | 低 |
LinkedList | 链表 | 有序(添加) | 不唯一 | 低 | 最高 |
HashSet | 哈希表 | 无序 | 唯一 | 最高 | 最高 |
HashMap | 哈希表 | key无序 | key唯一 | 最高 | 最高 |
LinkedHashSet | 哈 + 链 | 有序(添加) | 唯一 | 最高 | 最高 |
LinkedHashMap | 哈 + 链 | key有序(添加) | key唯一 | 最高 | 最高 |
TreeSet | 二叉树(红黑树) | 有序(升序) | 唯一 | 中等 | 中等 |
TreeMap | 二叉树(红黑树) | 有序(升序) | key唯一 | 中等 | 中等 |
3、collections工具类的使用
public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); ArrayList<Integer> arr = new ArrayList<>(Arrays.asList(100, 200, 300)); //对集合进行批量添加 Collections.addAll(list, 7, 8, 0, 1, 3, 5, 2, 4, 6); //对list进行反向排序 Collections.reverse(list); //对集合进行排序 Collections.sort(list); Collections.sort(list, (Integer a, Integer b) -> b - a); //把arr的项复制到list中,前提是arr的长度必需要小于等于list的长度 Collections.copy(list, arr); //把指定的List对象以某值进行填充 Collections.fill(list, 1000); //统计指定的元素出现的次数 int count = Collections.frequency(list, 1000); //查询最大值 System.out.println(Collections.max(arr)); //查询最小值 System.out.println(Collections.min(arr)); //对集合进行随机排序 // Collections.shuffle(arr); //判断两个集合没有交集 System.out.println(Collections.disjoint(arr, list)); //把两个元素的位置进行调换 Collections.swap(arr, 2, 1); //binarySearch 表示进行二分查找,前提是要先排好序 } }
Arrays的常用方法
public class Test { public static void main(String[] args) { ArrayList<Integer> arr = new ArrayList<>(); Collections.addAll(arr, 1, 2, 3, 4, 5, 6, 7); //把指定的转成list类型 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); //把list类型转成数组 Object[] array = list.toArray(); } }