1.集合运算(数学运算当中的交并补)
交集:
利用Collection接口提供的retainAll方法来实现
方法 | 内容 |
---|---|
retainAll(Collection<?> c) | 仅保留包含在指定集合中的这个集合中的元素 |
//当有需求求集合之间的交集 list1和list2的交集 ,得到list3交集
//声明list1和list2
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
//声明结果集合
ArrayList list3 = new ArrayList();
//保证新的集合没有任何值
list3.clear();
list1.add("A");
list1.add("B");
// list1.add("B");
// list1.add("C");
list2.add("B");
list2.add("D");
//list3先添加其中一个集合
list3.addAll(list1);
//利用该方法,该方法会修改自身的集合数据结构,方法结果返回true表示修改成功这个集合 返回false,表示没有修改该集合
//list3再去交集list2,来返回新的交集list结果
System.out.println(list3.retainAll(list2));;
System.out.println(list3);
并集:
//并集
//声明list1和list2集合
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
list1.add("A");
list1.add("B");
list1.add("B");
list2.add("B");
list2.add("D");
list2.add("D");
//声明结果集合
ArrayList list3 = new ArrayList();
//保证新的集合没有任何值
list3.clear();
//利用All来完成并集
list3.addAll(list1);
list3.addAll(list2);
System.out.println("并集:"+list3);
//如果有需要去掉重复的并集 可以利用HashSet集合的特性,形成之后,再赋值给list3
HashSet set = new HashSet();
set.addAll(list1);
set.addAll(list2);
list3.clear();
list3.addAll(set);
System.out.println("并集无重复:"+list3);
差集:
// 差集
// 声明list1和list2集合
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
list1.add("A");
list1.add("A");
list1.add("B");
list1.add("B");
list2.add("B");
list2.add("D");
list2.add("D");
// 声明结果集合
ArrayList list3 = new ArrayList();
list3.addAll(list1);
list3.removeAll(list2);
//如果还想去掉重复的元素,记得使用HashSet集合来完成这个
System.out.println("差集:"+list3);
2.泛型
泛型是程序设计语言的一种特性。
允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。
Java 泛型的参数只可以代表类,不能代表个别对象。由于 Java 泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型。Java 编译器在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。
在前面学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
//这里的集合没有做任何的类型限制,所以该集合默认可以放Object系列的实例对象
ArrayList list = new ArrayList();
list.add("sss");
list.add(11);
list.add(54.5);
//就会发现,无法直接使用对应的对象方法。需要进行强转
String str = (String)list.get(0);
System.out.println(str.substring(1));
//包括Integer类型。那么问题就是,如果在增强型的foreach循环里面,那么就会很麻烦
Integer i = (Integer)list.get(1);
System.out.println(i);
for (Object object : list) {
//ClassCastException 这里会这样报错,因为这个集合太多不同的类型的对象
str = (String)object;
}
一般使用来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type)
如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等,
若是<?>,则是默认是允许Object及其下的子类,也就是java的所有对象了。
举例说明:
Set 表示 集合里 是 T类的实例
List 表示 集合里 是 E类的实例
List<?> 表示 集合里的对象类型不确定,未指定
List 同 List<?> 是一样的。 ·······························
Java泛型中的标记符含义
符号 | 内容 |
---|---|
E | Element (在集合中使用,因为集合中存放的是元素) |
T | Type(Java 类) |
K | Key(键) |
V | Value(值) |
N | Number(数值类型) |
? | 表示不确定的java类型 |
S、U、V | 2nd、3rd、4th types |
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
//给集合添加一个String类型,那么在获取该数据的时候,得到的元素就是一个String类型,不需要强转
ArrayList<String> list = new ArrayList<String> ();
list.add( new String("22"));
//true
System.out.println(list.get(0) instanceof String);
String str = list.get(0);
泛型规则
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
- 静态泛型变量和静态泛型方法解释:https://blog.csdn.net/fengwei4618/article/details/70768183?utm_source=blogxgwz4
- 方法上面也可以声明泛型,静态方法也可以
自定义泛型类
在自定义泛型类的声明,是在类名后面加上 <T>
在类体中只能对这个 泛型进行声明,不能实现或赋值, 而且在静态成员 都不可以使用泛型
模拟List类仿写如何声明泛型
泛型方法
方法上面也可以声明泛型,静态方法也可以
泛型方法也可以定义多个
必须返回值类型之前去声明
练习:编写一个类,在实例化的时候需要泛型来定义其存储的数据类型,编写一个存储方法和一个返回该存储值的方法
有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。
例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
extends:限定通配符的上边界
上边界类型通配符(<? extends 父类型>):
因为可以确定父类型,所以可以以父类型去获取数据(向上转型)。但是不能写入数据。
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
super:限定通配符的下边界
接收Integer 或者Integer的父类型 因为确定子类了,所以可以传入值
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();
https://blog.csdn.net/hanchao5272/article/details/79355931
3.Map(键值对、键唯一、值不唯一)
Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值
---| Map: 键值对 (key,value) key的特点是无序的,不可以重复的,通过唯一的key拿到唯一的value。
---|HashMap 非线程安全,高效,key无序 key支持null
---|TreeMap key按按字典序 key不支持null
---|HashTable 线程安全,低效,key支持null
---|LinkedHashMap
性能 : HashMap > TreeMap > LinkedHashMap > HashTable
方法 | 内容 |
---|---|
get(Object key) | 返回指定键所映射的值;如果次映射不包含该键的映射关系,则返回null |
put(K key,V value) | 将指定的键与值对应起来,并添加到集合中 |
remove(Object key) | 如果存在一个键的映射关系,则将其从此映射中移除 |
keySet() | 返回次映射中包含键的Set视图 |
put方法:方法返回值为键所对应的值,使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
使用put方法时,若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
get方法 : 获取指定键(key)所对应的值(value)。
remove方法:根据指定的键(key)删除元素,返回被删除元素的值(value)。
键找值方式:即通过元素中的键,获取键所对应的值
//1.增强的for循环(entry集合)
for(Entry<Integer, String> entry:map.entrySet()){
System.out.println(entry);
}
//2.增强的for循环(key集合)
for(Integer key:map.keySet()){
System.out.println(key+" = "+map.get(key));
}
//3.遍历值的集合
for(String value:map.values()){
System.out.println(value);
}
Test1:
public class Test1 {
public static void main(String[] args) {
// 交集
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
List<Integer> list2 = new ArrayList<Integer>();
list2.add(5);
list2.add(6);
list2.add(7);
list2.add(8);
list2.add(1);
list2.add(2);
// 新增一个集合3出来,集合3就是用来获取交集的内容的
List<Integer> list3 = new ArrayList<Integer>();
list3.addAll(list1);
// retainAll:2个集合之间的交集
System.out.println(list3.retainAll(list2));
for (Integer integer : list3) {
System.out.println(integer);
}
}
}
Test2:
public class Test2 {
public static void main(String[] args) {
// 并集
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
List<Integer> list2 = new ArrayList<Integer>();
list2.add(5);
list2.add(6);
list2.add(7);
list2.add(8);
list2.add(1);
list2.add(2);
// 新增一个集合3出来,集合3就是用来获取并集的内容的
List<Integer> list3 = new ArrayList<Integer>();
list3.addAll(list1);
list3.addAll(list2);
for (Integer integer : list3) {
System.out.println(integer);
}
}
}
Test3:
public class Test3 {
public static void main(String[] args) {
// 差集
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
List<Integer> list2 = new ArrayList<Integer>();
list2.add(5);
list2.add(6);
list2.add(7);
list2.add(8);
list2.add(1);
list2.add(2);
// 新增一个集合3出来,集合3就是用来获取并集的内容的
List<Integer> list3 = new ArrayList<Integer>();
list3.addAll(list1);
//removeAll:减去集合中相同的数据
list3.removeAll(list2);
for (Integer integer : list3) {
System.out.println(integer);
}
//总结:
//交集:retainAll
//并集:addAll
//差集:removeAll
}
}
Test4:
public class Test1 {
// 集合
public static void main(String[] args) {
// 栈集合
Stack stack = new Stack();
// 压栈
stack.push(1);// 追加数据到栈集合中
stack.push(2);
stack.push(3);
stack.push(4);
// 出栈
System.out.println(stack.pop());// 移除顶部的栈内容,而且返回
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
Test5:
public class Test2 {
// 集合
public static void main(String[] args) {
// <E>:泛型---规范类型(设定一个固定类型)
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
// 这个叫for循环
for (int i = 0; i < args.length; i++) {
}
// foreach:增强版for循环
// 格式
// for (每一次迭代的内容都会赋值给前面的变量 : 迭代的集合) {
// 就能直接使用变量了
// }
// 一般都是Object吗,Object 是什么类型就看迭代的集合的泛型类型是什么
// 如果没有写泛型,那么就是object,如果已经规范类型了那么就可以填写Object/Integer
for (Integer q : queue) {
System.out.println(q);
}
System.out.println(queue.poll());//获取元素并删除
System.out.println(queue.element());//获取第一个元素
System.out.println(queue.peek());
}
}
Test6:
public class Test1 {
public static void main(String[] args) {
// 集合的分布
// Collection--单列集合
// List //有序可以重复
// ArrayList//数组实现, 查找快, 增删慢,线程不安全的
// LinkedList//Linked:链表//链表实现, 增删快, 查找慢
// Vector//数组实现, 查找快, 增删慢,线程安全的,因为线程安全肯定会比ArrayList慢,有得必有失
// 性能:ArrayList = LinkedList > Vector
List list = new ArrayList();
list.add("123");// 往集合中塞东西
list.add("456");
list.add("789");
System.out.println(list.get(1));// 下标
// 怎么迭代,可以有2种,一种是for循环、一种是foreach循环
for (int i = 0; i < list.size(); i++) {// list.size()获取集合长度
System.out.println(list.get(i));
}
for (Object object : list) {
System.out.println(object);
}
List list2 = new LinkedList();
list2.add("987");
list2.add("654");
list2.add("321");
System.out.println(list2.get(1));
for (Object object : list2) {
System.out.println(object);
}
List list3 = new Vector();
list3.add("741");
list3.add("852");
list3.add("963");
System.out.println(list3.get(1));
// Set //无序的不可重复的
// Map--key,value(键值对)
}
}
Test7:
public class Test2 {
public static void main(String[] args) {
// 集合的分布
// Collection--单列集合
// List //有序可以重复
// ArrayList//数组实现, 查找快, 增删慢,线程不安全的
// LinkedList//Linked:链表//链表实现, 增删快, 查找慢
// Vector//数组实现, 查找快, 增删慢,线程安全的,因为线程安全肯定会比ArrayList慢,有得必有失
// 性能:ArrayList = LinkedList > Vector
// Set //无序的不可重复的
// HashSet//内容无序 不可重复 支持null
// TreeSet//内按字典序 不可重复 不支持null
// LinkedHashSet//带存储顺序 不可重复
Set set = new HashSet();// set集合是没有下标的
set.add("123");
set.add("456");
set.add("789");
set.add(null);
set.add("456");
set.add("456");
set.add("456");
// set要拿到里面的内容,我们需要迭代数据
// set集合应该使用那个循环迭代呢for,还是foreach/iterator
for (Object object : set) {
System.out.println(object);
}
// iterator迭代器,可以使用迭代器迭代set集合
Iterator iterator = set.iterator();// 获取set集合的迭代器
// iterator.hasNext();// 询问是有还有下一个数据
while (iterator.hasNext()) {
Object object = iterator.next();
System.out.println(object);
}
System.out.println("--------------------------------------------------");
Set set2 = new TreeSet();// 内按字典序 不可重复 不支持null
set2.add("987");
set2.add("654");
set2.add("321");
set2.add("987");
set2.add("987");
set2.add("987");
set2.add("654");
set2.add("321");
// set2.add(null);//编译是可以通过的,可是会有运行时异常NullPointerException
for (Object object : set2) {
System.out.println(object);
}
// 字典序就是排序的意思 1-9 a-z ,先比较第一位 ,如果第一位比较不出来的,就比较第二位
// "112"
// "123"
// "456"
// "789"
// "aab"
// "abc"
// "ccc"
System.out.println("--------------------------------------------------");
Set set3 = new TreeSet();
set3.add("112");
set3.add("789");
set3.add("123");
set3.add("aab");
set3.add("456");
set3.add("ccc");
set3.add("abc");
for (Object object : set3) {
System.out.println(object);
}
Set set4 = Collections.synchronizedSet(set3);
set4.remove("abc");
// Map--key,value(键值对)
}
}
Test8:
public class Test1 {
public static void main(String[] args) {
List list = new ArrayList();// 集合中不能存放基本类型
// 没有泛型的默认是object类型,如果规范了类型之后,就要按照规范的类型来填写
list.add("123");// 只要带双引号的都是String
list.add(456);// Integer, 自动装箱,自动拆箱
list.add(456.02);// Double
for (Object object : list) {
System.out.println(object);
}
System.out.println("-----------------------------------------");
// index:下标
list.remove(2);
for (Object object : list) {
System.out.println(object);
}
System.out.println("-----------------------------------------");
list.clear();// 清空集合
for (Object object : list) {
System.out.println(object);
}
System.out.println("-----------------------------------------");
System.out.println(list.isEmpty());
System.out.println("-----------------------------------------");
List list2 = new ArrayList();// 集合中不能存放基本类型
// 没有泛型的默认是object类型,如果规范了类型之后,就要按照规范的类型来填写
list2.add("123");// 只要带双引号的都是String
list2.add(456);// Integer, 自动装箱,自动拆箱
list2.add(456.02);// Double
System.out.println(list2.contains(123));// 判断集合何中是否包含指定对象,有就返回true ,没有就false
list2.size();// 获取集合长度的
Object[] objects = list2.toArray();// 集合转数组
// 数组转集合呢
List list3 = Arrays.asList(objects);
// add()将指定对象存储到容器中
// remove()将指定的对象从集合中删除
// clear()清空集合中的所有元素
// isEmpty()判断集合是否为空
// contains()判断集合何中是否包含指定对象
// int size()返回集合容器的大小
// toArray()集合转换数组
List list4 = new ArrayList();// 只有4个元素
list4.add(1);
list4.add(2);
list4.add(3);
list4.add(4);
List list5 = new ArrayList();
list5.add(3);
list5.add(3);
list5.add(3);
list5.add(4);
// System.out.println(list4.addAll(list5));// 就会把list5的元素追加到list4中,所以现在的list4,一共有8个元素
// System.out.println(list4.size());
// addAll()将指定集合中的元素添加到调用该方法和集合中
// removeAll()将指定集合中的元素删除
// list4.removeAll(list5);// 如果list5中有的元素,在list4中移除掉,现在就剩下多少个元素
// System.out.println(list4.size());// 2
// containsAll()判断集合中是否包含指定集合
System.out.println(list4.containsAll(list5));
}
}
Test9:
public class Test2 {
public static void main(String[] args) {
// 去除重复数据
// 可以使用set集合,有一个特点就是不可重复的
// 那如果List 集合 addAll 到 Set 集合中会 怎么样? 会不会被Set集合自动处理掉那些重复的?会
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(4);
list.add(5);
list.add(1);
Set set = new HashSet();// 无序不可重复的
set.add(1);
set.add(6);
set.add(7);
set.add(5);
set.addAll(list);// 有多少个长度
System.out.println(set.size());
System.out.println("----------------------------------------");
for (Object object : set) {
System.out.println(object);
}
}
}