java 集合

1.简介

1.面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。数组虽然也可以存储对象,但长度是固定的;集合长度是可变的,数组中可以存储基本数据类型,集合只能存储对象。集合类的特点:集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象

2.集合图

 

 2.Collection接口

1.collection常用方法

  • 一组称为元素的对象
  • 个Collection中可以放不同类型的数据 (Object)当然你可以指明类型
  • 是Set接口和List接口的父类
  • Set - 无序的集合;不允许重复(哈希表实现唯一)HashSet
  • List - 有序的集合;允许重复 ArrayList(数组实现) LinkedList(链表实现)

 

3.Set接口

  • Collection的子接口
  • 用来包含一组 无序无重复 的对象 

1.Set接口的实现类

  • HashSet — HashSet的特性在于其内部对象的散列存取,即采用哈希技术(不要排序使用)
  • TreeSet — TreeSet存入的顺序跟存储的顺序不同,但是存储是按照排序存储的(排序使用)
// 创建集合对象  HashSet:不保证 set 的迭代顺序,特别是它不保证该顺序恒久不变。
// 哈希表由hashCode()和equals()方法来保证元素的唯一性。
		Set<String> set = new HashSet<String>();

		set.add("hello");
		set.add("aaaa");
		set.add("java");
		set.add("world");
		set.add("bbbb");
		set.add("aaaa");//已有相同,不会被插入
		set.add("aaaa");//已有相同,不会被插入
		
		//[java, world, hello, aaaa, bbbb]
		System.out.println(set);
/*
 * LinkedHashSet:底层数据结构是哈希表和链表。
 * 哈希表:能够保证元素的唯一性
 * 链表:能够保证元素有序
 */
public class LinkedHashSetDemo {
	public static void main(String[] args) {
		LinkedHashSet<String> link = new LinkedHashSet<String>();

		link.add("ccc");
		link.add("hello");
		link.add("bbb");
		link.add("world");
		link.add("aaa");
		link.add("java");
		link.add("aaa");
		link.add("java");

		System.out.println("link:" + link);
                //link:[ccc, hello, bbb, world, aaa, java]
	}
}
/*
 * TreeSet:底层数据结构是二叉树。
 * 可以让元素排序,有两种方案,分别是:自然排序,以及Comparator(比较器)进行排序,具体使用哪种情况看你使用的构造方法。
 */
public class TreeSetDemo {
	public static void main(String[] args) {
		// 20,18,23,22,17,24,19,18,24
		// 构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
		TreeSet<Integer> ts = new TreeSet<Integer>();

		// 存储元素
		ts.add(20);
		ts.add(18);
		ts.add(23);
		ts.add(22);
		ts.add(17);
		ts.add(24);
		ts.add(19);
		ts.add(18);
		ts.add(24);

		// [17, 18, 19, 20, 22, 23, 24]
		System.out.println(ts);
	}
}

2.使用HashSet储存自定义对象时必须重写equals和hashcode方法

如下例:

   a.

public class User {
  private String number;
  private String name;  
  private Integer age;    

  public User() {
  }

  public User(String number, String name, Integer age) {

      this.number = number;
      this.name = name;
      this.age = age;
  }


  public String getNumber() {
      return number;
  }

  public void setNumber(String number) {
      this.number = number;
  }

  public String getName() {
      return name;
  }

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

  public Integer getAge() {
      return age;
  }


  public void setAge(Integer age) {
      this.age = age;
  }

  @Override
  public String toString() {
      return "User{" +
              "number='" + number + '\'' +
              ", name='" + name + '\'' +
              ", age=" + age +
              '}';
  }
}
public class Test {
    public static void main(String[] args) {
        HashSet<User> set = new HashSet<>();
        User user1 = new User("1", "sj", 11);
        User user2 = new User("1", "sj", 11);
        set.add(user1);
        set.add(user2);
        System.out.println(set.size());//结果为2,自定义对象hashcode可能会相同
    }
}

 

如上结果为2,两个相同的数据还是添加进去了(因为是两个对象的引用地址并不同,认为是不同的对象,这个就需要我们重写 equals 和 hashCode方法

HashSet集合对象如何判断数据元素是否重复:

            检查待存对象hashCode值是否与集合中已有元素对象hashCode值相同,如

            果hashCode不同则表示不重复, 如果hashCode相同再调用equals方法进一步检查

           equals返回真表示重复,否则表示不重复。
 

2.如何解决呢?HashSet是基于 equals 和 hashCode来去重的,只需要重写equals 和 hashCode方法

public class User {
     private String number;//学号
     private String name;   //姓名
     private Integer age;    //年龄

    //无参构造函数    
     public User() {
     }

    //3个参数的构造函数
     public User(String number, String name, Integer age) {
         this.number = number;
         this.name = name;
         this.age = age;
     }


     public String getNumber() {
         return number;
     }

     public void setNumber(String number) {
         this.number = number;
     }

     public String getName() {
         return name;
     }

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

     public Integer getAge() {
         return age;
     }


     public void setAge(Integer age) {
         this.age = age;
     }

     @Override
     public boolean equals(Object o) {
         //判断传入的是否为同一个对象
         if (this == o) return true;
         //判断传入的对象是否为空,是不是相同的类
         if (o == null || getClass() != o.getClass()) return false;
        //强转
         User user = (User) o;
        //判断学号是否相同
         if (number != null ? !number.equals(user.number) : user.number != null) return false;
         //判断姓名是否相同
         if (name != null ? !name.equals(user.name) : user.name != null) return false;
         //判断年龄是否相同
         return age != null ? age.equals(user.age) : user.age == null;
     }

    /**
     * Hash值的获取方式
     * @return
     */
     @Override
     public int hashCode() {
         //获取学号、姓名、年龄的 hashCode 分别乘以 31
         int result = number != null ? number.hashCode() : 0;
         result = 100 * result + (name != null ? name.hashCode() : 0);
         result = 100 * result + (age != null ? age.hashCode() : 0);
         return result;
     }

     @Override
     public String toString() {
         return "User{" +
                 "number='" + number + '\'' +
                 ", name='" + name + '\'' +
                 ", age=" + age +
                 '}';
     }
}
public class Test {
    public static void main(String[] args) {

        HashSet<User> set = new HashSet<>();
        User user1 = new User("1", "sj", 22);
        User user2 = new User("1", "sj", 22);
        set.add(user1);
        set.add(user2);
        System.out.println(set.size());//结果为一
    }
}

 

 

 

 

 

4.List接口

  • Collection的子接口
  • 用来包含一组 有序有重复 的对象
  • List中的元素都对应一个整数型的序号,记载其在容器中的位置,可以根据序号存取容器中的元素

1.List有两种主要的集合实现类

  • ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快
  • LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合。而 LinkedList 提供了大量首尾操作的方法。它可以非常方便的实现我们数据结构中的常见的Stack(栈)、queue(队列)等。

List:
 *         ArrayList:
 *             底层数据结构是数组,查询快,增删慢
 *             线程不安全,效率高
 *         Vector:
 *             底层数据结构是数组,查询快,增删慢
 *             线程安全,效率低
 *         LinkedList:
 *             底层数据结构是链表,查询慢,增删快
 *             线程不安全,效率高
 * 

2.List接口常用方法

 

3.LinkedList增加方法

List -> ArrayList

/*
 * List集合的特有功能:
 * 		void add(int index,Object obj):在指定索引位置添加元素
 *		Object remove(int index):删除指定索引位置的元素,并把删除掉的元素值返回
 *		Object get(int index):根据给定索引,返回元素
 *		Object set(int index,E element):修改指定索引处的元素为给定的元素,并返回被修改的值
 */
public class ListDemo {
	public static void main(String[] args) {
		// 创建集合
		// Collection c = new ArrayList();
		List list = new ArrayList();

		// 测试功能
		list.add("hello");
		list.add("world");
		list.add("java");

		// void add(int index,Object obj):在指定索引位置添加元素
		// list.add(1, "android");
		// list.add(3, "android");
		// list.add(4, "android"); //有问题

		// Object remove(int index):删除指定索引位置的元素,并把删除掉的元素值返回
		// System.out.println("remove:" + list.remove(1));

		// Object get(int index):根据给定索引,返回元素
		// System.out.println("get:" + list.get(1));

		// Object set(int index,E element):修改指定索引处的元素为给定的元素,并返回被修改的值
		System.out.println("set:" + list.set(1, "android"));

		System.out.println("list:" + list);
	}
}

 List->  Vector

	Vector v = new Vector();

		// public void addElement(Object obj)
		v.addElement("hello");
		v.addElement("world");
		v.addElement("java");
		// 类似迭代器的方式
		Enumeration en = v.elements();
		while (en.hasMoreElements()) {
			String s = (String) en.nextElement();
			System.out.println(s);
		}

		System.out.println("v:" + v);
	}

 

// 创建集合对象
		LinkedList link = new LinkedList();

		// 添加元素
		link.add("hello");
		link.add("world");
		link.add("java");

		// void addFirst()
		// void addLast()
		// link.addFirst("android");
		// link.addLast("javaee");

		// Object removeFirst()
		// Object removeLast()
		// System.out.println("removeFirst:" + link.removeFirst());
		// System.out.println("removeLast:" + link.removeLast());

		// Object getFirst()
		// Object getLast()
		System.out.println("getFirst:" + link.getFirst());
		System.out.println("getLast:" + link.getLast());

		System.out.println("link:" + link);
	}

 

 

5.Iterator接口

  • Iterator对象称作迭代器,用来方便的实现对容器内的元素进行遍历操作 
  • 所有实现了Collection接口的集合类都有一个iterator( )方法,返回一个实现了Iterator接口的对象
  • Iterator对象实现了统一的一个用来遍历Collection中对象的
  • Iterator是为遍历而设计,能够从集合中取出元素和删除元素,但是没有添加元素的功能

1.Iterator常用方法

2.Iterator 的并发修改异常

public class IteratorDemo {
//在 list 集合迭代元素中,对元素进行判断,一旦条件满足就添加一个新元素
public static void main(String[] args) {
//创建 List 集合
List<String> list = new ArrayList<String>();
//给集合中添加元素
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
//迭代集合,当有元素为"abc2"时,集合加入新元素"Jss"
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
//判断取出的元素是否是"abc2",是就添加一个新元素
if("abc2".equals(str)){
list.add("Jss");// 该操作会导致程序出错
}
}
//打印容器中的元素
System.out.println(list);
}
}

运行上述代码发生了错误 java.util.ConcurrentModificationException 这是什么原因呢?
在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性 

并发修改异常解决办法:在迭代时,不要使用集合的方法操作元素。
那么想要在迭代时对元素操作咋办?通过 ListIterator 迭代器操作元素是可以的,ListIterator 的出现,
解决了使用 Iterator 迭代过程中可能会发生的错误情况

public class test {
	public static void main(String[] args) {
		List<String> list=new ArrayList<String>();
		
		list.add("1");
		list.add("2");
		list.add("3");
		
		ListIterator<String> it=list.listIterator();
		while(it.hasNext()) {
			String s=it.next();
			if("2".equals(s)){
				it.add("4");
			}
			System.out.println(s);
		}
		System.out.println(list);
	}

}

6.Collections类

  • 其实就是针对集合进行操作的工具类
  • Collections类是类似于Arrays类的公用工具类 ,它提供了一些static方法供集合类使用或操作集合类

1.Collections类中的

 

	// 创建集合对象
		ArrayList<Integer> array = new ArrayList<Integer>();

		// 添加元素
		array.add(30);
		array.add(20);
		array.add(50);
		array.add(10);
		array.add(40);
		Collections.sort(array);
		System.out.println("array:" + array);

                // Integer max = Collections.max(array);
                // int index = Collections.binarySearch(array, 30);

7.Map接口

  • Map内存储的是键/值对这样以成对的对象组(可以把一组对象当成一个元素),通过“键”对象来查询“值”对象
  • Map是不同于Collection的另外一种集合接口
  • Map中,key值是唯一的(不能重复),而key对象是与value对象关联在一起的
  • Map接口有两个实现:HashMap — key/value对是按照Hash算法存储的
    TreeMap — key/value对是排序(按key排序)存储的基于树实现

  • HashMap (线程不安全,允许将null作为一个entry的key或者value,)哈希表实现

  • TreeMap 对是排序(按key排序)存储的基于树实现

  • HashTable(线程安全,Hashtable不允许用null)

  HashMap:
   特点:
      是 Map 集合的子集合
      底层采用哈希表结构
      HashMap 集合中的 key 不能重复,通过重写 hashCode() 与 equals()方法来保证键的唯一。
      不能保证元素存与取的顺序完全一致
 LinkedHashMap:
   特点:
     是 HashMap 集合的子集合
     底层采用哈希表+链表结构
     LinkedHashMap 集合中的 key 不能重复,通过重写 hashCode() 与 equals()方法来保证键的唯一。

1.Map接口常用方法

2.HashMap与TreeMap的比较

  • HashMap基于哈希表实现。
  • TreeMap基于树实现。
  • HashMap可以通过调优初始容量和负载因子,优化HashMap空间的使用。
  • TreeMap没有调优选项,因为该树总处于平衡状态
  • HashMap性能优于TreeMap

3.HashMap与Hashtable的比较

  • Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
  • Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
  • HashMap允许将null作为一个entry的key或者value,而Hashtable不允许用null。

 

 

Map:元素是按照键值对形式存储的。每一对元素由两部分组成。分别叫键和值
 *               键是唯一的,值是可以重复的。
 *              所以Map集合的底层数据结构是针对键有效,跟值无关。
 *
 * Map接口和Collection接口的不同?
 *         A:Map集合是双列集合;Map集合的键是唯一的,值是可以重复的。其实我们也可以简单的理解为Map集合的键和值是由Set和List组成;数据结构针对键有效。
 *         B:Collection集合是单列集合;Collection集合的儿子Set是唯一的,List是可以重复的;数据结构针对元素有效。
 *
 * Map集合的功能:
 *         A:添加功能
 *             V put(K key,V value):添加,替换或者修改。键不同,添加到集合。键相同,值替换。
 *         B:移除功能
 *             void clear():移除所有映射关系
 *             V remove(Object key):根据键移除键值对元素,返回的是键对应的值
 *         C:判断功能
 *             boolean containsKey(Object key):判断Map集合中是否包含指定的键
 *             boolean containsValue(Object value):判断Map集合中是否包含指定的值
 *             boolean isEmpty():判断集合是否为空
 *         D:获取功能
 *             Set<Map.Entry<K,V>> entrySet():返回的是键值对对象的Set集合。
 *             V get(Object key):根据键获取值
 *             Set<K> keySet():所有的键的集合
 *             Collection<V> values():所有值的集合
 *             int size():集合的长度
 */ 

HashMap -获取key-value -------1

/*
 * V get(Object key)
 * Set<K> keySet()
 * Collection<V> values()
 */
public class MapDemo2 {
	public static void main(String[] args) {
		// 创建集合对象
		Map<String, String> map = new HashMap<String, String>();

		// 创建并添加元素
		map.put("1", "java");
		map.put("2", "php");
		map.put("3", "android");
		map.put("4", "go");

		// V get(Object key)
		System.out.println("get:" + map.get("1"));
		System.out.println("get:" + map.get("2"));
		System.out.println("---------------------");

		// Set<K> keySet() 获取Map集合的所有的键的Set集合
		Set<String> set = map.keySet();
		for (String key : set) {
			System.out.println(key);
		}
		System.out.println("---------------------");

		// Collection<V> values() 获取Map集合的所有的值的Collection集合
		Collection<String> cons = map.values();
		for (String value : cons) {
			System.out.println(value);
		}
	}
}

 HashMap -获取key-value -------2   Set<Map.Entry<K,V>> entrySet()(建议使用该方式遍历效率高)

public class MapDemo4 {
	public static void main(String[] args) {
		// 创建集合对象
		Map<String, String> map = new HashMap<String, String>();

		// 创建并添加元素
		map.put("1", "java");
		map.put("2", "php");
		map.put("3", "android");
		map.put("4", "go");

		// 遍历
		// 获取所有的键值对对象的Set集合。
		Set<Map.Entry<String, String>> set = map.entrySet();
		// 遍历键值对对象的Set集合,得到每一个键值对对象。
		for (Map.Entry<String, String> me : set) {
			// 根据键值对对象去获取键和值。getKey(),getValue()
			String key = me.getKey();
			String value = me.getValue();
			System.out.println(key + "---" + value);
		}
	}
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值