集合2

深拷贝与浅拷贝

  1. ##### 引用拷贝:

引用拷贝不会在堆上创建一个新的对象,只会在栈上生成一个新的引用地址,最终指向依然是堆上的同一个对象

  1. ##### 浅拷贝

浅拷贝会在堆上创建一个新的对象,新对象和原对象不等,但是新对象的属性和老对象相同

其中:

  • 如果属性是基本类型(int,double,long,boolean等),拷贝的就是基本类型的值。
  • 如果属性是引用类型(除了基本类型都是引用类型),拷贝的就是引⽤数据类型变量的地址值,⽽对于引⽤类型变量指向的堆中的对象不会拷贝。
  1. ##### 深拷贝

完全拷贝⼀个对象,在堆上创建一个新的对象,拷贝被拷贝对象的成员变量的值,同时堆中的对象也会拷贝。

  1. ##### 区别:

浅拷贝只是简单的复制,对于对象里面的对象属性和数组属性只是复制了地址,并没有创建新的相同对象或者数组。而深拷贝是完完全全的复制一份,空间大小占用一样但是位置不同!!

Set

Set接口基本介绍:
  • 无序(添加和取出的顺序不一致),没有索引
  • 不允许重复元素,所以最多包含一个null
Set接口的常用方法:

和List接口一样,Set接口也是Collection的子接口,因此,常用方法和Collection接口一样

  1. add:添加单个元素
  2. remove:删除指定元素
  3. contains:查找元素是否存在
  4. size:获取元素个数
  5. isEmpty:判断是否为空
  6. clear:清空
  7. addAll:添加多个元素
  8. containsAll:查找多个元素是否都存在
  9. removeAll:删除多个元素
Set接口的遍历方式:

同Collection的遍历方式一样,因为Set接口是Collection接口的子接口。

  1. 可以使用迭代器
  2. 增强for
  3. 不能使用索引的方式来获取,所以不能用普通的for循环遍历

HashSet:

  1. HashSet实现了Set接口

  2. HashSet实际上是HashMap,源码如下:

        public HashSet(){
            map = new HashMap<>();
        }
    
  3. 可以存放null值,但是只能由一个null

  4. HashSet不保证元素是有序的,取决于hash后,再确定索引的结果

  5. 不能有重复元素/对象

例1:
    /*
        1、执行add方法后,会返回一个boolean值
        2、添加成功,返回true,否则返回false
        3、如果通过remove指定删除哪个对象
    */
    HashSet set = new HashSet();
    System.out.print(set.add("join"));  //T
    System.out.print(set.add("lucy"));  //T
    System.out.print(set.add("join"));  //F
    System.out.print(set.add("jack"));  //T
    System.out.print(set.add("Rose"));  //T
    set.remove("join");
    System.out.print("set=" + set);

    /*
        输出结果:
            T
            T
            F
            T
            T
            set=[Rose,lucy,jack]
    */
例2:
    HashSet set = new HashSet();
    set.add("lucy");    //添加成功
    set.add("lucy");    //添加失败
    set.add(enw Dog("tom"));    //添加成功
    set.add(enw Dog("tom"));    //添加成功
    System.out.print("set=" + set);

    set.add(new String("hsp")); //添加成功
    set.add(new String("hsp")); //添加失败
    //String常量池里面的地址一样

    class Dog{
        ……
    }
HashSet扩容机制:
  1. HashSet底层是HashMap
  2. 添加一个元素时,先得到hash值,会转成->索引值
  3. 找到存储数据表table,看到这个索引位置是否已经存放的有元素
  4. 如果没有,直接加入
  5. 如果有,调用equals比较,

​ 如果相同,就放弃添加,

​ 如果不相同,则添加到最后

  1. 在java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)
添加元素底层机制:
  1. 先获取元素的哈希值(hashCode方法)
  2. 对哈希值进行运算,得出一个索引值即为要存放在哈希表中的位置号
  3. 如果该位置上没有其他元素,则直接存放,

​ 如果该位置上已经有其他元素,则需要进行equals判断,

​ 如果相等,则不再添加。如果不相等,则以链表的方式添加

HashSet实践:
/*
    定义一个Employee类,包含private成员属性name,age
    要求:
        创建3个Employee对象放入HashSet中
        当name和age的值相同时,认为是同一个员工,不能添加到HashSet中
*/
class Employee{
    private String name;
    private int age;
    //构造器
    //get、set方法
    //重写toString
    /*
        如果name和age值相同,则返回相同的hash值
        idea快捷键:alt + insert -> 选择equals and hashCode()
    */
    @Override
    public boolean equals(Object o){
        if(this == o)return true;
        if(o == null || getClass() != o.getClass())return false;
        Employee employee = (Employee) 0;
        return age == employee.age &&
            Object.equals(name,employee.name);
    }
    @Override
    public int hashSet(){
        return Object.hash(name,age);
    }
}

public static void main(String[] args) {
    HashSet hashSet = new HashSet();
    hashSet.add(new Employee("milan",18));  //可以
    hashSet.add(new Employee("smith",28));  //可以
    hashSet.add(new Employee("milan",18));  //不可以
    /*没重写equals和hashSet之前,加入了3个,
        因为new了3个不同的对象,hash值不相同,得到的索引位置不同
      重写之后,加入了2个
    */
}

LinkedHsahSet:

  1. LinkedHsahSet是HashSet的子类
  2. LinkedHsahSet底层是一个LinkedHsahMap,底层维护了一个数组 + 双向链表
  3. LinkedHsahSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
  4. LinkedHsahSet不允许添重复元素
说明:
  1. 在LinkedHsahSet中维护了一个hash表和双向链表(LinkedHsahSet 有head和tail)
  2. 每一个节点有pre和next属性,这样可以形成双向链表
  3. 在添加一个元素时,先求hash值,再求索引,确定该元素在hashtable的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashsset一样])
        tail.next = newElement; //简单指定
        newElement.pre = tail;
        tail = newElement;
    
  4. 这样的话,我们遍历LinkedHsahSet也能确保插入顺序和遍历顺序一致

练习:
    Car类(属性:name,price),如果name 和 price一样,则认为是相同元素,就不能添加

    public class Car{
        private String name;
        private double price;
        //构造器
        //set,get
        //重写toString
    }

    public static void main(String[] args) {
        LinkedHsahSet linkedHsahSet = new LinkedHsahSet();
        linkedHsahSet.add(new Car("奥托",1000));
        linkedHsahSet.add(new Car("奥迪",300000));    
        linkedHsahSet.add(new Car("法拉利",10000000)); 
        linkedHsahSet.add(new Car("奥迪",300000));
        linkedHsahSet.add(new Car("保时捷",70000000));     
        linkedHsahSet.add(new Car("奥迪",300000));    
        //重写之前,全部都是new的新对象,所以都可以加入
        //重写equals和hashCode之后不

Map接口和常用方法:

Map接口实现类的特点:
  1. Map与Collection并列存在,用于保存具有映射关系的数据:Key-Value
  2. Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
  3. Map中的key不允许重复,原因和HashSet一样(当有相同的key,就等价于替换)
  4. Map中的value可以重复
  5. Map中的key可以为null,value也可以为null,注意key为null只能有一个,value为null可以有多个
  6. 常用String类作为Map的key
  7. key和value之间存在单向一对一关系,即通过指定的key总能找到对应的vaule
Map接口常用方法:
  1. put 添加
  2. remove 根据键删除映射关系
  3. get 根据键获取值
  4. size 获取元素个数
  5. isEmpty 判断个数是否为0
  6. clear 清除
  7. containsKey 查找键是否存在
Map六大遍历方式:
  • containsKey:查找键是否存在
  • keySet:获取所有的键
  • entrySet:获取所有关系
  • values:获取所有的值

    public static void main(String[] args) {
    Map map = new HashMap();
    map.put(“邓超”,”孙俪”);
    map.put(“王宝强”,”马蓉”);
    map.put(“宋喆”,”马蓉”);
    map.put(“刘令博”,”null”);
    map.put(“null”,”刘亦菲”);
    map.put(“鹿晗”,”关晓彤”);

    //第一组,先取出所有的Key,通过Key取出相应的Value
    Set keySet = map.KeySet();
    //方式一、增强for
    for (Object Key : keySet) {
        System.out.print(key + "-" +map.get(Key));
    }
    //方式二:迭代器
    Iterator iterator = keyset.Iterator();
    while(Iterator.hasNext()){
        Object key = iterator.next();
        System.out.print(key + "-" +map.get(Key));
    }
    
    //第二组:把所有的value取出
    Collection values = map.values();
    //可以使用所有Collection使用的遍历方法
    /*
        方式一、增强for
        方式二、迭代器
    */
    
    //第三组:通过EntrySet来获取 K-V
    Set entrySet = map.entrySet();
    //方式一、增强for
    for (Object entry : entrySet) {
        //将entry 转成 Map.Entey
        Map.Entry m = (Map.Entry) entry;
        System.out.print(m.getKey() + m.getValue());
    }
    //方式二、迭代器
    

    }

Map例题:
使用HashMap添加3个员工对象,要求:键:员工id;值:员工对象
并遍历显示工资>18000的员工
员工类:姓名、工资、员工id

class Emp{
    private String name;
    private double sal;
    private int id;
    /*
        构造器
        set
        get
        重写toString
    */
}
public static void main(String[] args) {
    Map hashMap = new HashMap();
    //添加对象
    hashMap.put(1,new Emp("jack",300000,1));
    hashMap.put(2,new Emp("tom",1000,2));
    hashMap.put(3,new Emp("milan",12000,3));

    //两种遍历方式

    //1、使用keySet -> 增强for
    Set keySet = hashMap.keySet();
    for (Object key : keySet) {
        //先获取value
        Emp emp = (Emp) hashMap.get(key);
        if(emp.getSal() > 18000){
            System.out.print(emp);
        }
    }

    //2、使用EntrySet -> 迭代器
    Set entrySet = hashMap.entrySet();
    Iterator iterator = entrySet.iterator();
    while(iterator.hasNext()){
        Map.Entry entry = (Map.Entry)iterator.next();
        //通过entry取得key和value
        Emp emp = (Emp) entry.getValue();
        if(……){
            ……
        }
    }
}

HashMap小结:

  1. Map接口的常用实现类:HashMap、Hashtable和Properties
  2. HashMap是Map接口使用频率最高的实现类
  3. HashMap是以key-val对的方式来存储数据
  4. key不能重复,但是值可以重复,允许使用null键和null值
  5. 如果添加相同的key,则会覆盖原来的key-val,等同于修改(key不会替换,value会替换)
  6. 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的(jdk8的hashMap底层 数组+链表+红黑树)
  7. HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

HashMap扩容机制(与HashSet相同):

  1. HashMap底层维护了Node类型的数组table,默认为null
  2. 当创建对象时,将加载因子(loadfactor)初始化为0.75,table表大于临界值(table*加载因子),就要开始扩容
  3. 当添加key-val时,通过key的哈希值得到在table的索引,然后判断该索引处是否有元素,

​ 如果没有元素直接添加,

​ 如果改索引处有元素,继续判断该元素的key是否和准备加入的key相等,

​ 如果相等,则直接替换val;

​ 如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容

  1. 第1次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)

  2. 以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的两倍,即24,依次类推

  3. 在java8中,如果一条链表的元素超过TREEIFY_THRESHOLD(默认是8),并且table的大小 > MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

HashTable的基本介绍:

  1. 存放的元素是键值对,即:K-Y
  2. hashtable的键和值都不能为null,否则抛出NullPointerException
  3. hashTable使用方法基本上和HashMap一样
  4. hashTable是线程安全的,hashMap是线程不安全的
案例:
    Hashtable table = new Hashtable();  //可以
    table.put("join",100);  //可以
    table.put(null,100);    //异常
    table.put("join",null); //异常
    table.put("lucy",100);  //可以
    table.put("lic",100);   //可以
    table.put("lic",88);    //替换

Hashtable和HashMap对比:

HashMap:

​ 版本:1.2

​ 线程安全(同步):不安全

​ 效率:高

​ 允许null键bull值:可以

Hashtable:

​ 版本:1.0

​ 线程安全(同步):安全

​ 效率:较低

​ 允许null键bull值:不可以

Properties:

  1. Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存数据
  2. 他的使用特点和Hashtable类似
  3. Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改
  4. xxx.properties文件通常作为配置文件,这个知识点在IO流列举

集合选型规则:

  1. 先判断存储的类型(一组对象或一组键值对)
  2. 一组对象:Collection接口

允许重复:List

增删多:LinkedList(底层维护了一个双向列表)

改查多:ArrayList(底层维护Object类型的可变数组)

不允许重复:Set

无序:HashSet(底层是HashMap,维护了一个哈希表,即(数组+链表+红黑树))

排序:TreeSet

插入和取出顺序一致:LinkedHashSet,维护数组,双向链表

  1. 一组键值对:Map
    1. 键无序:HashMap(底层是:哈希表;jdk7:数组+链表,jak8:数组+链表+红黑树)

    2. 键排序:TreeMap

    3. 键插入和取出顺序一致:LinkedHashMap

    4. 读取文件:Properties

Collections工具类:

Collections工具类介绍:
  1. Collections是一个操作Set、List和Map等集合的工具类
  2. Collections中提供了一系列静态的方法对集合元素进行排序,查询和修改等操作
排序操作(均为static方法)
  1. reverse(List):反转List中元素的顺序
  2. shuffle(List):对List集合元素进行随机排序
  3. sort(List):根据元素的自然顺序对指定List集合元素按升序排序
  4. sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
  5. swqp(List,int,int):将指定list集合中的i处元素和j处元素进行交换
查找、替换:
  1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  2. Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
  3. Object min(Collection)
  4. Object min(Collection,Comparator)
  5. int frequency(Collection,Object):返回指定集合中指定元素的出现次数
  6. void copy(List dest,List src):将src中的内容复制到dest中
  7. boolean replaceAll(List list,Object oldVAl,Object newVal):使用新值替换List对象的所有旧值
创作不易!转载请注明作者及文章链接或作者博客链接——
- 作者:pidanxia
- 链接:https://pidanxia.ink
(链接可为:**文章链接**或者**作者博客链接**)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇