Heim > Java > javaLernprogramm > Hauptteil

Java Collection Framework erklärt Teil 3

巴扎黑
Freigeben: 2017-07-23 13:45:14
Original
1932 Leute haben es durchsucht

Collection Framework in Java (Teil 2)



Da das Collection Framework in Java viel Inhalt hat, ist es in drei Teile unterteilt, um das Collection Framework in Java vorzustellen Der Inhalt ist von oberflächlich bis tiefgründig, haha, dieser Artikel ist eigentlich immer noch die Grundlagen. Ist es überraschend, dass ich das Schreiben wirklich satt habe und zu faul zum Schreiben bin? .

Warme Erinnerung: Es wird empfohlen, mit dem Lesen von (Teil 1) zu beginnen~

Inhaltsverzeichnis

Leicht zu lesen Java Collection Framework (Teil 1) )

Eine einfache Einführung in das Java Collection Framework (Teil 2)

Eine einfache Einführung in Java Collection Framework (Teil 2)


Vorwort

In<

Leicht zu erlernendes Java Collections Framework (Teil 2) > Die Grundfunktionen der Kartenschnittstelle werden vorgestellt. Das verwendete Beispiel ist ein kleines Programm zur Simulation der Kursauswahl von Studenten im <Java Collection Framework (Teil 1) >. Freunde, die sich nicht sicher sind, können es zuerst lesen<Easy to Learn Deep Java Collection Framework (Teil 1) >. In diesem Artikel werden wir die folgenden Probleme lösen:

  • Wie kann man in einer Kurssequenz feststellen, ob ein oder mehrere bestimmte Kurse enthalten sind?

  • Wenn die Kurssequenz einen bestimmten Kurs enthält, wie kann dann die Indexposition des Kurses bestimmt werden?

  • Wie kann in der Studentenzuordnungstabelle festgestellt werden, ob ein bestimmter Studentenausweis enthalten ist?

  • Wie kann festgestellt werden, ob ein Schülerobjekt enthalten ist?

  • Was passiert, wenn die Kurse oder Studentenobjekte nach Kursname oder Studentenname sortiert sind? Was ist mit der Sortierung nach ID?

Die Probleme scheinen zahlreich und kompliziert zu sein, aber tatsächlich bestehen sie hauptsächlich aus zwei Teilen:

Wie man feststellt, ob eine Menge ein Element enthält; Wie eine geordnete Menge kombinieren. Nach festgelegten Regeln sortieren .


1. Anwendung der Methode „enthält“ in einem Satz

Für die erste Frage stellt der Satz eine Methode namens „enthält“ bereit, um zu bestimmen, ob der Satz ein bestimmtes enthält Element: Für die Methode „contains“ werden wir uns deren Verwendung und Vorsichtsmaßnahmen aus den Sammlungen List, Set und Map ansehen.

1) Die Methode „contains()“ in List – ermittelt, ob der Kurs in List existiert

Schreiben wir zunächst eine Testmethode, um mithilfe der Methode „Contains“ zu ermitteln, ob der Kurs in List existiert:

 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     }
Nach dem Login kopieren
Laufergebnisse:

Ergebnisanalyse:

Aus der Ergebnisse ausführen Es ist ersichtlich, dass der erste „Datenstruktur“-Kurs die Methode „enthält“ aufruft und „true“ zurückgibt, während der zweite „Datenstruktur“-Kurs die Methode „enthält“ aufruft und „false“ zurückgibt. Warum haben Kurse mit dem gleichen Titel „Datenstruktur“ zwei völlig unterschiedliche Ergebnisse?

Der erste „Datenstruktur“-Kurs stammt aus der

CoresesToSelect-Sammlung, daher enthält ihn natürlich die CoresesToSelect-Sammlung , und der Aufruf der Methode „contains“ gibt „true ;The“ zurück Der zweite „Datenstruktur“-Kurs ist ein neuer (neu erstellter) Kurs, und das System hat einen weiteren Speicherplatz geöffnet. Obwohl sein Name derselbe ist wie der erste „Datenstruktur“, handelt es sich um zwei verschiedene Objekte. Die Methode „Contains“ vergleicht standardmäßig die Speicheradresse des Referenzobjekts (Hash-Code). Wie können wir also Kurse mit demselben Namen verwenden, um festzustellen, ob der Kurs in der Liste enthalten ist?

Hier müssen wir ein tiefgreifendes Verständnis der Prinzipien der „Contains“-Methode haben, um uns zu helfen, die „Contains“-Methode zu verstehen und anzuwenden. Wie in der folgenden Abbildung gezeigt:

Alle Klassen in der Methode werden von der Object-Klasse geerbt, und in der Object-Klasse gibt es eine Methode equal(), die verwendet wird Um zwei zu vergleichen Ob die Objekte gleich sind, finden Sie die ausführliche Erklärung der Methode equal() in meinem anderen Blog-Beitrag, Link:

Dann schauen wir uns die internen Prinzipien der Methode „contains“ an.

Wie in der Abbildung oben gezeigt, vergleicht die Methode „enthält“ tatsächlich, ob zwei Objekte gleich sind, indem sie die Methode „equals“ jedes Objekts in der Sammlung durchläuft. Wenn sie gleich sind, gibt sie „true“ zurück, andernfalls gibt sie „false“ zurück. Standardmäßig vergleicht equal(), ob die Referenzen zweier Objekte gleich sind. Wenn wir die Methode „contains“ verwenden möchten, um zu vergleichen, ob die Werte zweier Objekte gleich sind, um festzustellen, ob die Sammlung ein Objekt enthält, müssen wir „equals“ überschreiben ()-Methode des Objekts.

Im Folgenden wird die Methode equal() der Kursklasse neu geschrieben, um zu vergleichen, ob die Namen zweier Kursobjekte identisch sind, z. B.:

 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 }
Nach dem Login kopieren

重写完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     }
Nach dem Login kopieren

运行结果:

这就奇怪了,我们不是已经重写了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     }
Nach dem Login kopieren

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

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

这里我总结一下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     }
Nach dem Login kopieren

运行结果:

注意:

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     }
Nach dem Login kopieren

运行结果:

这里我使用了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));
Nach dem Login kopieren

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     }
Nach dem Login kopieren

运行结果:

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

 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     }
Nach dem Login kopieren

运行结果:

注意:

对于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     }
Nach dem Login kopieren
查看信息说是sort()方法类型不匹配,无法对Student类型的List进行排序,为什么会这样呢?我们来看一下API的sort方法说明:
Nach dem Login kopieren

原来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     }
Nach dem Login kopieren

再修改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     }
Nach dem Login kopieren

Ergebnisse ausführen:

Hinweis: Der direkte Aufruf von sort (set) verwendet die Standardvergleichsregeln; der Aufruf der überladenen Methode sort (set, implementiert ComparatorName des Schnittstellenobjekts) verwendet temporäre Regeln.

>>>>>>>>>>>>>> >>>>>> ;>>>>>>>>>>>>>>>>>>> >>

So vergleichen Sie Klassen ohne Standardvergleichsregeln:

1. Implementieren Sie die Comparable-Schnittstelle:

1 die Klasse.

2. Implementieren Sie die Methode .compareTo(class name object name). Wenn dieser größer ist, wird ein positiver Wert zurückgegeben, wenn sie gleich sind, wird 0 zurückgegeben, und wenn dieser kleiner ist, wird ein negativer Wert zurückgegeben zurückgegeben. (Verschiedene Klassen umfassen die Methode .compareTo())

3. Rufen Sie Collections.sort (Objektname) zum Sortieren auf.

2. Lassen Sie diese Klasse die Comparator-Schnittstelle implementieren:

1. Erstellen Sie eine neue Klasse und implementieren Sie Comparator

2 Objektname 1, Klassenname, Objektname 2) Methode, wenn dieser größer ist, wird ein positiver Wert zurückgegeben, wenn sie gleich sind, wird 0 zurückgegeben, wenn dieser kleiner ist, wird ein negativer Wert zurückgegeben.

3. Rufen Sie die Methode Collections.sort (Objektname, Objektname, der die Schnittstelle Comparator implementiert) auf.


4. Zusammenfassung des Java Collection Framework

Am Ende dieses Artikels haben wir endlich das Java Collection Framework erkannt, das den folgenden Inhalt enthält:

Sammlung Schnittstelle, Kartenschnittstelle, Sammlungstoolklasse, vergleichbare Schnittstelle, Komparatorschnittstelle

  • In Java Collection Framework (Teil 1) Erfahren Sie mehr über die Collection-Schnittstelle in

  • Erfahren Sie mehr über die Mao-Schnittstelle in

    Java Collection Framework (Teil 2); >In diesem Artikel haben wir etwas über die Collections-Toolklasse, die Comparable-Schnittstelle und die Comparator-Schnittstelle erfahren.

  • Ich habe gerade ein wenig darüber geschrieben. Wenn Sie mehr wissen möchten, lesen Sie bitte die Java-API.,,

Das obige ist der detaillierte Inhalt vonJava Collection Framework erklärt Teil 3. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!