Collection是根部接口,具体看下图:
1、List
(1)、添加、获取元素
package List;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/13 22:51
*
* List集合根据角标获取元素
*/
public class List1 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add(1);
System.out.println(list);
//根据角标添加元素
//index必须小于等于list的size
list.add(1,"myxq");
System.out.println(list);
//获取制定角标的元素
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
上面代码中的list.add(1);这里调用的add方法会在内部自动装箱,当我们打开该文件的字节码可以看到:
本是基本数据类型的1在内部被自动转换成了Integer的包装类型,其他基本数据类型也是一样会被转换相应的包装类型。
(2)、删除元素(解决删除元素的并发异常)
package List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/13 22:58
*
* List集合解决删除元素的并发异常
*/
public class List2 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
//java.util.ConcurrentModificationException
//并发修改异常
//在迭代集合的过程的当中,是不允许直接修改集合的结构的
//删除时可以使用迭代器之中的删除
//遍历集合,如果元素等于2,则删除2
// 在获取迭代器时modCount == expectedModCount
// modCount:集合修改的次数
// expectedModCount:迭代器当中记录集合修改的次数
// 只要修改的次数不相等
// modCount != expectedModCount
// throw new ConcurrentModificationException();
// 所以list.remove("2")执行时modCount改变,就和expectedModCount不等
// 而迭代器中的remove会执行expectedModCount = modCount;
//1.遍历集合
Iterator iterator = list.iterator();
while (iterator.hasNext()){
//2.取出对应元素
String str = (String) iterator.next();
//3.判断元素是否等于2
if (str.equals("2")){
//4.等于2就把该元素删除
//list.remove("2");
iterator.remove(); //删除当前正在迭代集合的元素(正在遍历元素next)
list.add("myxq"); // Increments modCount!!导致modCount != expectedModCount
}
}
System.out.println(list);
}
}
(3)、添加元素(解决添加元素的并发异常)
在上面的删除元素中,我们可以通过迭代器的删除来解决删除元素导致的modCount != expectedModCount问题,但是迭代器中没有add方法,所以这时我们可以使用List自己的迭代器ListIterator:
package List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/13 23:22
*
* List集合解决添加元素的并发异常
*/
public class List3 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator iterator = list.iterator();
while (iterator.hasNext()){
String str = (String) iterator.next();
if (str.equals("2")){
//list.add("myxq"); // Increments modCount!!导致modCount != expectedModCount
}
}
//在List中有自己的迭代器
ListIterator listIterator = list.listIterator();
System.out.println(listIterator);//java.util.ArrayList$ListItr@4554617c
while (listIterator.hasNext()){
String lstr = (String) listIterator.next();
if (lstr.equals("2")){
listIterator.add("myXq");
}
}
System.out.println(list);//[1, 2, myXq, 3, 4]
}
}
ListIterator和迭代器的用法差不多,如下:
package List;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/13 23:31
*
* ListIterator迭代器方法
*/
public class ListIterator {
public static void main(String[] args) {
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
java.util.ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()){
System.out.print(listIterator.next()+"\t");
}
System.out.println();
System.out.println(list);
while (listIterator.hasPrevious()){
System.out.println("preIndex = " + listIterator.previousIndex());
System.out.println(listIterator.previous());
}
//上面循环输出的最终结果如下
/**
* preIndex = 3
4
preIndex = 2
3
preIndex = 1
2
preIndex = 0
1
*/
}
}
本来此处是一个小例子,但是在这个例子之前还得看看泛型的概念
当我们使用List的get方法时,取出来的全是Object对象,这会造成一定的麻烦,因为不同类型的对象时无法比较的,而且有些方法也无法使用,例如:当我们存储的是字符串时,想要使用字符串的某些方法,我们还得强转回来,所以这就引出了泛型的概念,给集合一个约束,约定只能存储什么类型的数据
泛型:广泛通用的类型(一开始不确定什么类型,在使用的时候才能确定是什么类型),换句话说就是代码模块中不确定自己是什么类型的,只有在谁调用它调用他的时候才来指明这个类型
但是泛型的本质还是Object,他是一个语法糖(此处就不解释语法糖了),只是在内部被强转了,具体可见以下的代码及其字节码
package List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 13:50
*/
//T:type E:element k:key可以自定义
class Point2<T>{
//1、可以使字符串类型
//2、Integer
//3、Double
//定义成泛型
T x;
T y;
public T getY() {
return y;
}
}
public class GenericType2 {
public static void main(String[] args) {
/**
*
* 1、在开始定义类的时候,就留一个插口
* 2、在创建对象的时候,再去插入对应的类型
*/
//创建对象时要指明泛型时什么类型
//如果没有指明,那就是Object类型
Point2<String> point2 = new Point2<String>();
point2.x = "10";
point2.y = "20";
System.out.println(point2.getY());
}
}
如上图中代码所示,语句System.out.println(point2.getY());本质上是System.out.println((String)point2.getY());也就是说输出的其实还是Object,只是在内部被强转成了String类型。
泛型类以及泛型方法的使用
package List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 14:41
*/
class Gtest<T>{
T name;
public T getName() {
return name;
}
}
class Gstudent{
//泛型方法
<T> void test(T a){
System.out.println(a.getClass());
}
//静态方法也可以自定义泛型
static <E> E test2(E name){
System.out.println(name.getClass());
return name;
}
}
public class GenericType3 {
/**
* 1、泛型类:在类上面定义的类型,在,在创建对象时要指定泛型类型
* 泛型当中定义的泛型只能用在普通方法上
* 不能使用在静态方法上面
* 静态方法是直接使用类名调用的,泛型是在创建对象时才去指定类型
* 2、自定义泛型方法:方法上面添加了泛型
* 单独的对一个方法上面泛型
* 方法中定义的泛型,是在使用方法时,参数传递时确定具体是什么类型
* 所以方法想要使用泛型,必须要有参数才有意义
*/
public static void main(String[] args) {
Gtest<String> t = new Gtest<>();
Gtest<String> t1 = new Gtest();
new Gstudent().test(10);//class java.lang.Integer
new Gstudent().test("10");//class java.lang.String
new Gstudent().test2(true);//class java.lang.Boolean
String name = new Gstudent().test2("yuanZhi");
System.out.println(name);//yuanZhi
Boolean aBoolean = new Gstudent().test2(true);
System.out.println(aBoolean);//true
}
}
package List;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 15:24
*/
public class GenericType4 {
/**
* 通配符:不知道使用什么类型来接收的时候,可以使用?表示未知
* 只能用来做接收使用
* 不能用来添加
* @param args
*/
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
test(list);
// test2(list); 报错,因为只能是Number或者Number的父类
// List<String> list2 = new ArrayList<>();
// test(list2); String并没有继承Number,所以在此处报错
// List<?> list3 = new ArrayList<>();
// list3.add("a"); 报错,只能接收,不能添加
}
static void test(List<? extends Number> list){
}
static void test2(List<? super Number> list){
}
}
好了,泛型介绍完了,下面就来讲一个List的学科、班级、学生的小例子:
package List;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 15:41
*/
class Person{
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class ListExample {
public static void main(String[] args) {
/**
* 学科 学科中有很多班级
* 班级中又有很多学生
*/
Person p1 = new Person("zs");
Person p2 = new Person("ls");
List<Person> c1 = new ArrayList<>();//班级1
c1.add(p1);
c1.add(p2);
Person p3 = new Person("zs1");
Person p4 = new Person("ls2");
List<Person> c2 = new ArrayList<>();//班级2
c2.add(p1);
c2.add(p2);
List<List<Person>> m = new ArrayList<>();//学科(集合中存集合)
m.add(c1);
m.add(c2);
//打印所有班级中的学生姓名
for (List<Person> list:m) {
for (Person p:list) {
System.out.println(p.getName());
}
}
}
}
ArrayList
上面List有的用法,ArrayList都有,所以这里不重复介绍
去除集合中的重复元素
package List;
import java.util.ArrayList;
import java.util.ListIterator;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/14 19:34
*
* 去除集合当中重复的元素
*/
public class ArrayList1 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("a");
arrayList.add("b");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
System.out.println(arrayList);//[a, a, b, b, c, d]
//想要的是[a,b,c,d]
ArrayList newList = getSingleEle(arrayList);
System.out.println(newList);//[a, b, c, d]
}
private static ArrayList getSingleEle(ArrayList arrayList) {
//1、创建一个空集合
ArrayList newList = new ArrayList();
//2、依次取出元素
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()){
//3、每取出一个元素,先判断新集合中是否已经包含了元素
Object object =listIterator.next();
//4、如果包含,就不添加,不包含菜添加到新集合
if(!newList.contains(object)){
newList.add(object);
}
}
return newList;
}
}
去除自定义对象的重复元素
package List;
import java.util.ArrayList;
import java.util.ListIterator;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/14 20:23
*
* 去除自定义对象重复元素
*/
class Student{
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//作对象的对比,不想让其比较地址,就得重写equals
@Override
public boolean equals(Object obj) {
Student stu = (Student) obj;
return this.name.equals(stu.name) && this.age == stu.age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ArrayList2 {
private static ArrayList getSingleEle(ArrayList arrayList) {
//1、创建一个空集合
ArrayList newList = new ArrayList();
//2、依次取出元素
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()){
//3、每取出一个元素,先判断新集合中是否已经包含了元素
Object object =listIterator.next();
//4、如果包含,就不添加,不包含菜添加到新集合
if(!newList.contains(object)){//contains判断有没有某元素(equals)->Object -> 地址
//没有重写equals,所以比的就是地址,当前的object就是Student类,而Student类并没有重写equals,所以地址不同导致都不包含
//所以在Student中药重写equals方法
newList.add(object);
}
}
return newList;
}
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(new Student("张三",20));
list.add(new Student("张三",20));
list.add(new Student("李四",21));
System.out.println(list);//[Student{name='张三', age=20}, Student{name='张三', age=20}, Student{name='李四', age=21}]
ArrayList newList = getSingleEle(list);
System.out.println(newList);//[Student{name='张三', age=20}, Student{name='李四', age=21}]
}
}
LinkedList
LinkedList的底层是基于链表的,如图:
同样List有的LinkedList也有,除此之外,还有特有的:
package List;
import java.util.ListIterator;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 10:52
*/
public class LinkedList1 {
public static void main(String[] args) {
java.util.LinkedList list = new java.util.LinkedList();
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);
ListIterator iterator = list.listIterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//特有
//往第一个位置添加元素
list.addFirst("mySql");//[mySql, a, b, c]
list.addFirst("1");//[1, mySql, a, b, c]
System.out.println(list);
//在集合的最后添加元素
list.addLast("yuanZhi");
System.out.println(list);//[1, mySql, a, b, c, yuanZhi]
//移除第一个元素
list.removeFirst();
System.out.println(list);//[mySql, a, b, c, yuanZhi]
//移除最后一个
list.removeLast();
System.out.println(list);//[mySql, a, b, c, yuanZhi]
//根据角标获取元素
//LinkedList查询是比较慢的,需要经历for循环依次询问
System.out.println(list.get(0));
}
}
用LinkedList模拟出栈入栈:
package List;
import java.util.LinkedList;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 11:06
*/
class Stack{
LinkedList linkedList;
Stack(){
linkedList = new LinkedList();
}
//入栈:在集合最后添加一个元素
void push(Object object){
linkedList.addLast(object);
}
//出栈:把集合中最后一个元素移除
void pop(){
linkedList.removeLast();
}
@Override
public String toString() {
return "Stack{" +
"linkedList=" + linkedList +
'}';
}
}
public class LinkedList2 {
public static void main(String[] args) {
Stack stack = new Stack();
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack);//Stack{linkedList=[a, b, c]}
stack.pop();//Stack{linkedList=[a, b]}
System.out.println(stack);
}
}
Vector
底层也是基于数组,使用少,因为如果只有一个线程访问集合,一般也最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果多线程访问集合,那么最好使用Vector,因为Vector的所有方法前面都加了锁,而ArrayList没有,所以Vector是线程安全的ArrayList不是。
package List;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 11:27
*/
public class Vector {
public static void main(String[] args) {
java.util.Vector vector = new java.util.Vector();
vector.add("a");
vector.add("b");
vector.add("c");
System.out.println(vector);//[a, b, c]
}
}
Set
Set中存的是无序不重复元素,并且已经覆盖了toString方法。
package Set;
import java.util.HashSet;
import java.util.Iterator;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 15:52
*/
public class Set1 {
public static void main(String[] args) {
//Set中存的是无序不重复的元素,并已经覆盖了toString
HashSet<String> hs = new HashSet<>();
boolean res1 = hs.add("a");
boolean res2 = hs.add("a");
hs.add("b");
hs.add("c");
hs.add("2");
hs.add("1");
System.out.println(res1);//true
System.out.println(res2);//false
System.out.println(hs);//[a, 1, b, 2, c]
Iterator iterator = hs.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//只要能用迭代器的,都可用它的增强型foreach
for (String str:hs
) {
System.out.println(str);
}
}
}
Set存储的元素时不重复的,但是若是自定义的对象,是会重复的,所以需要我们自己重写其中的equals和hashCode方法来达到存储的是不可重复元素的目的。
package Set;
import java.util.HashSet;
import java.util.Set;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 16:01
*/
class Person{
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
return age != null ? age.equals(person.age) : person.age == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Set2 {
public static void main(String[] args) {
//想要在Set中自定义对象去重
//1、重写equals
//2、重写hashCode
//3、自定义对象属性完全相同的话,就判定是同一个对象
Set<Person> s = new HashSet<Person>();
s.add(new Person("张三",20));
s.add(new Person("张三",20));
s.add(new Person("李四",21));
s.add(new Person("李四",21));
s.add(new Person("李四",21));
System.out.println(s);//[Person{name='张三', age=20}, Person{name='李四', age=21}]
}
}
利用Set的这一特性,可以获取1-20之间10个不重复的随机数
package Set;
import java.util.HashSet;
import java.util.Random;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 16:47
*
* 获取1-20之间的10个不重复的随机数
*/
public class GetRandom {
public static void main(String[] args) {
//1、使用random生产随机数
Random random = new Random();
//2、创建生成结果的集合
HashSet<Integer> hashSet = new HashSet<>();
//3、当生成的个数大于集合的size就不放了
while (hashSet.size() < 10){
//4、生成1-20之间的随机数
int res = random.nextInt(20) + 1;
//5、添加到集合当中
hashSet.add(res);
}
System.out.println(hashSet);
}
}
另外还可以达到字符串去重的目的
package Set;
import java.util.LinkedHashSet;
import java.util.Scanner;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 16:55
*
* 字符串去重
*/
public class RemoveRepeate {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = scanner.nextLine();//adhasjdhasjdsagdhasjh
//1、拿到字符串中的每一个字符
char[] arr = line.toCharArray();
//2、取出每一个元素,添加到一个可以去重的集合中
//为了保证输出输入顺序一致,选用LinkedHashSet
LinkedHashSet<Character> hs = new LinkedHashSet<>();
for (char c:arr
) {
hs.add(c);
}
System.out.println("去重后的结果:"+hs);//去重后的结果:[a, d, h, s, j, g]
}
}
TreeSet
TreeSet也是无序的(不会按照你添加的顺序展示),但是它会对你添加的元素进行排序,所以要保证元素的顺序时可以使用TreeSet
package Set;
import java.util.TreeSet;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 17:02
*/
public class TreeSet1 {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(2);
treeSet.add(2);
treeSet.add(7);
treeSet.add(9);
treeSet.add(6);
System.out.println(treeSet);//[2, 6, 7, 9]
TreeSet<String> treeSet2 = new TreeSet<>();
treeSet2.add("a");
treeSet2.add("c");
treeSet2.add("b");
treeSet2.add("e");
treeSet2.add("j");
System.out.println(treeSet2);//[a, b, c, e, j]
//汉字根据Unicode的值
TreeSet<String> treeSet3 = new TreeSet<>();
treeSet3.add("远");
treeSet3.add("志");
System.out.println('远'+0);//36828
System.out.println('志'+0);//24535
System.out.println(treeSet3);//[志, 远]
}
}
TreeSet添加元素时对你添加的元素进行排序是基于二叉树的算法,根据对其底层源码的分析,是在调用add方法时会调用一个compareTo方法,该方法会有一个返回值,若返回值为0,则只添加你添加的所有元素中的第一个元素;若是任意一正数,则都添加到集合中并且按照顺序显示;若是返回是任意一负数,则都添加到集合中,但是是按照倒序显示。
package Set;
import java.util.TreeSet;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 17:15
*/
class Person2 implements Comparable<Person2>{
private String name;
private Integer age;
public Person2(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person2 o) {
int num = this.age - o.age;
/*if (num == 0){
return this.name.compareTo(o.name);
}else {
return num;
}*/
return num == 0 ? this.name.compareTo(o.name) : num;
}
@Override
public String toString() {
return "Person2{" +
"name='" + name + '\'' +
'}';
}
}
public class TreeSet2 {
public static void main(String[] args) {
//TreeSet中存放的类型必须是同一类型,
// 因为不是同一类型没有可比性
//自定义的对象不能直接添加到TreeSet中
//想要添加到TreeSet中,必须实现Comparable接口
//重写其中的compareTo方法
TreeSet<Person2> set = new TreeSet<>();
set.add(new Person2("张三",20));
set.add(new Person2("李四",21));
set.add(new Person2("李四1",21));
set.add(new Person2("王五",25));
set.add(new Person2("赵六",23));
System.out.println(set);
}
}
另外,默认是调用对象的compareTo进行比较,如果自己传入了比较器,就会使用传入的比较器进行比较
package Set;
import java.util.Comparator;
import java.util.TreeSet;
/**
* @Author: yuanzhi...
* @Date: created in 2020/1/15 19:11
*/
public class TreeSet4 {
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>();
//默认使用字母的顺序
set.add("aaaaaaa");
set.add("z");
set.add("wq");
set.add("yz");
set.add("nb");
System.out.println(set);//[aaaaaaa, nb, wq, yz, z]
System.out.println("=========================分割线========================");
//使用比较器进行比较
//1、实现一个接口comparator
//2、定义一个类来实现这个接口
//3、重写它里面的方法
TreeSet<String> set2 = new TreeSet<>(new CompareLength());
set2.add("aaaaaaa");
set2.add("z");
set2.add("wq");
set2.add("wq");
set2.add("yz");
set2.add("nba");
System.out.println(set2);//[z, wq, yz, nba, aaaaaaa]
}
}
class CompareLength implements Comparator<String>{
/**
*
* @param o1 当前正在添加的对象
* @param o2 集合中的对象
* @return
*/
@Override
public int compare(String o1, String o2) {
int length = o1.length() - o2.length(); //主要比长度
return length == 0 ? o1.compareTo(o2) : length; //如果长度相等再去比较内容
}
}
有不到位的地方还请谅解
作者君总结码字不易,点个赞再走吧