例子5:演示List集合中常见的共性方法
- package cn.itheima.day11;
- import java.util.ArrayList;
- import java.util.List;
-
-
-
-
-
-
-
-
-
-
-
- public class ListDemo {
- public static void main(String[] args) {
- List list = new ArrayList();
- list.add("abc1");
- list.add("abc2");
- list.add("abc3");
- System.out.println("原集合元素:"+list);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- for(int x=0;x<list.size();x++){
- System.out.println(list.get(x));
- }
-
- }
- }
例子6:在迭代集合元素的同时,操作集合元素。
- package cn.itheima.day11;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- public class ListIteratorDemo {
- public static void main(String[] args) {
- List list = new ArrayList();
- list.add("abc1");
- list.add("abc2");
- list.add("abc3");
- list.add("abc4");
-
- Iterator it = list.iterator();
- while(it.hasNext()){
- String s = (String)it.next();
- if(s.equals("abc2"))
-
- list.add("haha");
- System.out.println("s="+s);
- }
- System.out.println(list);
- }
- }
在进行迭代过程中,如果出现了迭代器和容器同时对元素进行操作的情况很容易引发ConcurrentModificationException并发修改异常.解决方法:要么使用集合的方法操作元素,要么使用迭代器的方法操作元素。不要同时使用。很遗憾的是 迭代器Iterator中只有三个操作,判断hasNext,获取next,删除remove。想要其他的操作时,比如添加,这个迭代器就不可以使用了。这时怎么办呢?注意:对于List集合。有一个新的迭代方式。 就是ListIterator 列表迭代器。ListIterator本身也是Iterator的子接口。并提供了更多的迭代过程中的操作。在迭代过程中,如果需要增删改查元素的操作,需要列表迭代器。但是注意:该迭代器,只能用于List集合。
例子7:演示一下ListIterator列表迭代器的使用方法。
- package cn.itheima.day11;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import java.util.ListIterator;
- public class ListIteratorDemo2 {
- public static void main(String[] args) {
- List list = new ArrayList();
- list.add("abc1");
- list.add("abc2");
- list.add("abc3");
- list.add("abc4");
-
- ListIterator lit = list.listIterator();
- while(lit.hasNext()){
- String s = (String)lit.next();
- if(s.equals("abc2"))
-
- lit.set("qq");
- System.out.println("s="+s);
- }
- boolean b = lit.hasPrevious();
- System.out.println("b="+b);
- System.out.println(list);
- }
- }
List:有序,可重复,有索引。(面试重点) |--ArrayList:底层数据结构是数组结构。线程不安全的。所以ArrayList的出现替代了Vector.但是查询的速度很快,增删慢. |--Vector:底层数据结构是数组结构。jdk1.0版本。线程安全的。无论增删还是查询都非常慢。 |--LinkedList:底层是链表数据结构。线程不安全的,同时对元算的增删操作效率很高 可变长度的数组: ArrayList内部封装了一个默认长度为10的数组。当超出长度时,集合内部会自动生成一个新的数组。将原数组中的元素复制到新数组中,在将新元素添加到新数组。那么,新数组到底多长呢? 一般:ArrayList 50%延长,Vector100%延长。LinkedList的特有方法: 1)addFirst(); addLast();在jdk1.6以后。被 offerFirst(); offerLast();替代 2)获取元素,集合的长度不改变。如果集合中没有元素,那么该方法会发生异常NoSuchElementException getFirst(): getLast();在jdk1.6以后。被 peekFirst(); peekLast();替代 如果集合元素没有,该方法不会抛出异常,而是返回null。 3)获取元素(指的是删除元素后,元素返回回来显示),但是该元素会被删除出集合,集合的长度会改变。如果集合中没有元素,那么该方法会发生异常NoSuchElementException removeFirst(): removeLast(); 在jdk1.6以后。被 pollFirst(); pollLast();替代 如果集合元素没有,该方法不会抛出异常,而是返回null。
例子8:LinkedList对象的常见方法举例。
- package cn.itheima.day11;
- import java.util.LinkedList;
-
- public class LinkedListDemo {
- public static void main(String[] args) {
- LinkedList link =new LinkedList();
- link.addFirst("abc1");
- link.addFirst("abc2");
- link.offerFirst("abc3");
- link.offerFirst("abc4");
-
- System.out.println(link);
-
-
- System.out.println("头部元素="+link.peekFirst());
- System.out.println("尾部元素="+link.peekLast());
-
-
- System.out.println("删除头部元素="+link.pollFirst());
- System.out.println("删除后的头部元素="+link.peekFirst());
-
- while(!link.isEmpty()){
- System.out.println(link.removeFirst());
- }
- }
- }
Vector中提供了一个独特的取出方式,就是枚举Enumeration。此接口Enumeration的功能与 Iterator 接口的功能是重复的,Enumeration的名称和方法的名称过程,书写很麻烦。所以被Iterator所取代。
例子9: Vector中独特的取出方式实例演示。
- package cn.itheima.day11;
- import java.util.Enumeration;
- import java.util.Vector;
- public class VectorDemo {
- public static void main(String[] args) {
- Vector v = new Vector();
- v.addElement("abc1");
- v.addElement("abc2");
- v.addElement("abc3");
- v.addElement("abc4");
- Enumeration en = v.elements();
- while(en.hasMoreElements()){
- System.out.println(en.nextElement());
- }
- }
- }
例子10. 去除ArrayList集合中的重复元素。最好该元素还是自定义的。比如Person,如果同姓名,同年龄视为相同元素。
- package cn.itheima.day11;
- import java.util.ArrayList;
- import java.util.Iterator;
-
-
-
-
-
-
-
-
-
-
-
- class Person1{
- private String name;
- private int age;
- public Person1(String name, int age) {
- super();
- this.name = name;
- this.age = age;
- }
-
-
-
-
-
-
-
- public boolean equals(Object obj){
- if(this==obj){
- return true;
- }
- if(!(obj instanceof Person1)){
- return false;
- }
- Person1 p = (Person1)obj;
- return this.name.equals(p.name) && this.age==p.age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return name +"--" + age ;
- }
- }
- public class ListTest {
- public static ArrayList getSingleElement(ArrayList al){
- ArrayList newList = new ArrayList();
- Iterator it = al.iterator();
- while(it.hasNext()){
- Object obj = it.next();
- if(!newList.contains(obj)){
-
-
- newList.add(obj);
- }
- }
- return newList;
- }
- public static void main(String[] args) {
- ArrayList al = new ArrayList();
- al.add(new Person1("abc3", 23));
- al.add(new Person1("abc1", 21));
-
- al.add(new Person1("abc2", 22));
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- System.out.println(al);
-
-
- boolean b = al.remove(new Person1("abc2", 22));
- System.out.println(b);
- System.out.println(al);
- }
- }
例子11. 使用LinkedList模拟一个堆栈或者队列数据结构。 堆栈结构:先进后出。First In Last Out FILO 队列结构:先进先出。First In First Out FIFO 应该定义一个对象,内部使用的LinkedList。 对外提供添加获取的功能,可以完成对应的结构效果。
- package cn.itheima.day11;
- import java.util.LinkedList;
-
-
-
-
-
-
- class DuiLie{
- private LinkedList link;
- public DuiLie() {
- link = new LinkedList();
- }
- public void add(Object obj){
- link.addFirst(obj);
- }
- public Object get(){
-
- return link.removeLast();
- }
- public boolean isNull(){
- return link.isEmpty();
- }
- }
- public class ListTest2 {
- public static void main(String[] args) {
- DuiLie dl = new DuiLie();
- dl.add("abc1");
- dl.add("abc2");
- dl.add("abc3");
- dl.add("abc4");
- while(!dl.isNull()){
- System.out.println(dl.get());
- }
- }
- }
例子12.将字符串中的数值进行排序,生成一个新的字符串原字符串为“90 -1 23 0 8 14” 思路: 1,先要把数值取出。 2,存储到int数组中。 3,对int数组排序。 4,将int数组变成字符串。
- package cn.itheima.day11;
-
-
-
-
-
-
-
-
-
- class Tool {
-
- public static String sortNumberString(String str, String reg) {
- String[] arr = splitString(str, reg);
- int[] temp = stringToIntArray(arr);
- sortArray(temp);
- return toString(temp, reg);
- }
-
- private static String[] splitString(String str, String reg) {
- return str.split(reg);
- }
-
- private static int[] stringToIntArray(String[] arr) {
- int[] temp = new int[arr.length];
- for (int x = 0; x < arr.length; x++) {
- temp[x] = Integer.parseInt(arr[x]);
- }
- return temp;
- }
-
- private static void sortArray(int[] arr) {
-
- for (int x = 0; x < arr.length - 1; x++) {
- for (int y = x+1; y < arr.length; y++) {
- if (arr[x] > arr[y]) {
- int temp = arr[x];
- arr[x] = arr[y];
- arr[y] = temp;
- }
- }
- }
- }
-
- private static String toString(int[] arr, String reg) {
- StringBuilder sb = new StringBuilder();
- for (int x = 0; x < arr.length; x++) {
- if (x != arr.length - 1) {
- sb.append(arr[x] + reg);
- } else {
- sb.append(arr[x]);
- }
- }
- return sb.toString();
- }
- }
- public class Test {
- public static void main(String[] args) {
- String s =Tool.sortNumberString("90 -1 23 0 8 14"," ");
- System.out.println(s);
- }
- }
例子13,以下是一个多线程的运行实例,要求写出这个线程运行的过程。
- package cn.itheima.day11;
- class MyThread extends Thread{
- public void run(){
- try {
- Thread.currentThread().sleep(1000);
- } catch (InterruptedException e) {
- }
- System.out.println("MyThread running");
- }
- }
- public class ThreadTest {
- public static void main(String[] args) {
- MyThread t = new MyThread();
- t.run();
- t.start();
- System.out.println("Thread Test");
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
Collection |--List:有序(存储的顺序和取出的顺序一致。)元素可以重复,元素都有索引。 |--ArrayList: |--LinkedList: |--Set:无序,不可以重复元素。Set接口的方法和Collection中的方法一致。Set接口取出元素的方法只有迭代器。 |--HashSet:底层数据结构是哈希表。哈希表这种结构,其实就是对哈希值的存储。而且每一个对象都有自己的哈希值。因为Object类中的有一个方法hashCode方法。如何保证元素唯一性的呢?通过判断元素的hashCode方法,和equals方法完成的。当hashCode值相同是,会在判断一次euqals方法的返回值是否为true。如果hashCode值不相同,就确定元素的哈希表中的位置,就不用在判断equals了。哈希表中有一个桶结构。每一个桶都有一个哈希值,当哈希值相同,但是equals为false是,这些元素都存放一个桶里。 |--TreeSet:可以对Set集合中的元素进行排序。数据结构是二叉树数据结构。这种结构,可以提高排序性能。它又是如何保证元素唯一性的呢? 是根据比较方法的返回值确定的。只要返回的是0.就代表元素重复。
例子14:HashSet集合类的使用演示。
- package cn.itheima.day12;
- import java.util.HashSet;
- import java.util.Iterator;
- public class HashSetDemo {
- public static void main(String[] args) {
- HashSet hs = new HashSet();
- hs.add("abc2");
- hs.add("abc1");
- hs.add("abc3");
- hs.add("abc1");
- hs.add("abc3");
- hs.add("abc2");
- System.out.println("size:"+hs.size());
- Iterator it = hs.iterator();
- while(it.hasNext()){
- System.out.println(it.next());
- }
- }
- }
HashSet集合是如何保证元素唯一性的? HashSet集合保证元素唯一性,依赖的是元素的hashCode方法和euqals方法。当元素的哈希值不同时,元素都有自己的独立位置。不需要在判断元素的equals方法,当元素的哈希值相同时,这时元素在哈希表中位置相同,这时就需要再判断一次元素的内容是否相同。就需要调用元素的equals方法进行一次比较。如果equals返回是true。那么视为两个元素为重复元素。只储存一个。如果返回是false,那么这两个元素不是重复元素,会存储在同一个哈希值上。为了建立自定义对象判断元素是否重复的依据。需要覆盖hashCode方法,和equals方法。而且最好依据对象的特有条件来建立hashcode和euqals的实现。
例子15.HashSet中存储自定义的对象,如果姓名和年龄都相同就视为相同对象。就不进行存储了。
- package cn.itheima.day12;
- import java.util.HashSet;
- import java.util.Iterator;
- public class HashSetDemo2 {
- public static void main(String[] args) {
-
- HashSet hs = new HashSet();
- hs.add(new Person("lisi1", 21));
- hs.add(new Person("lisi6", 26));
- hs.add(new Person("lisi3", 23));
- hs.add(new Person("lisi6", 26));
- hs.add(new Person("lisi5", 25));
-
- Iterator it = hs.iterator();
- while(it.hasNext()){
- Person p = (Person)it.next();
- System.out.println(p.getName()+"------"+p.getAge());
- }
- }
- }
-
- class Person{
- private String name;
- private int age;
- public Person(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public int hashCode(){
- System.out.println(this+"-----hashCode");
- final int NUMBER = 3;
- return name.hashCode() + age*NUMBER;
-
- }
-
- public boolean equals(Object obj){
- System.out.println(this+"---equals----"+obj);
- if(this == obj)
- return true;
- if(!(obj instanceof Person))
- return false;
- Person p = (Person)obj;
- return this.name.equals(p.name) && this.age==p.age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return name+"----"+age;
- }
- }
总结细节特点: ArrayList:判断包含,以及删除,都是依据元素的equals方法。 HashSet:判断包含,以及删除,都是依据元素的hashCode方法。当hashCode值相同时,在判断一次equals方法。
例子16.HashSet的remove()方法的使用方法,即特点。
- package cn.itheima.day12;
- import java.util.HashSet;
- public class HashSetDemo3 {
- public static void main(String[] args) {
-
- HashSet hs = new HashSet();
- hs.add(new Person1("lisi1", 21));
-
-
- hs.add(new Person1("lisi6", 26));
- hs.add(new Person1("lisi1", 21));
- hs.add(new Person1("lisi3", 23));
- hs.add(new Person1("lisi5", 25));
- System.out.println("---------------");
- System.out.println("contains:"+hs.contains(new Person1("lisi6",26)));
- System.out.println("remove:"+hs.remove(new Person1("lisi1", 21))); System.out.println(hs);
- }
- }
-
- class Person1{
- private String name;
- private int age;
- public Person1(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public int hashCode(){
- System.out.println(this+"-----hashCode");
- final int NUMBER = 3;
- return name.hashCode() + age*NUMBER;
-
- }
-
- public boolean equals(Object obj){
- System.out.println(this+"---equals----"+obj);
- if(this == obj)
- return true;
- if(!(obj instanceof Person1))
- return false;
- Person1 p = (Person1)obj;
- return this.name.equals(p.name) && this.age==p.age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return name+"----"+age;
- }
- }
treeset集合使用于给元素进行排序的。那么自定义元素本身不具备比较性,treeset集合是无法对元素进行排序的。所以,在自定义对象时,需要对象具备一个扩展功能,用于比较的,而java已经提供了接口,可以让实现它的对象具备比较性。那么自定义类,要想要被treeset排序,就需要实现Comparable接口。以具备比较功能。比较的时候,要注意,主要条件和次要条件。如果主要条件相同,一定要比较次要条件。
例子17.自定义对象Person,想要对人对象按照年龄的从小到大排序。
- package cn.itheima.day12;
- import java.util.TreeSet;
- public class TreeSetDemo2 {
- public static void main(String[] args) {
- TreeSet ts = new TreeSet();
- ts.add(new Person2("lisi1", 21));
- ts.add(new Person2("lisi3", 23));
- ts.add(new Person2("lisi4", 24));
- ts.add(new Person2("lisi2", 22));
- ts.add(new Person2("lisi6", 26));
- ts.add(new Person2("lisi2", 23));
- System.out.println(ts);
- }
- }
-
- class Person2 implements Comparable{
- private String name;
- private int age;
- public Person2(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return name+"----"+age;
- }
- @Override
- public int compareTo(Object obj) {
- Person2 p = (Person2)obj;
-
-
- int num =new Integer(this.age).compareTo(new Integer(p.age));
- return num==0?this.name.compareTo(p.name):num;
-
-
-
-
-
-
- }
- }
当treeset集合中存储的元素不具备比较功能。或者具备的比较功能不是所需要的。例如:Person对象中的自然排序是按照年龄排序。现在需求:但是现在需求是想按姓名排序。改源代码这种方式想都不要想。有这种想法就是犯罪。该如何解决这个问题?既然元素具备的比较方式不满足应用。这时,可以让集合自身具备比较性。需要集合一初始化就具备比较功能。因为要在添加元素前具备。就需要在构造函数进行初始化。只要将一个实现了Comparator接口的子类对象作为参数传递给TreeSet集合的构造函数即可。这样该集合就具备了比较功能。建议使用第二种排序方式。
例子18,定义使用比较器来按照姓名进行对Person排序。
- package cn.itheima.day12;
- import java.util.Comparator;
- import java.util.TreeSet;
- public class TreeSetDemo3 {
- public static void main(String[] args) {
- TreeSet ts = new TreeSet(new CompareByName());
- ts.add(new Person3("lisi1", 21));
- ts.add(new Person3("lisi3", 23));
- ts.add(new Person3("lisi4", 24));
- ts.add(new Person3("lisi2", 22));
- ts.add(new Person3("lisi6", 26));
- System.out.println(ts);
- }
- }
-
- class CompareByName implements Comparator{
- @Override
- public int compare(Object o1, Object o2) {
- Person3 p1 = (Person3)o1;
- Person3 p2 = (Person3)o2;
- int num = p1.getName().compareTo(p2.getName());
- return num==0?p1.getAge()-p2.getAge():num;
- }
- }
- class Person3{
- private String name;
- private int age;
- public Person3(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return name+"----"+age;
- }
- }
总结:TreeSet排序方式有两种。 1,让元素自身具备比较性。其实是让元素实现Comparable接口,覆盖compareTo方法,此方法有一个参数。这称为元素的自然排序。 2,当元素自身不具备比较性,或者元素具备的比较性不是所需要的,可以让集合自身具备比较性。定义一个比较器:其实就是定义一个类,实现Comparator接口。覆盖compare方法,此方法有两个参数。将Comparator接口的子类对象作为参数传递给TreeSet的构造函数。当元素自身具备比较性,同时TreeSet集合也具备比较器,这时以比较器为主.到了这里,一般在描述一个对象时,如果该对象封装了具体的数据,会出现很多这样的对象比如:员工,学生对象等.这时就需要进行容器的存储.那么描述该类对象时,一定要复写几个方法. 1,hashCode() 2,equals() 3,toString()前三个方法如果不定义,本身对象中就有,但是,是继承于Object中的,而Object的排序都是按照自身的地址值,是不合适的,所以对象要定义依赖对象自身特征的条件判断。建立自己的特点。 4,最好实现Comparable接口让该类具备自然排序功能。 5.自身的构造函数。建立对象自身判断是否相同的依据,同时让对象具备基本的比较性。
例子19,对字符串进行长度排序,使用TreeSet.
- package cn.itheima.day12;
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.TreeSet;
-
-
-
-
-
-
-
-
-
- public class TreeSetTest {
- public static void main(String[] args) {
- TreeSet ts = new TreeSet(new CompareByLen());
- ts.add("abc");
- ts.add("z");
- ts.add("na");
- ts.add("cccpd");
- ts.add("sdssdfs");
- ts.add("bca");
- Iterator it = ts.iterator();
- while(it.hasNext()){
- System.out.println(it.next());
- }
- }
- }
-
- class CompareByLen implements Comparator{
- @Override
- public int compare(Object o1, Object o2) {
- String s1 = (String)o1;
- String s2 = (String)o2;
-
-
-
-
- int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
- return num==0?s1.compareTo(s2):num;
- }
- }