>  기사  >  Java  >  Java 컬렉션 프레임워크 설명 3부

Java 컬렉션 프레임워크 설명 3부

巴扎黑
巴扎黑원래의
2017-07-23 13:45:141970검색

Java의 컬렉션 프레임워크(2부)



Java의 컬렉션 프레임워크에는 내용이 많기 때문에 Java의 컬렉션 프레임워크를 세 부분으로 나누어 내용을 얕은 것부터 깊게 설명합니다. 기사는 사실 아직 기본입니다. 놀랍거나 놀랍지 않습니다 ̄▽ ̄ 글을 쓰는 것이 정말 피곤하고 글을 쓰기에는 너무 게으릅니다. .

알림: (1부)부터 읽기 시작하는 것이 좋습니다~

목차

Java 컬렉션 프레임워크(1부)

Java 컬렉션 프레임워크(2부)

Java 컬렉션 프레임워크(2부)


머리말

Map 인터페이스의 기본 작업은 <Java 컬렉션 프레임워크(2부) >에 소개되어 있습니다. 사용된 예제는 <Java Collection Framework(Part 1)>에서 학생 과목 선택을 시뮬레이션하는 작은 프로그램입니다. 잘 모르는 친구들은 먼저 읽어보세요<Java Collection Framework, 간단한 소개(상위)> ;.

이 기사에서는 다음 문제를 해결합니다.

  • 과정 순서에서 특정 과정이 포함되는지 여부를 어떻게 결정합니까?

  • 강좌 순서에 특정 강좌가 포함되어 있는 경우 해당 강좌의 인덱스 위치를 어떻게 결정하나요?

  • 학생 매핑 테이블에 특정 학생증이 포함되어 있는지 어떻게 확인하나요?

  • 학생 개체가 포함되어 있는지 확인하는 방법은 무엇입니까?

  • 강좌명이나 학생명으로 과목이나 학생 객체를 정렬한다면 어떨까요?

문제는 많고 복잡해 보이지만 사실 문제는 주로 두 부분으로 구성됩니다. 세트에 특정 요소가 포함되어 있는지 확인하는 방법 지정된 규칙에 따라 순서가 지정된 세트를 정렬하는 방법.


1. 컬렉션에 포함 메서드 적용

첫 번째 질문의 경우 컬렉션은 포함이라는 메서드를 제공합니다. 이 메서드는 컬렉션에 특정 요소가 포함되어 있는지 확인하는 데 사용됩니다. , 설정, 지도를 모아서 사용법과 주의사항을 확인하세요.

1) List의 Contains() 메소드 - 목록에 강좌가 존재하는지 확인

먼저, Contains 메소드를 사용하여 List에 강좌가 존재하는지 확인하는 테스트 메소드를 작성해 보겠습니다.

 1 /* 2  * 测试List的contains方法 3  */ 4     public void testListContains(){ 5         //取得备选课程序列的第0个元素 6         Course cr=this.CoresesToSelect.get(0); 7         System.out.println("取得课程:" +cr.getId()+","+cr.getName()); 8         System.out.println("备选课程中是否包含课程:"+cr.getName()+","+this.CoresesToSelect.contains(cr)); 9         //创建一个新的课程对象,它的id和name和cr一样10         Course cr2=new Course(cr.getId(),cr.getName());11         System.out.println("备选课程中是否包含课程:"+cr2.getName()+","+this.CoresesToSelect.contains(cr2));12         //通过indexOf方法来取的某元素的索引位置13         if(CoresesToSelect.contains(cr2)){14             System.out.println("课程:"+cr2.getName()+"的索引位置为:"+CoresesToSelect.indexOf(cr2));15 16         }17     }

Running 결과:

결과 분석:

실행 결과를 보면 첫 번째 "데이터 구조" 과정에서는 contain 메서드를 호출하여 true를 반환하고, 두 번째 "데이터 구조" 과정에서는 contain 메서드를 호출하는 것을 확인할 수 있습니다. 그리고 false를 반환합니다. "데이터 구조"라는 동일한 제목의 강좌가 완전히 다른 두 가지 결과를 갖는 이유는 무엇입니까?

첫 번째 "데이터 구조" 과정은 CoresesToSelect 컬렉션에서 가져왔으므로 당연히 CoresesToSelect 컬렉션에 포함되며 포함 메서드를 호출하면 true가 반환되지만 두 번째 "데이터 구조" 과정은 새로운 것입니다. (새로 생성된) 코스에서 시스템은 또 다른 메모리 공간을 엽니다. 이름은 첫 번째 "데이터 구조"와 동일하지만 시스템에 대한 두 개의 다른 개체입니다. 포함 메소드는 기본적으로 참조 객체(해시 코드)의 메모리 주소를 비교하므로 동일한 이름의 강좌를 사용하여 해당 강좌가 목록에 포함되어 있는지 확인하려면 어떻게 해야 합니까?

여기서 contain 메서드를 이해하고 사용하는 데 도움이 되기 위해서는 포함 메서드의 원리에 대한 심층적인 이해가 필요합니다. 아래 그림과 같이

메서드의 모든 클래스는 Object 클래스에서 상속되며, Object 클래스에는 두 개체가 같은지 비교하는 데 사용되는 equals() 메서드가 있습니다. () 메소드에 대한 자세한 설명은 제 다른 블로그 포스팅에 있습니다. 링크:

그럼 Contains 메소드의 내부 원리를 살펴보겠습니다.

위 그림에서 볼 수 있듯이, Contains 메소드는 컬렉션에 있는 각 객체의 equals 메소드를 순회하여 실제로 두 객체가 동일한지 비교합니다. 동일하면 true를 반환하고, 그렇지 않으면 false를 반환합니다. 기본적으로 equals()는 두 개체의 참조가 같은지 비교합니다. 컬렉션에 개체가 포함되어 있는지 확인하기 위해 두 개체의 값이 같은지 비교하기 위해 Contains 메서드를 사용하려면 같음을 재정의해야 합니다. () 객체의 메소드입니다.

다음은 Course 클래스의 equals() 메소드를 다시 작성하여 두 코스 객체의 이름이 동일한지 비교합니다. 예:

 1 public void equals (Object obj) 2 { 3   if(this == obj)  // 指向同一个内存快 必然是相同的 4      returned true;  //为什么contains(course2) 返回的是false 原因就在在这里 只是比较了一下 引用的值是否相同 没有进一步的比较 内存块中的值 下就是对这里记性了改写 5   if (obj == null)  // 如果obj为空 就直接没有戏了 6      return false; 7   if(! (obj instanceof Course))  //如果两者的不属于同一类型则 也直接没戏了 8     return false; 9   //经过以上的这么多的比较 终于可以判断二者的值是不是相同了10   //首相要把objet型的obj转成 Course11   Course course = (Course)  obj;12   if( this.name == null )13   {14      if(course.name == null )15         return true;16      else return false;17    }18    else19    {20      if(this.name.equals(course.name)) return true;21      else return false;22    )23    //如果还有别的属性接着写24 }

重写完Course类的equals()方法后,我们重写运行一下程序,结果如下:

可以看到contains方法可以根据课程名称来判断是否包含该课程了。

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

这里的indexOf()方法与lastIndexOf()方法实现原理和contains方法相似:

1、遍历调用每个元素的equals()方法,如果返回true则将次元素的索引返回;

2、如果有多个相同元素,则只返回第一个元素的索引;

3、lastIndexOf()方法则从最后一个元素开始遍历;

2)Set中contains()方法——判断Set中课程是否存在

 首先我们也来写一个测试方法来用contains方法来判断Set中课程是否存在:

 1     /* 2      * 测试Set的contains方法 3      */ 4     public void testSetContains(){ 5         System.out.println("请输入学生已选的课程名称:"); 6         String cName=in.next(); 7         Course c=new Course(cName); 8         System.out.println("学生已选的课程是否包含课程:"+cName+","+stu.getCourses().contains(c)); 9 10     }

运行结果:

这就奇怪了,我们不是已经重写了Course类的equals()方法吗?为什么在Set集合里调用contains方法还是返回false?

原来在HashSet里的contains方法和List里略有不同。它的原理如下图所示:

Set.contains(E e)工作原理是先调用从Object继承而来的hashCode方法,然后再调用equals()方法,如果hashCode相同,才会调用equals方法,只有两者都返回true,contains方法 才返回true。jvm运行时,给每个对象分配唯一一个标志身份的标志hashcode。众类鼻祖Object的hashCode()方法在默认情况下,判断哈希码是不是相同。即如同equals默认情况下比较的是二者是不是同一个内存快。Set集的contains方法,内部就是先调用hashCode再调用equals()方法。很多情况要结合实际对hashCode进行改写。

这里给出我对hashCode的重写(系统自动生成):

1 public int hashCode() {2         final int prime = 31;3         int result = 1;4         result = prime * result + ((name == null) ? 0 : name.hashCode());5         return result;6     }

然后我们重写运行一下程序,结果如下:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

这里我总结一下List和Set中contains方法的注意事项

1.list 与 set 中contain()方法调用机制:

list 中的contain()方法是拿到list中的每个对象来调用Object类中的equals()方法;

Set  中的contain()方法是拿到list中的每个元素来先调用hashcode()方法来返回哈希码值,当哈希码的值相等时,再调用equals()方法,当比较的元素此时也相同时,才会返回true。因此调用Set中的contain()方法时,需要对hashcode()方法及equals()方法进行重写。

2. == 和equals()两种比较方法,在使用时要注意:

1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

          如果作用于引用类型的变量,则比较的是所指向的对象的地址。

2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量。

如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;诸如String、Date等类应该根据情况覆盖其父类或Object类中的equals()方法,否则默认的equals()方法功能与“==”相同。

3)Mapt中containsKey方法和containsValue方法——判断Map中是否包含指定的key和value

Map中通过containsKey()方法和containsValue()方法来判断键和值是否存在(已经重写Student类的Hashcode和equals方法,这里不再列出)

 1 /* 2      * 测试Map中,是否包含某个key值或者某个value值 3      */ 4     public void ContainsKeyOrValue(){ 5         //在Map中,用containsKey方法,来判断是否包含某个key值 6         System.out.println("请输入学生id:"); 7         String id =in.next(); 8         System.out.println("您输入的学生id为"+id+",Map中是否包含此id:"+this.students.containsKey(id)); 9         if(students.containsKey(id)){10             System.out.println("对应的学生姓名:"+students.get(id).getName());11 12         }13         //在Map中,用containsValue方法,来判断是否包含某个value值14         System.out.println("请输入学生姓名:");15         String name =in.next();16         Student st=new Student();17         st.setName(name);18         System.out.println("您输入的学生姓名为"+name+",Map中是否包含此姓名:"+this.students.containsValue(st));19         if(students.containsValue(st)){20             21             Set<Entry<String, Student>> entrySet =students.entrySet();22             for(Entry<String, Student> entry:entrySet){23                 if(entry.getValue().getName().equals(name)){24                     System.out.println("对应的学生的id:"+entry.getValue().getId());25                 }26 27             }28         }29 30     }

运行结果:

注意:

1.Map 中对对象进行了 Key 标记,通过 get(Key)可以取得对应的对象。

2.Map 的containsValue()方法的参数是 Object 对象,因为Map 的 Value 值是对象元素。

3.Map 的containsKey()方法取得 Map 映射的 Key 值。

4.Map中的containsValue()方法原理跟HashSet的contains()相同,所以要重写Hashcode和equals方法。


二、Collections工具类

对于第二个问题,java集合框架还有一个成员就是Collections工具类,这个工具类提供了很多操作集合的方法,其中sort()方法是很常见的方法,它能对有序集合按照默认规则进行排序。接下来我们通过实例来看看Collections工具类是如何通过sort()对List进行排序的。

我写了四个测试方法来测试sort()方法,分别如下:

1)对Integer泛型的List进行排序

 1 /* 2      * 1.通过Collections.sort()方法,对Integer泛型的List进行排序 3      * 创建一个Integer泛型的List,插入十个100以内的不重复随机整数 4      * 调用Collections.sort()方法对其排序 5      */ 6     public void testSort1(){ 7         //创建一个Integer泛型的List,插入十个100以内的不重复随机整数 8         List<Integer> intList=new ArrayList<Integer>(); 9         int i=0;10         do{11             Random random=new Random();12             Integer n=random.nextInt(100);13             if(!intList.contains(n)){14                 intList.add(n);15                 System.out.println("成功添加整数:"+n);16                 i++;17             }18         }while(i<10);19         System.out.println("----------排序前-----------");20         for(Integer t:intList){21             System.out.print(t+"  ");22         }23         System.out.println();24         //调用Collections.sort()方法对其排序25     26         System.out.println("----------排序后-----------");27         Collections.sort(intList);28         for(Integer t:intList){29             System.out.print(t+"  ");30         }31     }

运行结果:

这里我使用了Random类来获取随机数,Random类的出现,可以替代之前的Math.random方法

Random类有很多方法:nextByte、nextDouble、nextInt、nextDouble、nextBoolean、nextFloat、nextLong,获取各种类型的随机数但是没有nextShort和nextCharacter

并且对于nextInt并且支持传入一个int类型参数,作为随机数的取值范围。

常见用法:nextInt对于从某一个String类型的对象中,获取一个随机位的字符很有用,

例如String str = "sdfsfsfsdsafdf"; Random r = new Random();char c = str.charAt(r.nextInt(str.length));

2)对String泛型的List进行排序

 1 /* 2      *2.对String泛型的List进行排序 3      * 创建一个String泛型的List,添加三个乱序的String 4      * 调用Collections.sort()方法对其排序 5      */ 6     public void testSort2(){ 7         //创建一个String泛型的List,添加三个乱序的String 8         List<String> strList=new ArrayList<String>(); 9         String[] str={"egesg","eDSGvdxbrb","23235sdvfsd"};10         strList.addAll(Arrays.asList(str));11         System.out.println("----------排序前-----------");12         for(String s:strList){13             System.out.print(s+",");14         }15         System.out.println();16     //调用Collections.sort()方法对其排序17         System.out.println("----------排序后-----------");18         Collections.sort(strList);19         for(String s:strList){20             System.out.print(s+",");21         }22     }

运行结果:

再写一个稍微复杂一点的例子:

 1 /* 2      * 3      * 创建一个String泛型的List,往其中添加十条随机字符串 4      * 每条字符串的长度为10以内的随机整数 5      * 每条字符串的每个字符都为随机生成的字符,字符可以重复 6      * 每条随机字符串不可以重复 7      * 调用Collections.sort()方法对其排序 8      */ 9     public String getRandomString(int size) {10         StringBuilder str= new StringBuilder();//可变字符串11         Random random=new Random();12         //存放所包含字符62位13         String  container = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";14         for(int j=0;j<size;j++){15             str.append(container.charAt(random.nextInt(container.length()-1)));16         }17         return str.toString();18     }19     public void testSort3(){20     21         //创建一个String泛型的List22         List<String> strList=new ArrayList<String>();23         Random random=new Random();24         String str;25         for(int i=0;i<10;i++){//添加十条随机字符串26             do{27             int size=random.nextInt(10);//每条字符串的长度为10以内的随机整数28             str=getRandomString(size);29             }while(strList.contains(str)||str.length()==0);30             strList.add(str);31 32         }33         System.out.println("----------排序前-----------");34         for(String s:strList){35             System.out.println(s);36         }37         System.out.println();38     //调用Collections.sort()方法对其排序39         System.out.println("----------排序后-----------");40         Collections.sort(strList);41         for(String s:strList){42             System.out.println(s);43         }44     }

运行结果:

注意:

对于String类型的sort()方法默认排序顺序为:

数字(0-9)--->大写字母(A-Z)--->小写字母(a-z)

3)对其他类型泛型的list进行排序,以,Student为例。

 1     /* 2      * 对其他类型泛型的list进行排序,以,Student为例。 3      */ 4     public void testSort4(){ 5         List<Student> stus=new ArrayList<Student>(); 6         Random random=new Random(); 7         stus.add(new Student(random.nextInt(1000)+"","Mike")); 8         stus.add(new Student(random.nextInt(1000)+"","Angela")); 9         stus.add(new Student(random.nextInt(1000)+"","Lucy"));10         System.out.println("----------排序前-----------");11         for(Student s:stus){12             System.out.println(s.getId()+","+s.getName()+" ");13         }14         System.out.println();15         System.out.println("----------排序后-----------");16         Collections.sort(stus);//程序编译出错17         for(Student s:stus){18             System.out.println(s.getId()+","+s.getName()+" ");19         }20         21     }
查看信息说是sort()方法类型不匹配,无法对Student类型的List进行排序,为什么会这样呢?我们来看一下API的sort方法说明:

原来collection.sort()方法对元素进行排序,列表中的元素都必需实现 Comparable 接口,否则不能使用 sort()方法排序,那么Comparable 接口是什么,该如何实现呢?请往下看!


三、Comparable & Comparator简介

在上述例子可以看到Collections工具类的sort()方法不能对Student类的List集合进行排序,通过查阅API我们知道因为Student类并没有继承Comparable & Comparator接口,Student类是不可比较的,所以编译器会报错。那么Comparable & Comparator这两个接口有什么不同呢?

compareable 是默认比较规则, comparator是临时比较规则

1.Comparable接口------可比较的

  • 实现该接口表示:这个类的实例可以比较大小,可以进行自然排序

  • 定义了默认的比较规则

  • 其实现类需实现compareTo()方法

  • comparaTo()方法返回正数表示大,负数表示小,0表示相等

2.Comparator接口-----比较工具接口

  • 用于定义临时比较规则,而不是默认比较规则

  • 其实现类需要实现compare()方法

compareTo()方法compare()方法的返回值有三种:

  • 返回0:两个对象相等

  • 返回1:该对象大于比较的对象

  • 返回-1:该对象小于比较的对象

那么我们给Student类加上Comparable接口和Comparator接口,规定默认规则是比较学生的id大小,临时规则是比较学生的姓名。代码如下:

注意:Comparable接口和Comparator接口后面都要加上泛型!!!

 1 public class Student implements Comparable<Student>,Comparator<Student>{ 2 .......//省略一段代码 3 @Override 4     public int compare(Student arg0, Student arg1) { 5         // TODO Auto-generated method stub 6         return arg0.name.compareTo(arg1.getName()); 7     } 8     @Override 9     public int compareTo(Student arg0) {10         // TODO Auto-generated method stub11         //默认与学生id比较12         return Integer.valueOf(this.getId()).compareTo(Integer.valueOf(arg0.getId()));13     }

再修改testSort4()方法,如下:

 1 /* 2      * 对其他类型泛型的list进行排序,以,Student为例。 3      */ 4     public void testSort4(){ 5         List<Student> stus=new ArrayList<Student>(); 6         Random random=new Random(); 7         stus.add(new Student(random.nextInt(1000)+"","Mike")); 8         stus.add(new Student(random.nextInt(1000)+"","Angela")); 9         stus.add(new Student(random.nextInt(1000)+"","Lucy"));10         System.out.println("----------排序前-----------");11         for(Student s:stus){12             System.out.println(s.getId()+","+s.getName()+" ");13         }14         System.out.println();15         System.out.println("----------排序后-----------");16         Collections.sort(stus);17         for(Student s:stus){18             System.out.println(s.getId()+","+s.getName()+" ");19         }20         System.out.println("----------根据姓名排序-----------");21         Collections.sort(stus,new Student());22         for(Student s:stus){23             System.out.println(s.getId()+","+s.getName()+" ");24         }25         26     }

실행 결과:

참고: sort(set)를 직접 호출하면 기본 비교 규칙이 사용됩니다. sort의 오버로드된 메서드 sort(set, Comparator<클래스 이름> 인터페이스의 객체 이름 구현)을 호출하면 임시 규칙이 사용됩니다. .

>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> 기본 비교 규칙 없이 클래스를 비교하는 방법 단계 요약: 1. 클래스가 Comparable 인터페이스를 구현하도록 합니다.

1. 클래스에 Comparable 구현을 추가합니다.

2.compareTo(클래스 이름 객체 이름) 메서드를 구현합니다. 이 값이 크면 양수 값을 반환하고, 같으면 0을 반환하고, 작으면 음수 값을 반환합니다. (다양한 클래스에는 .compareTo() 메소드가 포함됩니다.)

3. Collections.sort(객체 이름)를 호출하여 정렬합니다.

2. 이 클래스가 Comparator 인터페이스를 구현하도록 합니다.

1. 새 클래스를 만들고 Comparator<클래스 이름>

2을 구현합니다. 이 메소드는 이 값이 크면 양수 값을, 같으면 0을, 작으면 음수 값을 반환합니다.

3. Collections.sort(객체 이름, Comparator 인터페이스를 구현하는 객체 이름) 메서드를 호출합니다.

4. Java Collection Framework 요약

이 기사의 끝에서 우리는 마침내 다음 내용을 포함하는 Java Collection Framework를 인식했습니다.

Collection 인터페이스, Map 인터페이스, Collections 도구 클래스, Comparable 인터페이스, Comparator 인터페이스

Java 컬렉션 프레임워크(1부)
    에서 컬렉션 인터페이스에 대해 배웠습니다.
  • Java 컬렉션 프레임워크(2부)에서 Mao 인터페이스에 대해 배웠습니다.
  • 이 기사에서는 컬렉션 도구 클래스, Comparable 인터페이스 및 Comparator 인터페이스에 대해 배웠습니다.

    조금 더 자세히 알고 싶으시다면 Java API를 참고해주세요.

위 내용은 Java 컬렉션 프레임워크 설명 3부의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:JAVA 가상 머신에 대한 자세한 소개다음 기사:JAVA 가상 머신에 대한 자세한 소개

관련 기사

더보기