Java集合(二)

1. List集合简单使用
//学习Collection子类List的一些特有方法的使用
        //1.创建,还是采用父类引用指向子类对象,开发中一般直接用子类
        List lt = new ArrayList();

        //2. void add(int index, E element):在指定位置添加元素
        lt.add("a");
        lt.add("b");
        lt.add("d");
         //在指定位置添加元素
        lt.add(2,"c");//index可以小于等于size()并且大于等于0;
        System.out.println(lt);

        //3. E remove(int index):移除指定位置的元素,返回被删除的那个元素
        lt.remove(2);
        System.out.println(lt);
        //这里我们举个例子有问题的情况
        List lt1 = new ArrayList();
        lt1.add(11);
        lt1.add(23);
        lt1.add(45);//我们将这几个整数加入到集合中
        //来用哈删除方法
        //Object ob3 = lt1.remove(11);//这样写运行就会报错,我们的本意
        //也许就是想删除我们加入到集合中的11元素,但是在加入集合时,有自动装箱
        //而在这里传值进来却没有自动装箱,所以系统会将这个11当成索引使用,那么就会越界报错

        //4. E get(int index):获取指定位置的元素
        Object ob = lt.get(2);//这个方法可以用来做遍历,这是List集合中特有的遍历方式
        System.out.println(ob);

        //5. E set(int index, E element):给集合中指定位置的元素赋值,并返回改变之前这个位置的元素值
        Object ob1 = lt.set(2,"jj");
        System.out.println(ob1);
        System.out.println(lt);

2. 并发修改异常产生的原因和处理
//1.需求:我有一个集合,请问我想判断里面有没有"world"元素,有就向集合里面添加一个"javaEE"元素
        List lt = new ArrayList();
        lt.add("a");
        lt.add("b");
        lt.add("d");
        lt.add("world");
        lt.add("f");
        //迭代器遍历
        //Iterator it = lt.iterator();
        //用专门操作List集合的迭代器
        ListIterator lir = lt.listIterator();
        while (lir.hasNext()){
            //用String来记录这个it.next()
            String str = (String)lir.next();
            //判断是否有world元素
            if (str.equals("world")){
               //有,就向集合中添加一个元素
               // lt.add("javaEE");
                //出错原因解释:我们的集合中原来就5个元素,拿给迭代器去负责展示,但是
                //在迭代器展示元素的过程中,我们又去给集合增加了一个元素,这样就造成了并发修改
                  lir.add("javaEE");
            }
        }
        System.out.println(lt);
        //错误显示:java.util.ConcurrentModificationException:并发修改异常:当方法检测到对象的并发修改,
        //但不允许这种修改时,抛出此异常
        //解决问题:我们可以利用迭代器自己有的方法来帮助我们修改集合中的元素

3. 简单学习ListIterator(了解反向遍历)
 //ListIterator简单操作
        List lt = new ArrayList();
        lt.add("a");
        lt.add("b");
        lt.add("d");
        lt.add("world");
        lt.add("f");
        //用专门操作List集合的迭代器
        ListIterator lir = lt.listIterator();
        while (lir.hasNext()){

            System.out.println(lir.next());//获取元素,并将指针向后移动
        }
        System.out.println("-------------------");

        while (lir.hasPrevious()){//判断是否有前一个
            System.out.println(lir.previous());//获取元素,并将指针向前移动--相当于反向遍历
        }
        //会出现的问题:如果我们把正向遍历的代码注释掉的话,会发现调用反向遍历的代码也没有作用。
        //这是因为没有正向遍历的话,集合指针是指向0这个索引的,我们来向前遍历的话,就会到-1,那就没有元素,所以直接没有返回了
4. 数组和链表
1.数组:查询快,修改快,但是增和删操作慢(ArrayList)
2.链表:查询,修改满, 增删快(LinkedList)
3.List的三个子类的特点:

ArrayList:
 底层数据结构是数组,查询快,增删慢
线程不安全,效率高
Vector:
底层数据结构是数组,查询快,增删慢
线程安全,效率低
Vector相对ArrayList查询慢(线程安全)
Vector相对LinkedList增删慢(数据结构)

LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。

Vector和ArrayList的区别:
Vector是线程安全的,效率低
ArrayList是线程不安全的,效率高

ArrayList和LinkedList的区别:
ArrayList底层数据结构,查询和修改快
LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢

//我们如何使用List的三个子类呢?
查询多用:ArrayList
增删多用:LinkedList
都多用:ArrayList

5. 去除ArrayList中的重复元素
 //去除ArrayList中的重复元素的方式
        //思路:创建新集合的方式
        ArrayList lt = new ArrayList();
        lt.add("a");
        lt.add("b");
        lt.add("j");
        lt.add("world");
        lt.add("f");
        lt.add("b");
        lt.add("b");
        lt.add("j");
        lt.add("j");
        lt.add("world");

      ArrayList newList = getSingleArr(lt);
        System.out.println(newList);
    }
    //单独抽取一个方法
    public static ArrayList getSingleArr(ArrayList arrl){
            //创建一个新集合
        ArrayList newList = new ArrayList();
        //获取老集合的迭代器
        Iterator it = arrl.iterator();
        //遍历这个老集合
        while (it.hasNext()){
            Object ob = it.next();
            if (!newList.contains(ob)){
                newList.add(ob);
            }

        }
        return newList;
    }
6. 对于自定义对象在ArrayList中的去重
首先定义一个自定义类
public class Student {

    //两个私有成员变量
    private String name;
    private int age;
    //空参构造
    public Student() {
        super();
    }
    //有参构造
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    //重写toString方法
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    @Override
    public boolean equals(Object obj){
       //比较字面值,不比较地址
        Student s = (Student)obj;
       if (this.name.equals(s.name) && this.age == s.age){
           return true;
       }else{
           return false;
       }

    }
}
//在实现中:
public static void main (String[] args){
         //去除ArrayList中自定义重复对象
        ArrayList lt = new ArrayList();
        lt.add(new Student("tmac",18));
        lt.add(new Student("tmac",18));
        lt.add(new Student("kobe",18));
        lt.add(new Student("tmac",18));
        lt.add(new Student("kobe",18));
        lt.add(new Student("tmac",18));
 ArrayList newList = getSingleArr(lt);
       Iterator it = newList.iterator();
       while (it.hasNext()){
           System.out.println(it.next());
       }
//我们传入的是自定义对象,但是同样执行我们去除重复元素的方法,打印发现并没有去除掉
        //我们仔细分析,没有去除掉应该是!newList.contains(ob)这个判断都是真。造成这个的原因是
        //我们看底层contains的实现,发现是用equals方法作比较的,而equals方法比较的是对象的地址值
        //而我们上面创建的对象,地址值都不一样,所以无法去除,解决办法就是重写Student对象的equals方法

//顺带做到这里了,我们也来举个列子,我们先将Student中的重写equals方法注释掉
        //我们来删除这个newList中的对象
        newList.remove(new Student("tmac",18));
        System.out.println("****");
        System.out.println(newList);
        //你会发现这样也删不掉,那是因为remove的方法,底层一样依赖的是equals方法

 }
    //单独抽取一个方法
    public static ArrayList getSingleArr(ArrayList arrl){
            //创建一个新集合
        ArrayList newList = new ArrayList();
        //获取老集合的迭代器
        Iterator it = arrl.iterator();
        //遍历这个老集合
        while (it.hasNext()){
            Object ob = it.next();
            if (!newList.contains(ob)){
                newList.add(ob);
            }
 }
        return newList;
    }
}

7. LinkedList的特有功能
//LinkedList的特有功能
        /*
        * public void addFirst(E e)及addLast(E e)
        * public E getFirst()及getLast()
        * public E removeFirst()及public E removeLast()
        * public E get(int index):
        * */

        //1.public void addFirst(E e)及addLast(E e):
        LinkedList list = new LinkedList();
        list.addFirst("a");
        list.addFirst("b");
        list.addFirst("c");
        list.addFirst("d");
        //我们看这个我们每个元素都是放到第一位的,对于链表来说,就成了先进在后了
        System.out.println(list);

        list.addLast("e");
        list.addLast("f");//addLast:就是先进在前了
        System.out.println(list);

        //2. public E getFirst()及getLast()
        Object ob = list.getFirst();
        Object ob1 = list.getLast();
        System.out.println(ob);
        System.out.println(ob1);
        //3. public E removeFirst()及public E removeLast():删除头尾
        //4. public E get(int index):根据索引查找元素
        Object ob2 = list.get(2);
        //我们看这个get(int index):的源码,就知道为什么这个链表的查找更慢了
        System.out.println(ob2);
8. 栈和队列数据结构
栈: 先进后出

队列: 先进先出

LinkedList模拟栈的数据结构:
单独封装一个Stack(栈类):
public class Stack {
    //我们自己创建一个栈类,然后内部用LinkedList来实现进栈和弹栈
    //创建LinkedList的成员变量
    private LinkedList list = new LinkedList();
    //模拟进栈方法
    public void inStack(Object obj){
        list.addLast(obj);
    }

    //模拟出栈
    public  Object outStack(){
        return list.removeLast();
    }

    //模拟栈结构是否为空
    public  boolean isEmpty(){
        return list.isEmpty();
    }

    //重写Object的toString方法
    public String toString(){
        String str = new String();
        Iterator it = list.iterator();
        while (it.hasNext()){
           Object ob = it.next();
           str = str + ob + ",";
        }
       return str;
    }
}
//使用:
//直接调用我们封装的Stack类
        Stack s = new Stack();
        s.inStack("a”);//这里最先加进去的元素其实是a,因为最先调用这个加入a元素的方法
        s.inStack("b");
        s.inStack("c”);//理解一下先进后出
        System.out.println(s);
        while (!s.isEmpty()){
            System.out.println(s.outStack());
        }

9. 泛型简介
//泛型
        /*
        * 泛型好处:
        * 提高安全性(将运行期的错误转换到编译器)
        * 免去强转的麻烦
        * 泛型基本作用:
        * <>号中放的必须是引用数据类型
        * 泛型使用注意事项:
        * 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7版本的新特性)
        * */

        //泛型举例说明:
        ArrayList<Student> list = new ArrayList<Student>();
//        list.add(110);
//        list.add(true);
        list.add(new Student("tmac",18));
        list.add(new Student("李四",24));
        //我们给集合添加了三个不同类型的值,我们来遍历一下
         Iterator<Student> it = list.iterator();
         while (it.hasNext()){
             //System.out.println(it.next());
             //我们这样直接遍历是没有问题的,但是如果我们想要获得Student对象中的名字,年龄,
             //就要单独调用Student中的getName和getAge方法,如果我们直接将it.next()获得的元素
             //直接强转为Student对象,就会出错
//             Student s = (Student)it.next();
             //System.out.println(s.getName() + "   " + s.getAge());
             //报错:java.lang.ClassCastException:类型转换异常
             //解决加泛型--其实和iOS里面的泛型是一个道理哈

             Student s= it.next();
             //最好不要直接打印it.next(),因为it.next()方法只能调用一次,调用多次会将指针向后移动
             System.out.println(s.getName() + " 、、 " + s.getAge());
  }

10.方法泛型的区别
//泛型
        //普通方法
        Tool tool = new Tool();
        tool.show("我爱你");
        //静态方法
        Tool.print("我是谁”);

public class Tool<T> {
    private  T t;

    public  T getObj(){
        return t;
    }

    public void setObj(T t){
        this.t = t;
    }

    public void show(T t){
        System.out.println(t);//方法泛型最好和类的泛型一致
                              //如果不一致,需要在方法前声明该泛型
    }
     //对于T而言,在创建Tool的对象,给其赋值的时候,是什么类型的,T就是什么类型的

     //对于静态方法--必须要声明自己的泛型
    //这是因为,T是跟随Tool对象时,创建而创建,而静态方法是跟随Tool类的创建而创建的
    //如果我们将静态方法的泛型和类的泛型相同的话,很可能Tool对象还没有创建,而Tool创建了
    //这样我们静态方法的泛型就会出问题
    public static<X> void print(X x){
        System.out.println(x);
    }
    //这个一致,不是说命名相同,如果我只是在静态方法的方法名后接泛型名和类相同,是不行的
    //但是这样写是可以的:public static<T> void print(T t){}是可以的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容