Java第二部分:集合

Java第二部分:集合

本博客用以记录我在学习过程中的笔记,也可以分享给有需要的人。

学习内容和时间:JavaSE课程(视频来自于b站Idea黑马)、2020年10月。

1、Collection常用功能

集合是Java中提供的一种容器,可以用来存储多个数据。

集合和数组的区别:

  • 数组长度固定,集合长度可变
  • 数组存储同一个类型的元素,既可以存储基本类型的数据,可以存储对象;集合只能用来存储对象,而且对象的类型可以不一致

注意事项: Collection集合中没有定义带索引的方法。

  • List集合:特点:有索引的、可以存储重复元素、存储有序;
    1、ArrayList集合【重点】:底层是数组实现的,查询快、增删慢;
    2、LinkedList集合【次重点】:底层是链表实现的,查询慢、增删快;
    3、Vector集合【了解】

  • Set集合:特点:没有索引、不可以存储重复元素、存储无序;
    1、HashSet集合【重点】:底层是哈希表+(红黑树)实现的;
    2、LinkedHashSet集合【次重点】:底层是哈希表+链表实现的,可以保证存储有序
    3、TreeSet结集合【了解】:底层是二叉树实现的,一般用于排序

  • Java的常用功能:

public boolean add(E e):把给定的对象添加到当前的集合中

public void clear() :清空集合中的所有元素

public boolean remove(E e):把给定的对象在当前的集合中删除(返回值是boolean型,代表删除是否成功)

public boolean contains(E e):判断当前的集合中是否包含给定的对象

public boolean isEmpty():判断当前的集合是否为空

public int size():返回集合中元素的个数

public Object[] toArray():把集合中的元素,存储到数组中

public Object[] toArray(T[] a):把集合中的元素,存储到数组中。返回的数组的类型是指定数组的类型

注意事项: 使用集合的特有方法时,不能使用多态。

2、List集合

特点:有索引的、可以存储重复元素、存储有序;

2.1 ArrayList集合【重点】

特点:

  1. ArrayList底层是一个数组,所以 【查询快,增删慢】;
  2. 此实现不是同步的:可以多线程访问,效率较高,速度较快。

常用方法:

  1. 声明一个ArrayList
ArrayList<String> list = new ArrayList<>();//泛型只能是引用类型,不能是基本类型!
//ArrayList<int> list = new ArrayList<>()错误!
//(因为ArrayList里面保存的地址值,而基本类型的数据没有地址值,应使用基本数据类型对应的包装类)
		基本类型        包装类(引用型,包装类都位于java.lang包下)
        byte            Byte
        short           Short
        int             Integer 【特殊】
        long            Long
        float           Float
        double          Double
        char            Character   【特殊】
        boolean         Boolean
  1. 添加数据(add)
list.add("yy");
list.add("ni");
list.add("zui");
list.add("shuai!");
//向集合当中添加数据,要用到add,返回值一定是true(因为添加一定成功)
System.out.println(list);//yynizuishuai!
//注意事项:对于ArrayList集合来说,直接打印不再输出地址值,而是内容(重写了toString方法)。
  1. 获取数据(get)
String list1 = list.get(0);//从集合中获取元素,参数是索引编号,返回值就是这个位置的元素
System.out.println(list1);//yy
  1. 删除数据(remove)
String list2 = list.remove(0);//从集合中删除元素,参数是索引编号,返回值就是这个被删除的元素
System.out.println(list2);//yy
System.out.println(list);//nizuishuai!
  1. 获取集合长度
int listSize = list.size();//获取集合的尺寸长度,返回值是这个集合中的元素个数
System.out.println(listSize);//3

2.2 LinkedList集合【次重点】

特点:

  1. LinkedList集合是一个双向链表,所以【查询慢,增删快】,很方便找到头和尾
  2. 此实现不是同步的:可以多线程访问,效率较高,速度较快。

常用方法:

  1. 添加数据
public void addFirst(E e): 将指定元素插入此列表的开头
public void addLast(E e):将指定元素插入此列表的结尾
public void push(E e):将元素推入此列表所表示的堆栈(等效于addFirst)
  1. 获取数据
public E getFirst():返回此列表的第一个元素
public E getLast():返回此列表的最后一个元素
  1. 删除数据
public E removeFirst():移除此列表的第一个元素,并返回被移除的元素
public E removeLast():移除此列表的最后一个元素,并返回被移除的元素
public E pop():从此列表所表示的堆栈处弹出一个元素(等效于removeFirst)

2.3 Vector集合【了解】

特点:

  1. Vector底层是一个数组,所以 【查询快,增删慢】;
  2. 此实现是同步的:所以被ArrayList取代了。

3、Set集合

特点:没有索引、不可以存储重复元素、存储无序;

3.1 HashSet集合【重点】

特点:

  1. HashSet集合底层是一个哈希表,查询的速度非常快;
  2. 因为没有索引,所以不能使用普通for循环遍历,只能使用迭代器循环或者增强for循环遍历集合。

哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,不是物理地址)。

int hashCode():返回该对象的哈希值
使用方法:对象名.hashCode();返回的就是该对象的哈希值

哈希表:对元素进行分组,拥有相同哈希值的元素会被分在同一组;每组中,用链表将相同哈希值的元素连接再一起,若链表的长度超过了8位,那么就会把链表转换为红黑树(提高查询的速度)。

Set集合不存储重复集合的原理:Set集合在调用add方法时,会调用元素的hashCode方法和equals方法,首先判断哈希值是否相同;若相同,使用equals方法判断哈希值相同的元素是否重复。

Set不存储重复元素的前提:存储的元素必须重写hachCode方法和equals方法。

所以在HashSet中存放自定义类型的元素时,需要【重写对象中的hachCode方法和equals方法】,建立自己的比较方式,才能保证集合中的对象是唯一的。

3.2 LinkedHashSet集合【次重点】

HashSet集合中的元素是唯一的,但是不保证元素有序

在HashSet集合下面有一个子类叫做java.util.LinkedHashSet,它是链表哈希表(数组+链表/红黑树)组合的一个数据存储结构:多了一条链表(记录元素的存储顺序),保证元素【存储有序】

4、Collections集合帮助类

java.util.Collections是集合工具类,提供了一系列静态方法,用来对集合进行操作。

public static <T> boolean addAll(Collection<T> c,T... elements):往集合中添加【一些】元素
public static void shuffle(List<?> list):打乱集合的顺序
public static <T> void sort(List<T> list):将集合中的元素按照默认规则排序(默认是升序)
public static <T> void sort(List<T> list,Comparator<? super T>):将集合中的元素按照指定规则排序

常用方法:

  1. 添加【一些】元素
/*
    public static <T> boolean addAll(Collection<T> c,T... elements):往集合中添加一些元素
 */
Collections.addAll(list,"a","b","c");//return true
System.out.println(list);//[a, b, c]
  1. 打乱集合顺序
/*
    public static void shuffle(List<?> list):打乱集合的顺序
 */
Collections.shuffle(list);
System.out.println(list);//[b, c, a]
  1. 默认规则排序
/*
    public static <T> void sort(List<T> list):将集合中的元素按照默认规则排序
 */
Collections.sort(list);
System.out.println(list);//[a, b, c],默认是升序

	//注意事项:sort方法的使用前提:被排序的集合里边存储的集合,必须实现Comparable接口,重写接口中的方法compareTo定义排序的规则
	@Override
    public int compareTo(Person o) {
//        return 0;//认为元素都是相同的
//        return this.getAge()-o.getAge();//按照年龄升序【记住升序降序的规律】
        return o.getAge()-this.getAge();//按照年龄降序
   }
  1. 指定规则排序
/*
	public static <T> void sort(List<T> list,Comparator<? super T>):将集合中的元素按照指定规则排序
	
	Comparator和Comparable的区别:
		Comparable:自己(this)和别人(参数)进行比较,自己需要实现Comparable接口,重写比较规则compareTo方法
		Comparator:参数和参数之间进行比较
         */
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,2,1,3,4,5);

        Collections.sort(list, new Comparator<Integer>() {//使用到了匿名内部类
            @Override
            public int compare(Integer o1, Integer o2) {
//                return o1-o2;//【升序】
//                return o2-o1;//【降序】
                return o2.compareTo(o1);//【降序】
            }
//            public int compare(String o1, String o2) {
//                return o1.charAt(0)-o2.charAt(0);//按照String类型的首字母升序
//            }
        });
        System.out.println(list);//[5, 4, 3, 2, 1]

5、Map集合

Map集合是双列集合;

特点:通过【键】可以找到值【值】、键和值是一一映射的关系、键是唯一的、值可以重复。

5.1 HashMap

java.util.HashMap<k,v>集合 implements Map<k,v>接口

特点:

  1. HashMap集合底层是哈希表:查询速度非常快;
    JDK1.8之前:数组+单向链表
    JDK1.8之后:数组+单向链表\红黑树(链表的长度超过8):提高查询的速度

  2. HashMap集合是一个无序的集合,存储元素和取出元素的顺序可能不一致

5.2 LinkedHashMap

java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合

特点:

  1. LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序)
  2. LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序一致

HashMap和LinkedHashMap的存储无序与有序的区别如下:

Map<String,String> map1 = new HashMap<>();
map1.put("a","a");
map1.put("c","c");
map1.put("b","b");
map1.put("d","d");
System.out.println(map1);//{a=a, b=b, c=c, d=d},而存储数据的顺序是“acbd”,存储无序

Map<String,String> map2 = new LinkedHashMap<>();
map2.put("a","a");
map2.put("c","c");
map2.put("b","b");
map2.put("d","d");
System.out.println(map2);//{a=a, c=c, b=b, d=d},存储有序

5.3 Map的常用方法

public V put(K key,V value):把指定的键和值添加到Map集合中
public V remove(Object key):把指定的键 所对应的键值对 在集合中删除,并且返回被删除的值
public V get(Object key):根据指定的键 返回集合中对应的值
boolean containsKey(Object key):判断集合中是否包含所对应的键
public Set<K> keySet():获取Map集合中所有的键,存储到Set集合中
public Set<Map.Entry<K,V>> entrySet():获取Map集合中国所有的键值对对象,存储到Set集合中
default V getOrDefault​(Object key, V defaultValue):返回key键所对应的值,如果找不到该键则返回默认值defaultValue
  1. 添加键值对
/*
    public V put(K key,V value):把指定的键和值添加到Map集合中
    返回值:
        存储键值对时,key之前不存在,返回值V是null
        key之前存在,则发生重复,会使用新的value值替换map集合中的value值,并返回被替换的value值
 */
Map<String, String> map = new HashMap<>();
String value = map.put("YY", "LJL");
System.out.println(map);//{YY=LJL}
System.out.println(value);//null

String value1 = map.put("YY", "LJL");
System.out.println(map);//{YY=LJL}
System.out.println(value1);//LJL
  1. 删除键值对
/*
    public V remove(Object key):把指定的键 所对应的键值对 在集合中删除,并且返回被删除的值
    返回值:V
        key存在,v返回被删除的值
        key不存在,v返回null
 */
String v1 = map.remove("LJL");//没有键“LJL”
System.out.println(v1);//返回null
String v2 = map.remove("YY");//有键“YY”
System.out.println(v2);//返回被删除的键所对应的值,LJL
  1. 根据键,返回值
/*
    public V get(Object key):根据指定的键 返回集合中对应的值
    返回值:
        key存在,返回对应的value值
        key不存在,返回null
 */
  1. 判断是否存在键
/*
    boolean containsKey(Object key):判断集合中是否包含所对应的键
    返回值:
        key存在,返回true
        key不存在,返回值false
 */
  1. 遍历所有的键值对的方式1
/*
    public Set<K> keySet():获取Map集合中所有的键,存储到Set集合中
    返回值:
        返回此映射中包含的键的Set视图
        
    Map集合的第一种遍历方式:通过键找值
    1、使用Map集合中的keySet()方法,把Map集合中的所有key取出来,存储到一个Set集合中
    2、遍历Set集合,获取Map集合中的每一个key
    3、通过Map集合中的get(key)方法,通过key找到value
*/
//创建Map
Map<String,Integer> map = new HashMap<>();
map.put("123",123);
map.put("234",234);
map.put("567",567);

//1、使用Map集合中的keySet()方法,把Map集合中的所有key取出来,存储到一个Set集合中
Set<String> set = map.keySet();
//System.out.println(set);//[123, 234, 567]

//2、遍历Set集合,获取Map集合中的每一个key

//使用迭代器遍历
Iterator<String> it = set.iterator();
while(it.hasNext()){
    String key = it.next();
    //3、通过Map集合中的get(key)方法,通过key找到value
    Integer value = map.get(key);
    System.out.println(key+"="+value);//123=123 234=234 567=567
}

//使用增强for循环遍历
for(String key:map.keySet()){
	//3、通过Map集合中的get(key)方法,通过key找到value
    Integer value = map.get(key);
    System.out.println(key+"="+value);//123=123 234=234 567=567
}
  1. 遍历所有的键值对的方式2
/*
    public Set<Map.Entry<K,V>> entrySet()//:
    返回值:
    	Map集合中所有的键值对对象Entry,存储到Set集合中(Set可以遍历。获取每个entry)
    	
   	Entry对象的方法:
   	public K getKey():获取key
   	public V getValue():获取value
   	
        
    Map集合的第二种遍历方式:通过Entry对象获取键和值
    1、使用Map集合中的entrySet()方法,把Map集合中的多个Entry对象取出来,存储到一个Set集合中
    2、遍历Set集合,获取每一个Entry对象
    3、使用Entry对象中的方法getKey()和getValue()获取键与值
*/
//1、使用Map集合中的entrySet()方法,把Map集合中的多个Entry对象取出来,存储到一个Set集合中
Set<Map.Entry<String, Integer>> set = map.entrySet();

//2、遍历Set集合,获取每一个Entry对象

//迭代器遍历Set
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while(it.hasNext()){
    Map.Entry<String, Integer> next = it.next();
    //3、使用Entry对象中的方法getKey()和getValue()获取键与值
    System.out.println(next.getKey()+"="+next.getValue());//123=123 234=234 567=567
}

//使用增强for循环遍历Set
for (Map.Entry<String, Integer> entry : set) {
	//3、使用Entry对象中的方法getKey()和getValue()获取键与值
    System.out.println(entry.getKey()+"="+entry.getValue());//123=123 234=234 567=567
}

5.4 Map集合存储自定义类型的键值

注意事项: Map集合需要保证key是唯一的:作为key的元素,需要【重写hashCode方法和equals方法,以保证key唯一】。

例如:

Map<Student, String> map = new HashMap<>();//Student作为键,必须重写hashCode和equals方法

5.5 HashTable集合

java.util.HashTable<K,V>集合 implements Map<K,V>接口;

区别:

HashMap集合底层也是一个哈希表,是一个线程不安全的集合,是多线程集合,速度快;

HashMap集合(之前学的所有集合):可以存储null值和null键

HashTable集合底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢;

HashTable集合:不可以存储null值和null键;

HashTable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap、ArrayList)所取代;但是HashTable的子类Properties集合,是一个唯一和IO流相结合的集合,。

5.6 List、Set、Map接口添加元素的新特性

JDK9新特性:

  1. List接口、Set接口、Map接口:添加了一个新的静态方法of,可以给集合一次性添加多个元素
static <E> List<E> of (E... elements)
  1. 使用前提: 集合中存储的元素个数已经确定。

注意事项:

  1. of方法只适用于List接口、Set接口、Map接口,不适用于接口的实现类(如ArrayList,HashSet,HashMap等等);
  2. of方法的返回值是一个不能改变的集合,集合不能使用add、put方法添加元素,否则会抛出异常;
  3. Set接口和Map接口在调用of接口的时候,不能有重复的元素,否则会抛出异常;

6、泛型

创建集合对象时,如果不使用泛型。那么默认的类型就是Object类型,可以存储任意类型的数据,看似非常美好。但是这引发了一个弊端:因为一个集合中存储了任意类型的数据,很容易引发异常,不安全。
所以在创建集合对象是,往往使用泛型,这有如下两点好处:

  1. 避免了类型转换的麻烦,存储什么类型,取出什么类型
  2. 把运行期异常提升到了编译期异常

但是也有坏处:泛型是什么类型,只能存储什么类型的数据,有了一定的局限性。

6.1 定义和使用含有泛型的类

泛型是一个未知的数据类型,当我们不确定使用什么数据类型时,就可以使用泛型;

泛型可以接收任意的数据类型,如Integer、String等等;

在创建对象的时候,再确定泛型的具体数据类型。

使用方法:

/*
    格式:
        public class 类名称<E>{
            //...
        }

 */
public class Demo01GenericClass<E> {
    private E name;

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }
}

6.2 定义和使用含有泛型的方法

定义含有泛型的方法:泛型定义在方法的【修饰符和返回值类型之间】

使用格式:

/*
	修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){
		//...
	}
*/
//定义一个含有泛型的方法
public <M> void Method01(M m){
	System.out.println(m);
}

//定义一个含有泛型的静态方法
public static <M> void Method02(M m){
	System.out.println(m);
}

6.3 定义和使用含有泛型的接口

定义一个含有泛型的接口:

/*
    格式:
        public interface 接口名称<E>{
            //抽象方法(参数列表为泛型)
        }

 */
public interface Demo01GenericInterface<E> {
    void method(E e);
}

实现 含有泛型的接口 的实现类之一:

/*
    第一种方式:在定义实现类的时候,指定接口的泛型的类型。
    格式:
        public class 实现类名称 implements 接口名称<泛型的类型>{
            //...
        }
 */
public class Demo01GenericInterfaceImpl01 implements Demo01GenericInterface<String>{
    @Override
    public void method(String s) {
        System.out.println(s);
    }
}

//调用这种实现类:不需要再指定泛型了
Demo01GenericInterfaceImpl01 dgi1 = new Demo01GenericInterfaceImpl01();
dgi1.method("yy");//yy

实现 含有泛型的接口 的实现类之二:

/*
    第二种方式:在定义实现类的时候,不指定泛型的类型
    格式:
        public class 实现类名称<泛型> implements 接口名称<泛型>{
            //...
        }
 */
public class Demo01GenericInterfaceImpl02<E> implements Demo01GenericInterface<E>{
    @Override
    public void method(E e) {
        System.out.println(e);
    }
}

//调用这种实现类,需要指定泛型的具体数据类型,如ArrayList等等
Demo01GenericInterfaceImpl02<Integer> dgi2 = new Demo01GenericInterfaceImpl02<>();
dgi2.method(22);//22

6.4 泛型通配符

当使用 有泛型的类或者接口 时,传递的数据的类型不确定,可以使用通配符<?>表示。

但是一旦使用了泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。

6.5 泛型通配符的高级使用:受限泛型

  1. 泛型的上限限定:<? extends E>:表示使用的泛型只能是E类型的子类/本身
  2. 泛型的下限限定:<? super E>:表示使用的泛型只能是E类型的父类/本身
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值