JAVA集合

JAVA集合类

java的集合类通常分为Set、List、Map和Queue四大体系(本次介绍前三种)

集合与数组的区别

集合和数组类似,都可以存放很多元素,但与数组不同的是,集合的长度是可以变化的,而数组的长度是固定不变的;数组是存放基本类型的数据,集合是用来存放对象的引用
Collection API
最基本的集合接口是Collection接口,根据组织的方式及实现功能不同,Collection的子接口分为两类:Set接口和List
各种类的关系
在这里插入图片描述

集合类型

从体系上讲集合的类型可归纳为三种:集(Set)、列表(List)、映射(Map)。
Set集合是无序的集合,Set集合中不区分元素的顺序,但不允许出现重复的元素。SortedSet继承Set接口,与Set集合相同也不允许出现重复的元素,单机和中的元素是有序排列的。
在这里插入图片描述

List集合是有序集,在List中元素的存储按照加入是的顺序排列,以索引的方式提供对元素的访问,且允许包含重复元素
在这里插入图片描述

映射中保存成对的“”键-值”(Key-Value)信息,Key和Value均为对象,映射中不能包含重复的键,键的排列是无序的,每个键最多只能映射一个值。SortMap继承Map接口,但他的键是有顺序集合。
在这里插入图片描述

List接口及ArrayList、Vector类

List接口的实现类主要有ArrayList、Stack、Vector和LinkedList
1、ArrayList常见使用法

public class Arraylist {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<String> list = new ArrayList<String>();
		list.add("张三");//使用List的方法将张三添加进去
		list.add("王五");
		list.add("李四");
		list.add("小红");
		list.add("小白");
		System.out.println(list);
		
		//使用索引操作list
		list.remove(1);//使用函数移除指定位置元素 从零开始
		System.out.println(list);
		
		list.add(1,"新王五");//使用add函数添加
		System.out.println(list);
		
		list.set(3, "取代小红");//替换指定位置元素
		System.out.println(list);
		
		System.out.println(list.get(3));//获取指定位置的元素
		
	}

}

运行结果:
在这里插入图片描述
addAll函数

 List<String> list = new ArrayList<>();
        List<String> list4 = new ArrayList<>();
        list4.add("数据库");
        list4.add("操作系统");
        list4.add("编译原理");
        System.out.println(list.size());
        list.add("java");
        list.add("python");
        list.add("c#");
        list.add("script");
        list.addAll(list4);

增强for循环输出与list的截取

for(String ipo:list){
            System.out.println(ipo);
        }
        //list的截取
        System.out.println("++++++++++++++++++++++");
        list=list.subList(1,2);//结尾的不截取
        for(String ipc:list){
            System.out.println(ipc);
        }

在这里需要注意的一项,在使用增强for循环的时候其本质就是使用java中迭代器,而是用迭代的时候是不允许对原来的内容进行任何操作。
插入数据底层的变化
在这里插入图片描述
在这里插入图片描述
可以看出修改的数据越靠后,使用的时间就越短。
原因分析
因为ArrayList结构是有序列表,在进行添加新数据的时候,按照索引查找到位置,将值赋值给索引出,然后将索引处后面的所有内容向后移动,而下标越小,需要向后移动的数据越多,因此需要的时间就越大。

2、Vector向量
Vector类也实现了LIst接口,也用于表述长度可变的对象数组列表。与ArrayList的差别是:Vector是同步(线程安全)的,运行效率较低,主要用在多线程环境中;而ArrayList不是同步的,适合在单线程的环境中使用。
3、Stack堆栈
堆栈是一种“先进后出”数据结构,可以形象比较成为弹夹,只能在一端进行输入输出,最后的进入的最先出来
Stack 使用实例

public class Test_Stack {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Stack<String> stack = new Stack<String>();
		stack.push("张三");//将字符串压入栈中
		stack.push("李四");
		stack.push("王五");
		stack.push("小红");
		System.out.println(stack);
		System.out.println("弹栈前:size="+stack.size());
		System.out.println("弹出元素:"+stack.pop());
		System.out.println("弹栈后栈中的元素:"+stack);
		System.out.println("弹栈后:size="+stack.size());
	}

}

运行结果
在这里插入图片描述
4、LinkedList
LinkedList实现的是一个双向链表。每个节点除含有元素外,还包含向前、向后的指针。
链表的查找规律:距离中间越远查找越快。
源码分析:
在这里插入图片描述
通过分析源码可以看出,每次查询的时候先判断索引与中间值进行比较,当大于中间值的时候就会从最后一个元素向前查找。

5、LinkedList与ArrayList使用上面的区别
由于二者的底层是不一样的因此使用的时候也有一些差异

  1. LinkedList底层是一个双向链表,因此在有关对元素进行操作的都选取LinkedList。
  2. ArrayList底层是顺序表,因此设计到查询的业务尽量选取ArrayList

Map接口及Hashmap接口

1、HashMap
使用方法

public class Test_Map {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Map<String,String> map = new HashMap<String,String>();
		
		//给map中添加元素
		map.put("王五", "董事长");
		map.put("张三", "经理");
		System.out.println(map);
		
		//根据指定的key获取对应的value
		String wang = map.get("王五");
		System.out.println(wang);
		
		//根根据key删除元素  并且会返回对应的value的值
		
		String value = map.remove("张三");
		System.out.println(value);
		System.out.println(map);
		
	}

}

结果:
在这里插入图片描述
1.1HashMap的遍历*

public class Test_Map {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Map<String,String> map = new HashMap<String,String>();
		
		//给map中添加元素
		map.put("王五", "董事长");
		map.put("张三", "经理");
		for(Map.Entry<String,String> entry: map.entrySet()) {
			System.out.println("key = "+entry.getKey()+", value = "+entry.getValue());
		}
	}

}

结果:
在这里插入图片描述

		Set<String> set = map.keySet();
        Integer value = map.get("A");

        for(String  str : set){
            Integer a = map.get(str);
            System.out.println(a);
        }

其实这里有四种遍历方法,这里只列出其中最常用的一种
一个好用的方法
System.out.println(map.getOrDefault(“f”,1000)); 在map中查找key为f查到的话返回查到的值,没有查到的话返回默认值1000
2、HashTable
HashMap是基于哈希表的Map接口的实现,此实现提供所有可选择的映射操作,并允许使用空(null)值和空(nulll)键。除了不同步和允许使用null之外,hashmap类与HashTable类大致相同。
3、HashTable和HashMap的区别

  1. HashMap没有锁 因此读写都不安全
  2. HashTable有锁机制,因此是线程安全的但是效率低,但是读写都是安全的。
  3. HashMap键允许为空,值也允许为空。
  4. HashTable键不允许为空,值也不允许为空。

Set接口和其实现类

Set接口中定义的常用方法和Conllection接口方法相同,另外Set对add()添加了限制,即不能添加相同的内容元素对象。主要接口的实现类有HashSet和TreeSet类

常见适用方法
住:没有get方法

public class Test_hashset {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Set<String> hs = new HashSet<String>();
		hs.add("张三");
		hs.add("李四");
		System.out.println(hs);
		
		hs.add("小王");
		hs.add("小王");
		System.out.println(hs);
	}

}

结果:
在这里插入图片描述
可以看到 自动过滤掉重复的内容了
set集合高级用法
因为set不允许有重复的但是当使用下面的这种方式,他不能判断类是否完全相同

Set<String> set = new HashSet();
        set.add("admin");
        set.add("root");
        set.add("test");
        set.add("administor");
//        for(String str : set){
//            //set.remove("admin");
//            //set.remove(str);
//            //出现错误的原因是使用迭代器时候不允许操作原来的内容 包括增删改查
//            System.out.println(str);
//        }
        Set<Student> set3 = new HashSet<>();
        Student student = new Student("2018005845",22,"山西太原");
        Student student1 = new Student("2018005845",22,"山西太原");
        Student student2 = new Student("2018005845",22,"山西太原");
        set3.add(student1);
        set3.add(student);
        set3.add(student2);
        System.out.println(set3);



	student类如下:
	public class Student {
    private String num;
    private int age;
    private String address;
	public Student(String num, int age, String address) {
        this.num = num;
        this.age = age;
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "num='" + num + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
    }

运行结果:
在这里插入图片描述从运行结果当中可以看出,三个类都输出了
分析原因:
因为在使用HashSet的add其实使用的HashMap的put函数
HashMap put源码

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)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                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
                            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);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

分析源码可以得出结论:
hashSet使用的是hashMap的put方法,而hashMap的put方法,使用hashCode()用key作为参数计算出hash值,然后进行比较,如果相同,再通过equals()比较key值是否相同,如果相同,返回同一个对象。
我们在使用的时候对象的对象的HashCode值不一样,因此添加的时候就把三个对象当成不一样的对象,因此最后三个对象都添加成功
解决这种问题的方法:
重写类中hashCode和equals方法
在student类中写:
在这里插入图片描述
书写的方式有很多种 只要能满足最后的结果即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值