Java笔记(集合、散列表、Map、泛型)

这篇具有很好参考价值的文章主要介绍了Java笔记(集合、散列表、Map、泛型)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、集合

1.Set和排序

  • set:无序不可重复
  • 无序:不保证有序,就是有可能有序,有可能无序
  • 不可重复:不能添加重复数据
  • HashSet
  • TreeSet:底层是红黑树,会自动排序,意味着里面存储的必须是同类型的元素对象
  • 数字:从小到大排序
  • 字符串:一次比较每一位的ascll码值
  • 日期:自然日期顺序

1.1.TreeSet

public class Collection_01_TreeSet {
	public static void main(String[] args) {
		Set set=new TreeSet();
		//添加,不可重复
		set.add(1);
		set.add(2);
		set.add(6);
		set.add(5);
		set.add(2);
		System.out.println(set);
		//删除,只能根据内容删除
		set.remove(2);
		System.out.println(set);
		//遍历
		for (Object object : set) {
			System.out.println(object);
		}
		set=new TreeSet();
		set.add("1");
		set.add("6");
		set.add("18");
		set.add("10");
		//根据ascll码比较从第一位开始比较,后面每一位都进行比较
		System.out.println(set);
	}
}

1.2.Comparable

  • 只有实现了comparable接口才可以自动排序,例如Integer,String
  • 如果我们添加的是自定义类型的对象,必须让该类也实现Comparable接口,并实现compareTo方法
  • 如果没有实现Comparable接口,向TreeSet中保存数据时会报错 类型转换异常( java.lang.ClassCastException: Day18.User cannot be cast to java.lang.Comparable )
@Override
	public int compareTo(Object o) {
		//this 是要添加的元素
		// 哦是集合中的元素
		if(o instanceof User){
			User oldUser=(User)o;
		//返回0说明相等,不再添加
		//返回大于0,说明要添加的元素比集合中的大,往后放
		//返回小于0,说明要添加的元素比集合中的小,往前放
			return this.age-oldUser.age;
		}
		return 0;
	}

源码

//把添加的对象转换为Comparable类型      
Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                //用要添加的元素调用compareTo方法把集合中的元素传入
                cmp = k.compareTo(t.key);
                if (cmp < 0) //返回值小于0的放左边
                    t = t.left;
                else if (cmp > 0)//返回值大于0的放右边
                    t = t.right;
                else
                    return t.setValue(value);//等于0则不添加
            } while (t != null);
import java.util.Set;
import java.util.TreeSet;

public class Collection_02_Sort {
	public static void main(String[] args) {
		//只有实现了comparable接口才可以自动排序,例如Integer,String
		//如果我们添加的是自定义类型的对象,必须让该类也实现Comparable接口,并实现compareTo方法
		//如果没有实现Comparable接口,向TreeSet中保存数据时会报错 类型转换异常( java.lang.ClassCastException: Day18.User cannot be cast to java.lang.Comparable )
		Set set=new TreeSet();
		set.add(new User(1));
		set.add(new User(66));
		set.add(new User(6));
		set.add(new User(666));
		System.out.println(set);
	}
}
class User implements Comparable{
	int age;
	public User(int age){
		this.age=age;
	}
	@Override
	public String toString() {
		return "User[age="+age+"]";
	}
	@Override
	public int compareTo(Object o) {
		//this 是要添加的元素
		// o 是集合中的元素
		if(o instanceof User){
			User oldUser=(User)o;
		//返回0说明相等,不再添加
		//返回大于0,说明要添加的元素比集合中的大,往后放
		//返回小于0,说明要添加的元素比集合中的小,往前放
			//return oldUser.age-this.age; 逆序
			return this.age-oldUser.age;
		}
		return 0;
	}
}

1.3.Comparator

  • 场景1 :
  • 使用TreeSet保存的数字(Integer)类型,此时由于Integer实现了Comparable接口,并且是按数值大小进行升序排序
  • 假如 我们需要降序排序 怎么办?
  • 场景2 :
  • 使用TreeSet要保存的数据,并没有实现Comparable接口,这样是存不进去的,怎么解决?
  • 以上两种场景,可以使用 comparator接口解决 , 只要使用comparator之后, 不管原来是否有comparable 都会按照comparator来进行排序
  • comparator优先级较高

源码

//如果comparator不是空就调用compare方法,如果为空就先转换为comparable,再调用compareTo方法,所以comparator优先级要高于comparable
@SuppressWarnings("unchecked")
    final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }

例:

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class Collection_03_Sort {
	public static void main(String[] args) {
		//将比较器类的对象传入就会按照比较器类的方式进行排序
		Set set =new TreeSet(new ComparatorImpl());
		set.add(1);
		set.add(666);
		set.add(6);
		set.add(66);
		System.out.println(set);
	}
}
//比较器类
class ComparatorImpl implements Comparator{
	@Override
	public int compare(Object o1, Object o2) {
        //o1是要添加的元素
		//o2是集合中的元素
		return (Integer)o2-(Integer)o1;
	}
}

匿名内部类方式:

Set set=new TreeSet(new Comparator() {
	@Override
	public int compare(Object o1, Object o2) {
		return (Integer)o2-(Integer)o1;
	}
});
set.add(1);
set.add(666);
set.add(6);
set.add(66);
System.out.println(set);

1.4.List排序

Collections中有一个sort方法,可以进行排序

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Collection_04_Sort {
	public static void main(String[] args) {
		List list =new ArrayList();
		list.add(1);
		list.add(5);
		list.add(7);
		list.add(3);
		//之所以可以使用sort方法,是因为Integer实现了comparable接口
		Collections.sort(list);
		//如果添加的元素没有实现comparable接口,或者排序规则不是我们想要的,可以通过comparator实现
		Collections.sort(list, new Comparator() {
			@Override
			public int compare(Object o1, Object o2) {
				return (Integer)o2-(Integer)o1;
			}
		});
		System.out.println(list);
	}
}

1.5.总结

Comparator 与 Comparable

  • 如果添加的元素类,是我们写的,比如 User ,那么我们想要排序,可以使用comparable来解决,这样还能保留comparator的扩展性

  • 如果添加的元素类,不是我们写的,意味着我们没办法修改对应的源码,就使用comparator来解决

2.Set

  • List 有序可重复
    • ArrayList : 查询快,底层是数组
    • LinkedList : 添加删除快,底层是双向链表
  • Set 无序不可重复
    • HashSet : 底层是散列表
    • TreeSet : 底层是红黑树,元素必须有序
  • Map 无序,key不能重复,value能重复,保存映射关系
    • HashMap : 底层是散列表
    • TreeMap : 底层是红黑树,元素必须有序

2.1.HashSet的使用

import java.util.HashSet;
import java.util.Set;

public class Collection_05_HashSet {
	public static void main(String[] args) {
		Set set=new HashSet();
		//不能重复
		set.add(1);
		set.add("c");
		set.add(7);
		set.add("b");
		set.add("c");
		set.add(6);
		set.add("a");
		//根据内容删除
		set.remove("c");
		for (Object object : set) {
			System.out.println(object);
		}
		System.out.println(set);
	}

二、散列表

1.概述

  • 散列表又叫哈希表,数组中保存的是单向链表

  • hash算法 : 是一种安全的加密算法,可以把不定长数据改为定长数据,并且不保证其唯一性

  • 其中算法包括 : 直接寻址法,数字分析法,平方取中法,折叠法,随机数法,除留余数法

  • map特性 : 无序,key不可重复,value可重复, 保存的是key和value键值对

  • Node : 1 key , 2 value , 3 next , 4 hash

  • 添加过程 :

    • 添加数据时(key,value) , 调用key的hashCode方法,生成hash值,然后通过hash算法得到数组下标
    • 如果该下标对应的空间中,没有数据,就创建一个Node对象,把key和value封装进去,保存到对应的下标上
    • ​ 如果该下标对应的空间中有数据,则调用key的equals方法,和空间中所有的数据进行比较
    • 如果没有相同的,则创建一个Node对象,保存在这个单向链表中的尾部
    • 如果equals判断有相同的,则不添加对应的key,value值替换原来的value

    1.8开始,为了提高查询效率,对链表进行了优化,如果数组对应的链表中的数据大于等于7(第八个),会把链表转换为红黑树

    当红黑树的个数小于6,则转换为链表

    红黑树:

    1. 节点是红色或黑色
    2. 根节点是黑色
    3. 每个叶子结点都是黑色的空节点(null)
    4. 不能有两个相邻的红色节点
    5. 从任一节点到每个叶子的所有路径都包含相同数目的黑色节点

源码:

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
 /**
     * The default initial capacity - MUST be a power of two.
     */
	//数组默认长度16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
	//最大容量2^30
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * The load factor used when none specified in constructor.
     */
    //加载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * The bin count threshold for using a tree rather than list for a
     * bin.  Bins are converted to trees when adding an element to a
     * bin with at least this many nodes. The value must be greater
     * than 2 and should be at least 8 to mesh with assumptions in
     * tree removal about conversion back to plain bins upon
     * shrinkage.
     */
	//链表个数达到8个,就转型红黑树
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * The bin count threshold for untreeifying a (split) bin during a
     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
     * most 6 to mesh with shrinkage detection under removal.
     */
	//红黑树个数小于6就转换为链表
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * The smallest table capacity for which bins may be treeified.
     * (Otherwise the table is resized if too many nodes in a bin.)
     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
     * between resizing and treeification thresholds.
     */
    static final int MIN_TREEIFY_CAPACITY = 64;

2.添加

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            //第一次添加时,创建散列表,长度默认16
            n = (tab = resize()).length;
     //就散下标,然后获取下标对应的数据
        if ((p = tab[i = (n - 1) & hash]) == null)
            //如果为null,说明改下表没有值
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            //p是数组中保存的第一个节点对象
            //判断key是否和p相同
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                //到这里说明key和p不一样,然后判断是否是红黑树类型
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {//到这里说明是链表
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            //如果链表长度大于等于7转换红黑树
                            treeifyBin(tab, hash);
                        break;
                    }
                     if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);//如果key已存在,则把value覆盖
                return oldValue;
            }
        }

三、Map

1.继承体系

Java笔记(集合、散列表、Map、泛型),java,笔记

2.常用方法

Java笔记(集合、散列表、Map、泛型),java,笔记

3.HashMap

在使用hashSet 和 hashMap的时候,想要代表对象的唯一性,需要同时覆写hashCode方法和equals方法

public class Collection_06_Hash {
	public static void main(String[] args) {
		HashMap map=new HashMap();
		//key不能重复,重复不添加
		map.put("a", "a1");
		map.put("b", "b1");
		//根据key删除这个映射关系
		map.remove("a");
		//如果key是未有的key,则为添加,如果key已存在,则是修改
		//修改的是value值,key不能修改
		map.put("b","b2");
		//根据key获取value值
		System.out.println(map.get("b"));
		//个数
		map.size();
		//是否包含某个key
		map.containsKey("b");
		//是否包含某个value
		map.containsValue("b1");
		//是否为空(个数为0)
		map.isEmpty();
		//清空
		map.clear();
		System.out.println(map);
		//遍历相关 map不能直接遍历
		map.put("a", "a1");
		map.put("b", "b1");
		//获取所有value值
		map.values();
		//把map中所有的key保存到set中,并返回
		Set set=map.keySet();
		for (Object object : set) {
			System.out.println(object+":"+map.get(object));
		}
		//把key和value封装到entry中,然后保存在set中返回
		Set entrys=map.entrySet();
		for (Object object : entrys) {
			Entry entry=(Entry)object;
			System.out.println(entry.getKey()+":"+entry.getValue());
		}
	}
}

4.TreeMap

public class Collection_07_TreeMap {
	public static void main(String[] args) {
		//和treeSet使用方式一样,只不过添加的时候需要使用put添加键值对
		TreeMap map=new TreeMap();
		//比较也是按照key比较,和value没有关系
		map.put("a", 666);
		map.put("a2", 666);
		map.put("a3", 666);
		map.put("a1", 666);
		//常用方法和HashMap类似
		System.out.println(map);
	}
}

四、泛型

1.概述

  • 泛型 : 编译时进行类型检查
  • 可以限制类型统一,并且在编译时进行类型校验,不符合条件的不能使用
  • 现在集合中 是可以保存任意元素 , 加上泛型之后,就只能保存某一种数据类型的元素
  • 泛型 不能写基本类型, 假如想写int ,就要写成Integer(int的包装类)

2.使用方式

public class Collection_08_Generic {
	public static void main(String[] args) {
		List list =new ArrayList();
		list.add(1);
		list.add("a");
		//未加泛型前可以传入各种类型
		for (Object object : list) {
			System.out.println(object);
		}
		List<String> list2=new ArrayList<String>();
		list2.add("a");
		//加了泛型后只可传入String类型(只能传一种)
		for (String string : list2) {
			System.out.println(string);
		}
	}
}

3.注意

泛型 不能写基本类型, 假如想写int ,就要写成Integer(int的包装类)文章来源地址https://www.toymoban.com/news/detail-826791.html

4.自定义泛型

  • E : element的简写,一般代表元素,而集合中或者数组中的数据,我们叫元素
  • K V : 表示的是键值对,一般在map中存储
  • N : Number
  • T : type,表示具体的一个java类型
  • ? : 表示不确定的类型
  • 如果规定了泛型,但是不设置泛型的话,则默认为Object
public class Collection_09_Generic {
	public static void main(String[] args) {
		MyClass myClass=new MyClass();
		myClass.m1(1);
		myClass.m1("a");
		MyClass<String> myClass2=new MyClass<String>();
		//只可传入泛型所规定的数据类型
		myClass2.m1("a");
	}
}
class MyClass<T>{
	public void m1(T t){
		System.out.println(t);
	}
}

5.面试题

  • Map以Value进行排序
  • Map是没有办法按照value排序的,因为源码中写死了,使用key进行比较
  • 所以只能保存到List中进行排序
public class Collection_10 {
	public static void main(String[] args) {
		Map<String,Integer> map=new HashMap<String, Integer>();
		map.put("a", 5);
		map.put("aaa", 9);
		map.put("aa", 7);
		map.put("6a6a6", 6);
		//把键值对取出
		Set set=map.entrySet();
		//转为list
		List<Entry<String, Integer>> list=new ArrayList<Map.Entry<String,Integer>>(set);
		//排序
		Collections.sort(list,new Comparator<Entry<String,Integer>>() {
			@Override
			public int compare(Entry<String, Integer> o1,
					Entry<String, Integer> o2) {
				//o1是要添加的元素,o2是集合中的元素
				//按value排序,大于零放后面,小于零放前面
				return o1.getValue()-o2.getValue();
			}
		});
		System.out.println(list);
	}
}

到了这里,关于Java笔记(集合、散列表、Map、泛型)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java集合-Collection & Map

    1.集合主要是两组:单列集合(Collection) , 双列集合(Map) 2.Collection 接口有两个重要的子接口 List ,Set . 他们的实现子类都是单列集合 3.Map 接口的实现子类 是双列集合,存放的 K-V 单列集合的顶级接口,含有Iterator()方法,主要用于遍历Collection集合中的元素 Collection的所有实现类都有

    2024年02月09日
    浏览(47)
  • Java基础——Map集合遍历方式

    (1)方式一:键找值 先获取Map集合的全部键的Set集合。 遍历键的Set集合,然后通过键提取对应值。 涉及API: 方法名称 说明 SetK keySet() 获取所有键的集合 V get(Object key) 根据键获取值 (2)方式二:键值对 先把Map集合转换成Set集合,Set集合中每个元素都是键值对实现类型了。

    2023年04月10日
    浏览(41)
  • 【Java】Map集合中常用方法

    Map集合的常用方法 方法名称 作用 V put(Key k,V value) 添加元素 V remove(K key, V value) 根据键值删除对应的值 void clear() 清除所有键值元素 boolean containsKey(Object key) 判断集合中是否包含指定的键 boolean containsValue(Object value) 判断集合中是否包含指定的值 boolean isEmpty() 判断集合是否为空

    2024年02月08日
    浏览(40)
  • Java集合利器 Map & Set

    Map 和 Set 是一种专门用来进行搜索的数据结构,其搜索的效率与其具体的实例化子类有关。它们分别定义了两种不同的数据结构和特点: Map(映射) :Map是一种键值对(key-value)的集合,每个键值对都是一个元素。 Set(集合) :Set是一种不允许重复元素(key)的集合。 通

    2024年02月12日
    浏览(37)
  • Java 集合Map相关面试题

    📕作者简介: 过去日记 ,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。 📗本文收录于java面试题系列,大家有兴趣的可以看一看 📘相关专栏Rust初阶教程、go语言基础系列、spring教程等,大家有兴趣的可以看一看 📙Java并发编程系列,设计模式系列、

    2024年01月25日
    浏览(37)
  • Java集合(List、Set、Map)

    Java中的集合是用于存储和组织对象的数据结构。Java提供了许多不同的集合类,包括List、Set和Map等,以满足不同的需求。下面将介绍一些常见的Java集合类及其使用方法。 一、List List是一个有序的集合,它允许元素重复出现,并提供了索引访问元素的功能。List可以通过以下方

    2024年02月16日
    浏览(41)
  • Java中Map集合初始化并赋值

    Java中Map集合初始化并赋值的几种方式:

    2024年02月11日
    浏览(53)
  • Java的集合类:List、Set、Map

    在 Java 中,集合类是一组有序或无序的数据元素的集合。Java 集合类可用于存储和操作各种数据类型的元素,如整数、字符串、对象等。集合类是动态的,可以在运行时根据需要调整其大小。 Java 集合类可以分为三类: List - 有序集合,允许重复元素 Set - 无序集合,不允许重

    2024年02月16日
    浏览(48)
  • Java8 - 将 List 集合转为 Map

    1. 将List转为Map:key=userId, value=name 输出: 2. 将List转为Map:key=userId, value=User对象 输出: 3. 重复的 key 处理 如果出现相同的key,那么会抛出重复key的异常,比如我们将userId为3的修改为2,则会和第二个用户冲突: 抛出异常: Collectors.toMap支持第三个参数,对重复值进行选取:

    2024年02月08日
    浏览(103)
  • Java-集合框架-List,Set,Map,队列

    Java集合框架是一组用于存储和操作数据的类和接口。它提供了不同类型的集合,如List,Set,Map和队列,以满足不同的需求。 List:有序的集合,允许重复的元素。 Set:无序的集合,不允许重复的元素。 Map:键值对的集合,每个元素都包含一个键和一个值。 队列:先进先出(

    2024年02月11日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包