您的当前位置:首页正文

Java 集合---尚硅谷Java入门视频学习

2024-11-27 来源:个人技术集锦
  • 问题:什么时候需要一个容纳数据的容器,也就是集合对象?
    Java集合框架中就包含了对不确定个数的数据处理的集合类
  • 问题:如果只是为了容纳数据,可以是直接使用数组,为什么要学习集合?
    数组使用起来不方便。在数据个数不确定的场合,数组使用起来不是很方便

根据数据的不同,Java的集合分为2大体系:

List :按照插入顺序保存数据,数据可以重复的
具体的实现类: ArrayList, LinkedList
Set : 集,无序保存,数据不能重复
具体的实现类 HashSet
Queue : 队列
具体的实现类:ArrayBlockingQueue

    1. 成对出现的数据体系 : Map接口定义了相关的规则
      所谓的成对的数据,就是2个数据有关系,可以根据第一个数据关联到第二个数据。
      也称之为键值对数据 ,(123123, zhangsan) => (key, value)

具体的实现 : HashMap, Hashtable

1.ArrayList

创建第一个集合对象:ArrayList

 ArrayList list = new ArrayList(3);
  1. 不需要传递构造参数,直接new就可以,底层数组为空数组
  2. 构造参数需要传递一个int类型的值,用于设定底层数组的长度
  3. 构造参数需要传递一个Collection集合类型的值,用于将其他集合中的数据放置在当前集合中
  • 增加数据
    添加数据时,如果集合中没有任何的数据,那么底层会创建长度为10的数组(扩容)
 	// add方法可以增加数据,只要将数据作为参数传递到add方法即可
    // 添加数据时,如果集合中没有任何的数据,那么底层会创建长度为10的数组
    list.add("zhangsan");
    list.add("zhangsan");
    list.add("wangwu");
    list.add("zhaoliu");
    // 获取集合中数据的条数
    System.out.println(list.size());
    // 获取指定位置的数据,可以采用索引的方式
    System.out.println(list.get(1));
    // 遍历集合中的数据
    for ( int i = 0; i < list.size(); i++ ) {
        //System.out.println("集合中的数据:" + list.get(i));
    }
    // TODO 如果循环遍历集合数据时,不关心数据的位置,那么可以采用特殊的for循环
    // for (循环对象:集合) {}
    for ( Object obj : list ) {
        System.out.println("集合中的数据:" + obj);
    }
// add方法可以传递2个参数的,第一个参数表示数据增加的位置(索引),第二个参数表示数据
list.add(1, "zhaoliu");

addAll()方法

		ArrayList list = new ArrayList();
        list.add("zhangsan");
        list.add("lisi");
        list.add("wangwu");
        list.add("zhangsan");
        list.add("zhangsan");
        ArrayList otherList = new ArrayList();
        otherList.add("1");
        otherList.add("2");
        otherList.add("3");
        list.addAll( otherList );//将otherList 集合追加到list集合末尾
  • 修改数据
    将指定位置的数据进行修改,set方法需要传递2个参数,第一个参数表示数据的位置,第二个参数修改的值。
    方法会返回结果,这个结果就是更新前的值
Object oldVal = list.set(1, "lisi");
System.out.println("修改前的值:" + oldVal);
  • 删除数据
    将指定位置的数据进行删除,remove方法需要传递1个参数,参数表示数据的位置。
    方法会返回结果,这个结果就是删除的值
Object removeVal = list.remove(1);
System.out.println("删除的值:" + removeVal);
// TODO 打印集合对象
System.out.println(list);
  • 其他常用方法
// size方法表示集合内部数据的数量
System.out.println(list.size());
// 清空集合中的数据
list.clear();
// 删除指定集合中的数据
list.removeAll(otherList);  //删除list集合中otherList集合里的数据
// 判断集合中的数据是否为空
System.out.println(list.isEmpty());
// 用于判断集合中是否存在某条数据,返回布尔类型的值
System.out.println(list.contains("zhangsan123"));
// 用于获取数据在索引中的第一个位置,如果数据不存在,那么返回-1
System.out.println(list.indexOf("zhangsan123"));
System.out.println(list.indexOf("zhangsan"));
System.out.println(list.lastIndexOf("zhangsan"));
//集合变数组
Object[] objects = list.toArray();
// 复制新集合
Object clone = list.clone();
ArrayList list1 = (ArrayList)clone;
System.out.println(list);
System.out.println(list1);

2.LinkedList

  • 构建集合对象
  LinkedList list = new LinkedList();
  • 添加数据
//添加数据
// 增加第一个数据
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
//向指定的位置添加数据 
list.addFirst("lisi"); //增加到数据的前面
list.addLast("2");//增加到数据的后面(默认)
list.add(1, "wangwu"); //添加到第一个位置(0和1之间)
//向集合中添加另一个集合
LinkedList list1 = new LinkedList();
list1.add("zhangsan1");
list1.add("lisi2");
list1.add("wangwu3");
list.addAll(list1);  //将list1集合追加到list集合末尾
  • 获取数据
System.out.println(list.getFirst());
System.out.println(list.getLast());
// 获取数据(遍历数据)
System.out.println(list.get(1));
for ( int i = 0; i < list.size(); i++ ) {
    System.out.println(list.get(i));
}
for ( Object obj : list ) {
   System.out.println(obj);
}
  • 修改数据
list.set(1, "zhaoliu");
  • 删除数据
   list.remove("zhangsan");
   list.removeFirst(); // 删除第一个
   list.removeLast(); // 删除最后一个
   list.remove(1);// 删除指定索引
  • 其他方法
System.out.println(list.size());
System.out.println(list.isEmpty());
list.clear();
list.contains("1");
list.element(); // 获取集合第一个数据
list.indexOf("");
list.lastIndexOf("");
list.push("aaa"); // 添加数据到第一个
System.out.println(list.pop()); // 弹出第一个数据

ArrayList和LinkedList对比

3.泛型

背景

public class Main{
    public static void main(String[] args) {
        Person6 person = new Person6();
        User6 user = new User6();
		ArrayList list = new ArrayList();
        list.add(person);
      	list.add(user);
        list.remove(0);
        // 从集合中获取的对象类型为Object
        Object o = list.get(0);
        // 如果想要执行对象的方法,那么需要进行强制类型转换
       if ( o instanceof  Person6 ) {
            Person6 p = (Person6)o;
            p.testPerson();
       }
    }
}
class Person6 {
    public void testPerson() {
        System.out.println("person...");
    }
}
class User6 {
    public void testUser() {
        System.out.println("user...");
    }
}

因为多态语法对对象的使用场景进行了约束,从集合中获取的对象类型为Object,不能直接调用对象类型本身的方法,可见集合对象在处理不同类型的数据时比较繁琐。
集合中没有约定存储数据的类型,不同类型的数据都可以存放在里面,保存了不同类型的数据后,处理起来机会比较麻烦。

泛型的使用

泛型和类型

public class Java07_Collection_Generic {
    public static void main(String[] args) {
        // 泛型语法
        // TODO 泛型和类型的区别
        // 有时,也把泛型称之为类型参数
        MyContainer<User7> myContainer = new MyContainer();
        //myContainer.data = new Object();

        // 类型存在多态的使用方式,但是泛型没有多态的概念
        test(myContainer);


    }
    public static void test(MyContainer<User7> myContainer) {
        System.out.println(myContainer);
    }
}
// TODO 容器类
class MyContainer<T> {
    public T data;
}
class User7 {

}

4.HashSet

  • 创建对象
 // HashSet : Hash + Set
// Hash : 哈希算法,散列算法
HashSet set = new HashSet();
  • 增加数据
    不会重复存储
// TODo 增加数据
set.add("zhangsan");
set.add("zhangsan");  
set.add("lisi");
set.add("wangwu");  //[zhangsan,lisi,wangwu]

不能修改数据 ,要修改只能先删除再增加。

  • 删除数据
//删除数据
set.remove("wangwu");
  • 查询数据
    数据没有对应的索引,没有查询数据的方法。要查询只能遍历
// TODo 查询数据
for (Object o : set) {
   System.out.println(o);
}
System.out.println(set);
}
  • 其他常用方法
HashSet set = new HashSet();
ArrayList list = new ArrayList();
list.add("zhangsan");
list.add("lisi");
list.add("wamngwu");
set.addAll(list);
Object[] objects = set.toArray();
System.out.println(set.isEmpty());
set.clear();
set.contains("zhangsan");
System.out.println(set.size());
Object clone = set.clone();
System.out.println(clone);
System.out.println(set);
  • 重复数据的问题
public class Java09_Collection_Set_2 {
    public static void main(String[] args) {

        
        HashSet set = new HashSet();

        User9 user1 = new User9();
        user1.id = 1001;
        user1.name = "zhangsan";
        System.out.println(user1.hashCode());

        User9 user2 = new User9();
        user2.id = 1001;
        user2.name = "zhangsan";
        System.out.println(user2.hashCode());

        User9 user3 = new User9();
        user3.id = 1002;
        user3.name = "lisi";

        set.add(user1);
        set.add(user2);
        set.add(user3);
        System.out.println(set);
    }
}
class User9 {
    public int id;
    public String name;
    @Override
    public String toString() {
        return "User["+id+", "+name+"]";
    }
}

传递给HashSet一个对象时,进行定位操作的方式:传递一个对象时,以对象的hashCode来做哈希运算,找到数据存放的位置。如果这个位置没有存放数据,则直接将数据存储,如果这个位置已经有数据,则通过equals()方法判断两个数据是否相等,如果相等,则直接丢弃即将要存入的数据;如果不相等,则通过链表将两个位置相同的数据连接起来进行存放(HashSet 底层数据结构为 数组 + 链表)。
如果要使HashSet以对象的属性值是否相同为标准,判断存入的两个对象是否相同,则需要将判断对象是否相等以及获取对象hashCode值的方法进行重写。

public class Java09_Collection_Set_2 {
    public static void main(String[] args) {

        // TODO 集合 - Collection - Set
        // HashSet 底层数据结构为 数组 + 链表

        HashSet set = new HashSet();
        User9 user1 = new User9();
        user1.id = 1001;
        user1.name = "zhangsan";
        System.out.println(user1.hashCode());

        User9 user2 = new User9();
        user2.id = 1001;
        user2.name = "zhangsan";
        System.out.println(user2.hashCode());

        User9 user3 = new User9();
        user3.id = 1002;
        user3.name = "lisi";

        set.add(user1);
        set.add(user2);
        set.add(user3);
        System.out.println(set);
    }
}
class User9 {
    public int id;
    public String name;

    @Override
    // 类似于内存地址
    public int hashCode() {
        return id;
    }

    @Override
    // 判断两个对象的属性是否完全相同
    public boolean equals(Object obj) {
        if ( obj instanceof User9 ) {
            User9 otherUser = (User9)obj;
            if ( otherUser.id == this.id ) {
                if ( otherUser.name.equals(this.name) ) {
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }
    @Override
    public String toString() {
        return "User["+id+", "+name+"]";
    }
}

如此,两个对象id值相同时,其hashCode值相同,进行哈希定位时其位置也相同;再根据重写的equals方法,可判断出两个对象属性完全相同,即两个数据为同一个值。因此上面的HashSet中只会存储两个对象。

5.Queue

  • 入队方法
// ArrayBlockingQueue : Array + Blocking(阻塞,堵住) + Queue
ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
// add方法如果增加数据增加不了,直接发生错误。
queue.add("zhangsan");
queue.add("lisi");
queue.add("wangwu");
queue.add("zhaoliu"); // 发生错误,Queue full
queue.put("zhangsan");
System.out.println("第一个人挂号");
queue.put("lisi");
System.out.println("第二个人挂号");
queue.put("wangwu");
System.out.println("第三个人挂号");
queue.put("zhaoliu");  // 不发生错误,但一直阻塞
System.out.println("第四个人挂号");
boolean zhangsan = queue.offer("zhangsan");
System.out.println(zhangsan);   // true
boolean lisi = queue.offer("lisi");
System.out.println(lisi);
boolean wangwu = queue.offer("wangwu");
System.out.println(wangwu);
boolean zhaoliu = queue.offer("zhaoliu");
System.out.println(zhaoliu);  // false
  • 出队方法
System.out.println(queue.poll());  // zhangsan
//当队列中没有数据时,执行此方法会输出null
System.out.println(queue.take());// zhangsan
//当队列中没有数据时,执行此方法会阻塞程序

6. HashMap

// HashMap : Hash + Map
// 数据存储是无序
HashMap map = new HashMap();
 // 添加数据:put
// 修改数据,put方法也可以修改数据,返回值就是被修改的值
map.put("zhangsan", "1");
System.out.println(map.put("zhangsan", "4"));  //key相同,value会被覆盖   输出覆盖的值 1
map.put("lisi", "2");
map.put("wangwu", "3");
// 修改数据 返回值就是被修改的值   如果不存在则返回null,且不会在map中添加
Object b = map.replace("b", "4"); 
System.out.println(b);
 //查询数据
System.out.println(map.get("zhangsan"));
// 删除数据
map.remove("zhangsan");
System.out.println(map);
map.remove("zhangsan", "1");  //删除键值对 key value都相同时才删除
// TODO 获取map集合中所有的key
Set set = map.keySet();
for (Object k : set) {
   System.out.println(map.get(k));  //获取key对应的value
}
System.out.println(map.containsKey("zhangsan"));
Collection values = map.values();
map.containsValue("1");
System.out.println(map);
HashMap<String, String> map = new HashMap();
// TODO 获取键值对对象
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
   System.out.println(entry.getKey() + "=" + entry.getValue()); //lisi=2
}

7.Hashtable

HashMap与Hashtable

  1. 实现方式不一样的 : 继承父类不一样
  2. 底层结构的容量不同: HashMap(16), Hashtable(11)
  3. HashMap的K,V都可以为null, Hashtable的K, V不能是null
  4. HashMap的数据定位采用的是Hash算法,但是Hashtable采用的就是hashcode
  5. HashMap的性能较高,但是Hashtable较低

8.迭代器

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
Set<String> keys = map.keySet();
for (String key : keys) {
    if ( "b".equals(key) ) {
	    map.remove("b");
    }
   System.out.println(map.get(key));
}

在遍历的时候修改会发生错误ConcurrentModificationException

// TODO 迭代器
        Iterator<String> iterator = keys.iterator();
        // hasNext方法用于判断是否存在下一条数据
        while (iterator.hasNext()) {
            // 获取下一条数据
            String key = iterator.next();
            if("b".equals(key)) {
                // remove方法只能对当前数据删除
                iterator.remove();
            }
            System.out.println(map.get(key));
        }

显示全文