ホームページ >Java >&#&チュートリアル >Java コレクション フレームワークの説明パート 3
Java のコレクション フレームワークは内容が多いため、3 つのパートに分けて Java のコレクション フレームワークを紹介します。内容は浅いものから深いものまであります。この記事は、驚くべきかそうでないかは、実はまだ基本です ̄▽ ̄ 書くのが本当に疲れて、書くのが面倒です。 。
注意: (パート 1)~
Java コレクション フレームワーク (パート 1)
Java コレクション フレームワーク (パート 2)
Javaコレクション フレームワーク (パート 2)
Map インターフェイスの基本的な操作は、< Java コレクション フレームワーク (パート 2) > で紹介されています。使用されている例は、<Java Collection Framework (パート 1)> で学生のコース選択をシミュレートする小さなプログラムです。よくわからない人は、最初に読んでください< Java Collection Framework、簡単な紹介 (上) > ;。
この記事では、次の問題を解決します:
コースシーケンスに、特定のコースが含まれているかどうかを確認するにはどうすればよいですか?
コースシーケンスに特定のコースが含まれている場合、コースのインデックス位置を決定するにはどうすればよいですか?
学生マッピングテーブルに、特定の学生IDが含まれているかどうかを確認するにはどうすればよいですか?
生徒オブジェクトが含まれているかどうかを確認するにはどうすればよいですか?
コース名または学生名でコースまたは学生オブジェクトを並べ替える場合はどうなりますか? ID で並べ替える場合はどうでしょうか?
問題は多くて複雑に見えますが、実際には主に次の 2 つの部分で構成されます: セットに特定の要素が含まれているかどうかを判断する方法; 指定されたルールに従って順序付きセットを並べ替える方法。
最初の質問では、コレクションには contains というメソッドがあり、このメソッドはコレクションに特定の要素が含まれているかどうかを判断するために使用されます。 、セット、マップコレクションの使い方や注意事項をご覧いただけます。
まず、Contains メソッドを使用してリスト内のコースが存在するかどうかを判断するテスト メソッドを作成しましょう:
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結果:
結果分析:
実行結果から、最初の「データ構造」コースは contains メソッドを呼び出すと true を返し、2 番目の「データ構造」コースは contains メソッドを呼び出すことがわかります。そして false を返します。 「データ構造」という同じタイトルのコースが 2 つのまったく異なる結果になるのはなぜですか?
最初の「データ構造」コースは CoresesToSelect コレクションから取得されるため、もちろん CoresesToSelect コレクション に含まれており、contains メソッドを呼び出すと true が返されますが、2 番目の「データ構造」コースは新しいものです。 (新しく作成された) コースでは、システムは別のメモリ空間を開きます。その名前は最初の「データ構造」と同じですが、これらはシステムにとって 2 つの異なるオブジェクトです。 contains メソッドのデフォルトでは、参照オブジェクト (ハッシュ コード) のメモリ アドレスを比較します。では、同じ名前のコースを使用して、そのコースがリストに含まれているかどうかを判断するにはどうすればよいでしょうか?
ここでは、contains メソッドを理解して使用するために、contains メソッドの原理を深く理解する必要があります。以下の図に示すように、
メソッドのすべてのクラスはObjectクラスから継承されており、Objectクラスには2つのオブジェクトが等しいかどうかを比較するために使用されるequals()メソッドがあります。 () メソッドの詳細な説明は、私の他のブログ投稿のリンクにあります:
それでは、contains メソッドの内部原理を見てみましょう。
上の図に示すように、contains メソッドは、コレクション内の各オブジェクトの equals メソッドを走査することで、2 つのオブジェクトが等しいかどうかを実際に比較します。等しい場合は true を返し、そうでない場合は false を返します。デフォルトでは、equals() は 2 つのオブジェクトの参照が等しいかどうかを比較します。 contains メソッドを使用して 2 つのオブジェクトの値が等しいかどうかを比較し、コレクションにオブジェクトが含まれているかどうかを判断する場合は、equals をオーバーライドする必要があります。オブジェクトの () メソッド。
以下は、Course クラスの equals() メソッドを書き換えて、2 つの Course オブジェクトの名前が同じかどうかを比較します。たとえば、
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()方法则从最后一个元素开始遍历;
首先我们也来写一个测试方法来用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()方法功能与“==”相同。
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方法。
对于第二个问题,java集合框架还有一个成员就是Collections工具类,这个工具类提供了很多操作集合的方法,其中sort()方法是很常见的方法,它能对有序集合按照默认规则进行排序。接下来我们通过实例来看看Collections工具类是如何通过sort()对List进行排序的。
我写了四个测试方法来测试sort()方法,分别如下:
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));
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) 原来collection.sort()方法对元素进行排序,列表中的元素都必需实现 Comparable 接口,否则不能使用 sort()方法排序,那么Comparable 接口是什么,该如何实现呢?请往下看! 在上述例子可以看到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接口后面都要加上泛型!!! 再修改testSort4()方法,如下: 実行結果: 注: sort (set) を直接呼び出すと、デフォルトの比較ルールが使用されます。sort のオーバーロードされたメソッド sort (set、 Comparator<クラス名> インターフェイスのオブジェクト名を実装します) を呼び出すと、一時ルールが使用されます。 。 >>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> > デフォルトの比較ルールを使用せずにクラスを比較する方法。 手順の概要: 1. クラスに Comparable<クラス名> を追加します。 2. .compareTo(クラス名オブジェクト名)メソッドを実装します。これが大きい場合は正の値を返し、等しい場合は0を返し、小さい場合は負の値を返します。 (さまざまなクラスには .compareTo() メソッドが含まれます) 3. Collections.sort (オブジェクト名) を呼び出して並べ替えます。 2. このクラスに Comparator インターフェイスを実装させます: 1. 新しいクラスを作成し、Comparator<クラス名>を追加します 2. .compare(クラス名オブジェクト名 1, クラス名, オブジェクト名 2) を実装します。このメソッドでは、これが大きい場合は正の値が返され、等しい場合は 0 が返され、これが小さい場合は負の値が返されます。 3. Collections.sort (オブジェクト名、Comparator では、Collection インターフェースについて学びました。 Java Collection Framework (Part 2) では、Mao インターフェースについて学びました。 詳しくは、Java API を参照してください。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方法说明:
三、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 }
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 }
以上がJava コレクション フレームワークの説明パート 3の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。