java--集合(2)--黑马程序员

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

集合(2)

主要内容:《 泛型、泛型的方法、接口、通配符、增强for、可变参数、静态导入、嵌套、Set集合 》

 

前言:为什么使用泛型


1.对于集合类,就其本身而言,是可以添加任何的引用类型。因为它的add()方法的形参是Object类型;
2.但,这样在我们取出时,会造成很大的麻烦,我们总要向下转型为我们存储的类型;一旦判断失误,就会导致
 转换失败,会抛出异常。
3.我们在平时使用集合类时,更多的情况是"只存储一种类型"。
4.所以这时,Java为我们提供了一种方式,可以在定义集合时,就规定好这个集合内能够存储什么类型的数据,
 一旦定义之后,它的add()方法就只能接受那种类型的数据。这种方式:泛型

 5.泛型的语法:
 ArrayList<String> list = new ArrayList<String>();
 或者:
 ArrayList<String> list = new ArrayList<>();(比较常用)
 或者:
 ArrayList<String> list = new ArrayList();

 6.注意:泛型:只在"编译期"存在。一旦生成class文件后,泛型信息就没有了。
 说明,只是用在"编译"时,进行"类型检查"。

1.泛型的格式与定义

格式:
ArrayList<String> strList = new ArrayList<String>();
或者:
ArrayList<String> strList = new ArrayList<>();(建议使用)
或者:
ArrayList<String> strList = new ArrayList();
2.泛型的定义:
1).泛型类:
class MyArrayList<T>{
public void show(T t){
}
}
说明:
A.<T>就是一个泛型的定义,在类名的后面;
B.可以使用大写或小写字母,或单词都可以;<T>,<t>,<a,b>
C.可以定义多个泛型,多个泛型之间用,逗号隔开;<T,B,C>

2.泛型的方法

class MyArrayList{
//此方法能够保证:传入的是什么类型,返回的就是什么类型;
public <T> T show(T t){
}
}

3.泛型接口

interface IA<T>{
void show(T t);
}
当子类实现时:
1.可以继续使用泛型:
class SubA<T> implements IA<T>{
void show(T t){
}
}
2.可以丢弃泛型:
class SubA implements IA{
void show(Object obj){
}
}
3.可以定义为某个具体类型:
class SubA implements IA<String>{
void show(String str){
}
}

4.泛型通配符:


 1.<?>:
 1).能够指向什么类型的对象?可以指向具有任何具体类型泛型的集合对象;
 ArrayList<?> list1 = new ArrayList<>();//OK的
 ArrayList<?> list2 = new ArrayList<String>();//OK的
 ArrayList<?> list3 = new ArrayList<Integer>();//OK的
 2).可以添加什么类型的引用?
 list1:不能添加任何类型;
 list2:不能添加任何类型;
 list3:不能添加任何类型;
 3).取出时,用什么接收?
 接收全部使用Object接收;
 特点:不能向里面存东西,但可以从里面取东西。这种声明一般用于方法的返回值;
 2.<? extends E>:
 1).能够指向什么类型的对象?可以指向具有E或者E的子类类型泛型的集合对象;
 ArrayList<? extends B> list4 = new ArrayList<A>();//NO
 ArrayList<? extends B> list5 = new ArrayList<B>();//OK
 ArrayList<? extends B> list6 = new ArrayList<C>();//OK

 public <? extends B> show(){
 ArrayList<B> list = new ArrayList<B>();
 ArrayList<C> list2 = new ArrayList<C>();
 //return list;
return list2;
 }

取出时,可以使用E或E的父类类型接收;
 特点:不能向里面存东西,只能从里面取东西。这种声明一般用于方法的返回值;表示,这个方法返回的集合,里面存的可能是E类型,或者E的某个子类类型;
 3.<? super E>:
 1).能够指向什么类型的对象?可以指向具有E或者E的"父类"类型泛型的集合对象;
 2).可以添加什么类型的引用?可以添加E或E的子类对象的引用;
 3).取出时,用什么接收?取出时只能用Object接收;
 特点:存入的时候是任何E或E的子类对象的引用。取出时,仍然使用Object接收。所以这种声明一般用于方法的形参

 1 class A{
 2 }
 3 class B extends A{
 4 }
 5 class C extends B{
 6 }
 7 class D extends B{
 8     
 9 }
10 public class Demo {
11     public static void main(String[] args) {
12         //一.**************通配符:<?>***************************
13         //1.能够指向什么类型的对象?
14         ArrayList<?> list1 = new ArrayList<>();
15         ArrayList<?> list2 = new ArrayList<String>();
16         ArrayList<?> list3 = new ArrayList<Integer>();
17         //2.可以添加什么类型的引用?
18         //向list1中添加元素:
19 //        list1.add("aa");//NO
20 //        list1.add(10);//NO
21 //        list1.add(new Object());//NO
22         
23         //向list2中添加元素:
24 //        list2.add("aaa");//NO
25 //        list2.add(10);//NO
26 //        list2.add(new Object());//NO
27         
28         //向list3中添加元素:
29 //        list3.add("aaa");//NO
30 //        list3.add(10);//NO
31 //        list3.add(new Object());//NO
32         //3.取出时,用什么接收?
33         Object obj1 = list1.get(0);//OK的
34         Object obj2 = list2.get(0);//OK的
35         Object obj3 = list3.get(0);//OK的
36         //二.**************通配符:<? extends E>***************************
37         //1.能够指向什么类型的对象?
38     //    ArrayList<? extends B> list4 = new ArrayList<A>();//NO
39         ArrayList<? extends B> list5 = new ArrayList<B>();//OK
40         ArrayList<? extends B> list6 = new ArrayList<C>();//OK
41         
42         //2.可以添加什么类型的引用?
43 //        list5.add(new A());//NO
44 //        list5.add(new B());//NO
45 //        list5.add(new C());//NO
46         
47 //        list6.add(new A());//NO
48 //        list6.add(new B());//NO
49 //        list6.add(new C());//NO
50         
51         //3.取出时,用什么接收:
52         B b1 = list5.get(0);
53         B b2 = list6.get(0);
54         
55         //三.**************通配符:<? super E>***************************
56         //1.能够指向什么类型的对象?
57         ArrayList<? super B> list7 = new ArrayList<A>();//OK
58         ArrayList<? super B> list8 = new ArrayList<B>();//OK
59     //    ArrayList<? super B> list9 = new ArrayList<C>();//NO
60         //2.可以添加什么类型的引用?
61     //    list7.add(new A());//No
62         list7.add(new B());//OK
63         list7.add(new C());//OK
64         
65     //    list8.add(new A());//NO
66         list8.add(new B());//OK
67         list8.add(new C());//OK
68         
69         //3.取出时,用什么接收?
70         Object obj4 = list7.get(0);
71         Object obj5 = list8.get(0);
72         
73         
74         
75     }
76 }

 

5.增强for

 

增强for循环:
 1.语法格式:
    ArrayList<String> list = new ArrayList<>();
    for(集合里面存储的数据类型 变量名 : 集合/数组变量名){
    }
    for(String str : list){
    }
  2.增强for循环的特点:
    1).没有循环变量;一般用于不需要循环变量的循环操作;如果在循环中需要循环变量,还是使用普通for循环;
    2).可以遍历集合,数组;
    3).增强for循环底层就是使用的"迭代器"。因为仍然会产生并发修改异常;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.定义一个存储String类型的集合
 4         ArrayList<String> strList = new ArrayList<>();
 5         //2.填充数据
 6         strList.add("aaa");
 7         strList.add("bbb");
 8         strList.add("ccc");
 9         //3.使用增强for遍历
10         strList = null;
11         for(String s : strList){
12             System.out.println(s);
13         /*    if(s.equals("bbb")){
14                 strList.add("ddd");//仍然能够产生"并发修改异常"。
15             }*/
16         }
17         for(int i = 0;i < strList.size() ; i++){
18             String s = strList.get(i);
19             System.out.println(s);
20         }
21         
22         //变量数组
23         int[] intArray = {1,32,4,243,25,43,5};
24         for(int n : intArray){
25             System.out.println(n);
26         }
27     }
28 }

 


6.可变参数

   1.定义一个方法,这个方法可以接收0 -- 无限多的某类型实参。这种形参就是:可变参数;
   2.格式:
   public int getMax(int ... nums){
  }
   注意:数据类型:可以是任何的Java类型(基本数据类型和引用数据类型);
   3.调用getMax()方法时,可以传递:0 -- 无限多;
   getMax();//不传参数可以。
   getMax(1432,432,43,25,432,432,43,25,325,2,432,4532);//传多个参数也可以;
   4.注意:
  1).可变参数可以同其它形参共存,但可变参数一定要位于参数列表的末尾;
   5.可变参数,在方法内部,是按照"数组"的方式工作的。
   通过反编译后,我们也看出,可变形参也被编译为数组的形式;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.求两个数的最大值;
 4         int a = 10;
 5         int b = 20;
 6         int max = MyMath.getMax(a,b);
 7         System.out.println("max = " + max);
 8         /*
 9         int[] array = {1,432,4,3245,32,4};
10         max = MyMath.getMax(array);
11         System.out.println("max = " + max);
12         */
13         
14         max = MyMath.getMax(14,3,432,432,5,435,32,432,5,435,2,432,45,324);
15         System.out.println("max = " + max);
16         
17     }
18     
19 }

 

7.静态导入

1.直接导入到某个类的静态方法名;
import static java.lang.Math.abs;
2.可以使用通配符
import static java.lang.Math.*;


8.集合的嵌套

  1.一个集合,可以存储任何类型的对象,包括"集合"。
  2.所以:一个集合可以存储另一个集合,这就叫:集合的嵌套;
 
  例子:一个班有3名同学,有3个姓名。另一个班有5名同学,有5个姓名;
     要求:将两个班合并为一个集合打印:
 
  1.定义一个集合,存储第一个班的3名学员;
  2.定义一个集合,存储第二个班的5名学员;
  3.定义一个大集合,将前面的两个小集合存入;
  4.遍历大集合

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.第一个班的集合
 4         ArrayList<String> class1List = new ArrayList<>();
 5         class1List.add("马云");
 6         class1List.add("马化腾");
 7         class1List.add("雷军");
 8         
 9         //2.第二班的集合
10         ArrayList<String> class2List = new ArrayList<>();
11         class2List.add("成龙");
12         class2List.add("甄子丹");
13         class2List.add("李连杰");
14         class2List.add("吴京");
15         class2List.add("洪金宝");
16         
17         //3.实例化一个大集合
18         ArrayList<ArrayList<String>> list = new ArrayList<>();
19         list.add(class1List);
20         list.add(class2List);
21         
22         //4.打印大集合
23         for(ArrayList<String> classList : list){
24             for(String name : classList){
25                 System.out.println(name);
26             }
27         }
28     }
29 }

9.Set集合

Collection
  |--List(接口):
   |--Set(接口):它是Collection的子接口,所以,它继承了所有Collection中的
   一些基本方法,我们可以找一个子类,直接测试;
   特点:
   1.无序(取出时跟存入时的顺序不一致)
   2.不存储重复值;
  |--HashSet(类):内部使用"哈希表"实现;

Set集合存储字符串

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.定义一个HashSet对象;
 4         Set<String> strSet = new HashSet<>();
 5         //2.填充集合:Collection的add(Object o);
 6         strSet.add("aaa");
 7         strSet.add("bbb");
 8         strSet.add("ccc");
 9         strSet.add("ddd");
10         
11         strSet.add("ccc");//不存储重复值
12         strSet.add("ddd");//不存储重复值
13         strSet.add("eee");
14         
15         String s1 = new String("ccc");
16         strSet.add(s1);//不存储重复值;
17         
18         
19         //3.遍历集合:
20         //方式一:toArray();
21         Object[] objArray = strSet.toArray();
22         for(Object o : objArray){
23             System.out.println(o);//取出时跟存入的顺序不一致;
24         }
25         System.out.println("************************************");
26         //方式二:iterator()
27         Iterator it = strSet.iterator();
28         while(it.hasNext()){
29             System.out.println(it.next());
30         }
31         //方式三:因为增强for是基于迭代器的,所以,凡是能用迭代器遍历的,使用增强for都可以
32         System.out.println("************************************");
33         for(String s : strSet){
34             System.out.println(s);
35         }
36         
37     }
38 }

 

 

10.HashSet保证元素的唯一性:

  1.由于HashSet内部使用了"哈希表",所以它会先产生"哈希值";
  2.通过查看源码,我们知道,判断重复元素的方式:
  1.先判断:hashCode是否相同;
  2.如果hashCode相同,再判断equals;
  3.所以,我们使用HashSet存入自定义对象,如果想使HashSet存储不同的元素,排除掉--不同对象,但内部属性完全相同的对象,
  我们就要在我们的自定义类中重写:hashCode()和equals()

 

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.实例化一个Set
 4         Set<Student> stuSet = new HashSet<>();
 5         //2.填充数据
 6         stuSet.add(new Student("张三",20));
 7         stuSet.add(new Student("李四",22));
 8         stuSet.add(new Student("王五",24));
 9         Student stu1 = new Student("周六",26);
10         Student stu2 = new Student("周六",26);
11         /*
12         System.out.println(stu1.hashCode());
13         System.out.println(stu2.hashCode());*/
14         
15         stuSet.add(stu1);
16         
17         stuSet.add(stu2);
18         
19         //3.遍历
20         for(Student stu : stuSet){
21             System.out.println(stu.getName() + "," + stu.getAge());
22         }
23     }
24 }
 1 package cn.itcast.demo02_Set集合保证元素的唯一性;
 2 
 3 public class Student {
 4     private String name;
 5     private int age;
 6     public Student(String name, int age) {
 7         super();
 8         this.name = name;
 9         this.age = age;
10     }
11     public Student() {
12         super();
13     }
14     public String getName() {
15         return name;
16     }
17     public void setName(String name) {
18         this.name = name;
19     }
20     public int getAge() {
21         return age;
22     }
23     public void setAge(int age) {
24         this.age = age;
25     }
26     /*
27     @Override
28     public int hashCode() {
29         //一般情况下,是将内部的成员进行一个int值的累加:
30         //对于基本数据类型,尽量转换为int值;
31         //对于引用类型,调用它的hashCode()方法;
32         
33         int code1 = this.age;
34         int code2 = this.name.hashCode();//调用String类内部的hashCode()方法,此方法是重写Object
35         
36         return code1 + code2;
37     }
38     
39     public boolean equals(Object obj){
40         Student stu = (Student)obj;
41         return this.name.equals(stu.name) && this.age == stu.age;
42     }
43     */
44     @Override
45     public int hashCode() {
46         final int prime = 31;
47         int result = 1;
48         result = prime * result + age;
49         result = prime * result + ((name == null) ? 0 : name.hashCode());
50         return result;
51     }
52     @Override
53     public boolean equals(Object obj) {
54         if (this == obj)
55             return true;
56         if (obj == null)
57             return false;
58         if (getClass() != obj.getClass())
59             return false;
60         Student other = (Student) obj;
61         if (age != other.age)
62             return false;
63         if (name == null) {
64             if (other.name != null)
65                 return false;
66         } else if (!name.equals(other.name))
67             return false;
68         return true;
69     }
70     
71     
72     
73 }
74  

11.LinkedHashSet类

Collection
  |--List
  |--Set
  |--HashSet
  |--LinkedHashSet类:
 特点:
   1.内部由链表和哈希表实现;
   2.链表:保证顺序;
      哈希表:保证唯一;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.实例化一个LinkedHashSet
 4         Set<Student> set = new LinkedHashSet<>();
 5         //2.填充数据
 6         set.add(new Student("刘德华",20,'男',80.0));
 7         set.add(new Student("张学友",22,'男',83.0));
 8         set.add(new Student("黎明",24,'男',88.0));
 9         set.add(new Student("郭富城",26,'男',90.0));
10         
11         set.add(new Student("郭富城",26,'男',90.0));
12         //3.遍历
13         for(Student stu : set){
14             System.out.println(stu.getName() + "," + stu.getAge() + "," + stu.getSex() + "," + stu.getScore());
15         }
16         
17     }
18 }
 1 package cn.itcast.demo04_LinkedHashSet类;
 2 
 3 public class Student {
 4     private String name;
 5     private int age;
 6     private char sex;
 7     private double score;
 8     public Student(String name, int age, char sex, double score) {
 9         super();
10         this.name = name;
11         this.age = age;
12         this.sex = sex;
13         this.score = score;
14     }
15     public String getName() {
16         return name;
17     }
18     public void setName(String name) {
19         this.name = name;
20     }
21     public int getAge() {
22         return age;
23     }
24     public void setAge(int age) {
25         this.age = age;
26     }
27     public char getSex() {
28         return sex;
29     }
30     public void setSex(char sex) {
31         this.sex = sex;
32     }
33     public double getScore() {
34         return score;
35     }
36     public void setScore(double score) {
37         this.score = score;
38     }
39     @Override
40     public int hashCode() {
41         final int prime = 31;
42         int result = 1;
43         result = prime * result + age;
44         result = prime * result + ((name == null) ? 0 : name.hashCode());
45         long temp;
46         temp = Double.doubleToLongBits(score);
47         result = prime * result + (int) (temp ^ (temp >>> 32));
48         result = prime * result + sex;
49         return result;
50     }
51     @Override
52     public boolean equals(Object obj) {
53         if (this == obj)
54             return true;
55         if (obj == null)
56             return false;
57         if (getClass() != obj.getClass())
58             return false;
59         Student other = (Student) obj;
60         if (age != other.age)
61             return false;
62         if (name == null) {
63             if (other.name != null)
64                 return false;
65         } else if (!name.equals(other.name))
66             return false;
67         if (Double.doubleToLongBits(score) != Double
68                 .doubleToLongBits(other.score))
69             return false;
70         if (sex != other.sex)
71             return false;
72         return true;
73     }
74     
75     
76 }

12.Map概述

Map集合,就是基于"键,值"对的映射关系
    1."键"不能重复:
    2.每个"键"映射一个"值";
  Map和Collection的不同:
   1.Map是双列的(键、值对)。Collection都是单列的。
   2.Map的键唯一,Collection的子体系Set是唯一的:HashSet(唯一)内部使用-->HashMap。所以HashMap对于重复的"键值"的判断,跟HashSet的判断方式    是一样的;
   3.Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效

13.Map接口的基本方法

Map(接口):无序的。键、值对存储
 |--HashMap(类):
 
  Map的基本方法:
 
  V put(Object key,Object value):添加元素。key做键,value做值
  V remove(Object key):删除key所对应的值,key也会一起删除;
  void clear():清空集合
 boolean containsKey(Object key):判断key在集合中是否存在
 boolean containsValue(Object value):判断value在集合中是否存在;
 boolean isEmpty():判断集合是否为空
 int size():返回集合内的元素的数量;

 1 public class Demo {
 2     public static void main(String[] args) {
 3         Map<String,String> map = new HashMap<>();
 4         //V put(Object key,Object value):填充集合
 5         map.put("it001", "刘德华");
 6         map.put("it002", "张学友");
 7         map.put("it003", "周润发");
 8         map.put("it004", "鞠萍");
 9         map.put("it001", "刘亦菲");//当存储重复的键时,会使用新值,替换原值;
10         
11         //遍历集合
12         System.out.println(map);
13         //V remove(Object key)移除鞠萍
14         map.remove("it004");
15         System.out.println("删除掉鞠萍后:" + map);
16         //3.void clear()
17 /*        map.clear();
18         System.out.println("清空集合后:" + map);*/
19         //4.boolean containsKey(Object key)
20         System.out.println("键it001在集合中是否存在:" + map.containsKey("it001"));
21         System.out.println("键it009在集合中是否存在:" + map.containsKey("it009"));
22         
23         //5. boolean containsValue(Object value)
24         System.out.println("值\"刘德华\"在集合中是否存在:" + map.containsValue("刘德华"));
25         System.out.println("值\"刘亦菲\"在集合中是否存在:" + map.containsValue("刘亦菲"));
26         
27         //6.boolean isEmpty()
28         /*System.out.println("集合是否为空:" + map.isEmpty());
29         map.clear();
30         System.out.println("清空集合后,集合是否为空:" + map.isEmpty());*/
31         
32         //7.int size();
33         System.out.println("集合大小:" + map.size());
34         System.out.println("最后打印集合:" + map);
35     }
36 }

14.Map接口的获取方法

Map接口的获取的方法:
 
  V get(Object key):通过一个key获取一个value;
  Set<K> keySet():获取所有的key,以一个Set返回;
  Collection<V> values():获取所有的value,以一个Collection

 1 public class Demo {
 2     public static void main(String[] args) {
 3         Map<String,String> map = new HashMap<>();
 4         //V put(Object key,Object value):填充集合
 5         map.put("it001", "刘德华");
 6         map.put("it002", "张学友");
 7         map.put("it003", "周润发");
 8         map.put("it004", "鞠萍");
 9         
10         //1.V get(Object key)
11         String value = map.get("it001");
12         System.out.println("value = " + value);
13         System.out.println("**************************");
14         //2.Set<K> keySet()
15         Set<String> keySet = map.keySet();
16         for(String key : keySet){
17             System.out.println(key);
18         }
19         System.out.println("**************************");
20         //3.Collection<V> values()
21         Collection<String> values = map.values();
22         for(String v : values){
23             System.out.println(v);
24         }
25         System.out.println("**************************");
26         //遍历Map
27         Set<String> keys = map.keySet();
28         for(String k : keys){
29             String v = map.get(k);
30             System.out.println("键:" + k + " 值:" + v);
31         }
32     }
33 }

15.获取"键值对"的对象

 1 public class Demo {
 2     public static void main(String[] args) {
 3         Map<String,String> map = new HashMap<>();
 4         //V put(Object key,Object value):填充集合
 5         map.put("it001", "刘德华");
 6         map.put("it002", "张学友");
 7         map.put("it003", "周润发");
 8         map.put("it004", "鞠萍");
 9         
10         //获取"键值对"的对象
11         Set<Map.Entry<String, String>> enSet = map.entrySet();
12         for(Map.Entry<String, String> en : enSet){
13             String key = en.getKey();
14             String value = en.getValue();
15             System.out.println(key + "--" + value);
16             
17         }
18     }
19 }

16.LinkedHashMap类

 1.内部由链表和哈希表实现;
 2.链表:保证了有序;
 哈希表:保证了唯一;
 注意:Map子类的数据结构,都是应用在"键"上的。

 1 public class Demo {
 2     public static void main(String[] args) {
 3         //1.实例化一个Map
 4         Map<String,String> map = new LinkedHashMap<>();
 5         //2.填充集合
 6         map.put("it001", "刘德华");
 7         map.put("it002", "张学友");
 8         map.put("it003", "周润发");
 9         map.put("it004", "郭富城");
10         map.put("it001", "刘亦菲");//覆盖原it001的value
11         
12         //3.遍历
13         Set<String> keySet = map.keySet();
14         for(String key : keySet){
15             System.out.println(key + "---" + map.get(key));
16         }
17     }
18 }

 

转载于:https://www.cnblogs.com/linmusen/p/4709265.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值