Java基础集合、泛型

集合

集合的由来:对象用于封装特有数据,对象多了就需要储存,如果对象的个数不确定,就使用集合进行存储

集合的特点:
1.用于储存对象的容器
2.集合的长度是可变的
3.集合中不可以存储基本数据类型值

集合容器因为内部的数据结构不同,有多种具体的容器,不断向上抽取就形成了集合框架

框架顶层:Collection

Collection接口的常用方法:
1.添加
boolean add(Object obj) 添加元素
boolean addAll(Collection coll)添加集合
2.删除
clear() 将集合中的元素全删除,清空集合。
boolean remove(Object obj)删除元素
boolean removeAll(Collection coll)将两个集合中相同的元素从调用removeAll的集合中删除

3.判断
boolean isEmpty() 判断集合中是否包含元素,如果不包含就返回true
boolean contains(Object obj) 判断集合中是否包含元素,如果包含就返回true
boolean containAll(Collection coll)

4.获取
int size() 获取集合中的元素个数
Iterator iterator() 取出集合中的元素的方式(迭代器)

5.其他
boolean retainAll() 仅保留此Collection中那些也包含在指定Collection中的元素(和removeAll相反)

iterator 迭代器中的方法:

boolean hasNext ==》 判断是否还有元素可以迭代

E next ==》返回迭代的下一个元素

void remove ==》从迭代器指定的Collection中移除迭代器返回的最后一个元素

迭代的两种方式:
1.

Iterator it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
        }

2.

for(Iterator it = coll.iterator();it.hasNext(); ){
System.out.println(it.next());
        }

注意:for循环中哄的it循环完后就从内存释放了,而while中的it循环完后还可以使用(占内存)

每一个容器都有自己的取出方式,且都在容器的内部,为了能建立每一个容器内部取出的统一规则,就对其进行了规则的定义:hasNext()、next()。怎么判断,怎么取出是容器自己实现的。

迭代器的由来:
将每一个容器中统一的取出规则进行抽取,于是得到了迭代器接口(Iterator)

每一个容器内部都实现了Iterator接口的抽象方法,且在容器中都为内部类,而调用容器内部的Iterator接口的实现方法则需要创建Iterator接口对象,通过对象调用容器中实现的Iterator接口方法

在使用容器中Iterator接口的实现方法:
1.通过创建一个容器对象来调用容器中Iterator接口的实现方法,这样会带来不安全性,因为在获取Iterator接口实现方法的同时,还可以调用容器中的其他方法

2.通过容器内部的iterator()方法创建一个Iterator接口的对象,将对象的使用权限向上抽取,降低了对象对容器的调用权限,这样一来有利于安全性,所以建议使用这种方法。

Collection接口中的子类接口—List接口:

List接口的特性:
有序的Collection(存入和取出的顺序一致),元素都有索引(角标),与set不同的是列表通常允许重复的元素

List接口下的实现类:
1.ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
2.LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。
3.Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都很慢。

数组在增大进行延长时:ArrayList:50%延长
Vector:100%延长
增删操作分析:
ArrayList:增删慢是因为空间是连续的,增删一个元素其后面的元素都需要移动

LinkedList:增删快是因为空间不是连续的,只需要修改相关的地址值就可以了

查询操作分析:
ArrayList:查询快是因为空间是连续的
LinkedList:查询慢是因为空间是不连续的

List特有的常用方法:
1.添加
void add(index,element)
void addAll(index,element)==》在指定位置插入指定的Collection中的所有元素

2.删除
Object remove(index)==》删除指定角标的元素

3.获取
Object get(index)==》通过角标获取元素
int indeOf (Object)==》通过元素获取第一次出现的角标
int lastIndexOf(Object)==》通过元素获取最后一次出现的角标
List subList(form,to)==获取子串

4.修改
Object remove(index,element)==》修改指定角标的元素

在Collection接口的子类List接口中凡是能操作角标的方法都是特有方法

List接口可完成增擅长优化了其父类接口(Collection)功能的局限性

当对集合对象冰法存在修改、访问或者修改、修改时,就会抛出异常(ConCurrentModificationException)
示例:


List list = new ArrayList();
list.add("1");
list.add("2");
Iterator i = list.iterator();

while(i.hasNext){
Objec obj = it.next();

if(obj.equals(“2”)){
list.add(“5”);
   }
   else
   System.out.println("next:"+obj)
}

注意事项:
1.集合中元素的存在,首先要有Collection(集合)接口的实现类

2.在Collection的实现类中,用实现类依据所需,创建一个Collection接口对象或者其子类类接口对象(之所以不创建本类对象,而通过接口向上转型,十位了限制对象的权限,起到安全作用)

3.Collection接口中没有直接对元素进行取出的方法,只有迭代器。而每个Collection接口的实现子类中都有自己的Iterator(迭代器)实现方法,Collection可通过Iterator(迭代器)对元素进行取出操作

List接口还优化出了独有的ListIterator迭代器比Collection接口中的Iterator迭代器更完善的功能。

add(E e) 将指定的元素插入列表

hasNext() 以正向遍历列表,如果 next 返回一个元素而不是抛出异常,则返回 true

haspervious() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。

next() 返回列表中的下一个元素。

nextIndext() 返回对 next 的后续调用所返回元素的索引。

pervious() 返回列表中的前一个元素。

perviousIndex() 返回对 previous 的后续调用所返回元素的索引。

remove() 从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)

set(E e) 用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)

在List集合中对元素操作完毕后若还需要对集合中的元素进行操作可以通过其独有的ListIterator迭代器进行操作

ArrayList集合示例:

public class Person {
    public String name;
    public int age;

    public Person(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;
    }

    @Override
    public int hashCode() {

        return 0;
    }
    public String toString(){
        return name.toString()+":"+age;

    }
    @Override
    public boolean equals(Object obj) {
//      System.out.println("调用equals()方法的对象为:"+this.getName()+"     被调用的对象为:"+((Person)obj).getName());
        Person p =(Person)obj;
        //System.out.println(this.name.equals(p.name));
        return this.name.equals(p.name) && this.age==p.age;
    }


}
public class ArrayListTextBean2 {
public static void main(String[] args) {


//      demo();

//      singleDemo();


        ArrayList al = new ArrayList();
        al.add(new Person("lisi1",21));
        al.add(new Person("lisi2",22));
        al.add(new Person("lisi3",23));
        al.add(new Person("lisi4",24));
        al.add(new Person("lisi2",22));
        al.add(new Person("lisi3",23));
        System.out.println(al);

        al = getSingleElement(al);


        System.out.println(al); 

    }

    /**
     * 
     */
    public static void singleDemo() {
        ArrayList al = new ArrayList();
        al.add("abc1");
        al.add("abc2");
        al.add("abc2");
        al.add("abc1");
        al.add("abc");
        System.out.println(al);

        al = getSingleElement(al);

        System.out.println(al);


    }

    public static ArrayList getSingleElement(ArrayList al) {

        //1,定义一个临时容器。
        ArrayList temp = new ArrayList();

        //2,迭代al集合。
        Iterator it = al.iterator();

        while(it.hasNext()){
            Person obj = (Person)it.next();

            //3,判断被迭代到的元素是否在临时容器存在。
            if(!temp.contains(obj)){
                temp.add(obj);
                System.out.println("除去重复被添加的元素为:"+obj.getName()+"   "+obj.getAge());
            }
        }

        return temp;
    }
}

结果为:

除去重复被添加的元素为:lisi2   22
除去重复被添加的元素为:lisi3   23
除去重复被添加的元素为:lisi4   24
[lisi1:21, lisi2:22, lisi3:23, lisi4:24]

LinkedList:的特有方法。
addFirst();
addLast();
在jdk1.6以后。
offerFirst();
offerLast();

getFirst():获取链表中的第一个元素。如果链表为空,抛出NoSuchElementException;
getLast();
在jdk1.6以后。
peekFirst();获取链表中的第一个元素。如果链表为空,返回null。
peekLast();

removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出NoSuchElementException
removeLast();
在jdk1.6以后。
pollFirst();获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回null。
pollLast();

LinkedList集合示例:

public class LinkedListText {

    /**
     * @param args
     */
    public static void main(String[] args) {
        LinkedList ll = new LinkedList();
        ll.add("thangsan");
        ll.add("zhangsan");
        ll.add("ehangsan");
        ll.add("fhangsan");
        ll.add("rangsan");

        Iterator it = ll.iterator();
        //!ll.isEmpty()
        while(it.hasNext()){
            System.out.println(it.next());
        }

    }

}

结果为:

thangsan
zhangsan
ehangsan
fhangsan
rangsan

add()添加一个对象进来但默认的是Object类型的,这也就因为在可以接受任意类,但都会让传进来的类向上转型为Object类型,失去类原有的特有方法

通过Iterator(迭代器)方法被添加进入集合的元素访问的是向上转型后的元素,并不是原有的对象,所以不能访问这个对象中的特有方法,若迭代器中想访问这个对象中的特有方法,则需要对这个对象向下转型
例如:
Person p = (Person)it.next();

Set接口:
Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一种,迭代器。

Set接口的实现子类:
1.HashSet:底层数据结构是哈希表,线程是不同步的。无序,高效;

2.LinkedHashSet:有序,hashset的子类。

3.TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

HashSet集合保证元素唯一性:
通过元素的hashCode方法,和equals方法完成的。
当元素的hashCode值相同时,才继续判断元素的equals是否为true。
如果为true,那么视为相同元素,不存。如果为false,那么存储。
如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。

TreeSet集合保证元素唯一性:
用元素中的compareTo(Object obj)方法 ==》来自于comparale接口
用集合本身定义的compare(Object o1,Object o2)方法==》来自于comparator接口

compareTo()和compare()方法其原理都是二叉树,为了提高二叉树的查找效率,在每次添加新元素前都会对已有元素进行折中;当调用方法后返回值=0时,则调用此方法的对象,等于当前集合对象中的某一元素,为保证唯一性,调用此方的元素将不被添加入集合。

HashSet集合示例:

public class HashsetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /*创建一盒HashSet实现类对象*/
        HashSet hs = new HashSet();

        /*往HashSers实现类中添加元素(对象)*/
        hs.add(new Person("lisi1",11));
        hs.add(new Person("lisi2",12));
        hs.add(new Person("lisi3",13));
        hs.add(new Person("lisi4",14));
        hs.add(new Person("lisi1",11));
        /*创建引用Iteator对象,引用Hashset中的iterator()方法*/
        Iterator it = hs.iterator();

        /*通过while循环输出元素(对象)*/
        while(it.hasNext()){
            Person p = (Person)it.next();
            System.out.println(p.getName()+"..."+p.getAge());
        }

结果为:

lisi4...14
lisi3...13
lisi2...12
lisi1...11

LinkHashSet集合示例:

public class LinkHashSet {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /*创建一盒HashSet实现类对象*/
        HashSet hs = new LinkedHashSet();

        /*往HashSers实现类中添加元素(对象)*/
        hs.add("lisi1");
        hs.add("lisi2");
        hs.add("lisi3");
        hs.add("lisi4");
        hs.add("lisi5");

        /*创建引用Iteator对象,引用Hashset中的iterator()方法*/
        Iterator it = hs.iterator();

        /*通过while循环输出元素(对象)*/
        while(it.hasNext()){
//          Person p = (Person)it.next();
//          System.out.println(p.getName()+"..."+p.getAge());
            System.out.println(it.next());
        }
    }

}

结果为:

lisi1
lisi2
lisi3
lisi4
lisi5

TreeSet示例:

public class TreeSetPersonAge implements Comparable{

    private String name;
    private int age;

    public TreeSetPersonAge(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;
    }

    @Override
    public int hashCode() {

        return 0;
    }

    @Override
    public String toString(){
        return name.toString()+" "+age;
    }
    public int compareTo(Object o) {
        TreeSetPersonAge p = (TreeSetPersonAge)o;
        int temp = this.age - p.age;
//      System.out.println("传入的值为:"+this);
//      System.out.println("此时的折点为:"+p);
        return temp==0?this.name.compareTo(p.name):temp;
    }
}
public class TreeSetDemoAge {

    public static void main(String[] args) {
        /*=======按照名字的字典顺序排序*/
        /*创建TreeSet集合*/
        TreeSet ts = new TreeSet();

        /*在集合中添加元素(对象)*/
        ts.add(new TreeSetPersonAge("zhangsan",28));
        ts.add(new TreeSetPersonAge("ehangsan",38));
        ts.add(new TreeSetPersonAge("rangsan",48));
        ts.add(new TreeSetPersonAge("thangsan",58));
        ts.add(new TreeSetPersonAge("fhangsan",68));

        /*创建迭代器*/
        Iterator it = ts.iterator();

        /*利用迭代器取出TreeSet中的元素*/
        while(it.hasNext()){
            TreeSetPersonAge p = (TreeSetPersonAge)it.next();
            System.out.println(p.getName()+",  "+p.getAge());
        }   

    }

}

结果为:

zhangsan,  28
ehangsan,  38
rangsan,  48
thangsan,  58
fhangsan,  68

泛型:

1:将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题。
2:避免了强制转换的麻烦。

泛型什么时候用?
当操作数的引用数据类型不确定的时候

泛型是什么?
泛型其实就是一个用于接收集体引用数据类的参数范围

注意:
1.在程序中,只要用到了带<>的类或者接口,就要明确传入的具体引用数据类型,在java提供的中,有的已明确,有的未明确。

2.泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全

3.运行时,会将泛型去掉,生成的calss文件中是不带泛型的,这个称为:泛型的擦除
(为什么擦除呢?因为为了兼容运行的类加载器)

4.泛型的补偿:在运行时,通过获取元素的类型进行转换动作,不用使用者再强制转换。

5.因为静态是不需要定义对象的,所以,当方法静态时,不能访问类上定义的泛型。如果静态方法使用泛型,那么只能将泛型定义在方法上

泛型可以定义在:类上,方法上,接口上。

泛型中的通配符:可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。

泛型限定:
上限:?extends E:可以接收E类型或者E的子类型对象。
下限:?super E:可以接收E类型或者E的父类型对象。

上限什么时候用:往集合中添加元素时,既可以添加E类型对象,又可以添加E的子类型对象。为什么?因为取的时候,E类型既可以接收E类对象,又可以接收E的子类型对象。

下限什么时候用:当从集合中获取元素进行操作的时候,可以用当前元素的类型接收,也可以用当前元素的父类型接收。


使用权限:  <?>     >    <? extends class>  >    < class>

使用集合的技巧:
看到Array就是数组结构,有角标,查询速度很快。
看到link就是链表结构:增删速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();
看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。
看到tree就是二叉树,就要想到排序,就想要用到比较。
比较的两种方式:
一个是Comparable:覆盖compareTo方法;
一个是Comparator:覆盖compare方法。
LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。

集合什么时候用?
当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。

保证唯一,就用Set。不保证唯一,就用List。

Map集合
Map与Collection的不同:
Map一次存一对元素,Collection一次存一个元素;
Map是双列集合,Collection是单列集合;

注意:Map集合中存储的就是键值对,Map集合中必须保证键的唯一性

Map集合常用方法:
1.添加
put(key,value):当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。
void putAll(Map);
2.删除
void clear():清空
value remove(key) :删除指定键。
3.判断。
boolean isEmpty():
boolean containsKey(key):是否包含key
boolean containsValue(value) :是否包含value
4.取出
int size():返回长度
value get(key) :通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的

Map集合的重点方法keySet()方法:
原理:通过keySet方法获取Map中所有键,所在的Set集合,再通过Set集合的迭代器获取到每一个键,再对每一个键通过Map集合中的get方法获取其对于的值。

Map集合keySet集合示例:

public class MapKeySetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /*创建Map集合的实现类KeySetjihe*/
        HashMap<Integer,String> map = new HashMap<Integer,String>();


        /*往集合中添加元素*/
        map.put(1, "wangcai");
        map.put(2, "xiaoqing");
        map.put(3,"hahah");
        map.put(4, "xixi");

        /*通过Map集合的实现类集合HashMap集合中的KeySet()方法,获取HashMap集合中所有键,所在
         * 的Set()集合,再通过Set()集合中的Iterator()获取到每一个键,再对每一个键获取其对应的值*/
        Set<Integer> s = map.keySet();

        /*调用Set集合中的itrator()方法,利用迭代器输出集合中的键和值*/
        Iterator<Integer> it = s.iterator();

        /*通过迭代器输出集合中的元素*/
        while(it.hasNext()){
            Integer key = it.next();
            System.out.println("学号:"+key+",  姓名:"+map.get(key));
        }

    }

}

结果为:

学号:1,  姓名:wangcai
学号:2,  姓名:xiaoqing
学号:3,  姓名:hahah
学号:4,  姓名:xixi

Map集合的重点方法entrySet()方法:
entrySet()方法将键和值得银蛇关系最为对象存储到了Set集合中,而对象就要有类型,映射关系的类型就是Map.Enty

原理:通过entrySet()方法,获取Map集合中所有的键值映射关系所在的Set集合,再通过Set集合的迭代器,获取到每一个键和值得映射关系,再对每一个键和值的映射关系通过Map.Enty对象的getKey()、getValue()获取其中的键和值

Map集合entrySet示例:

public class MapEnTrySetDemo {

    public static void main(String[] args) {
        /*创建一个Map集合 的实现类集合HashMap集合*/
        HashMap<Integer,String> map = new LinkedHashMap<Integer,String>();


        /*在集合中添加元素*/
        map.put(1, "wangcai");
        map.put(2, "xiaoqing");
        map.put(3,"hahah");
        map.put(4, "xixi");

        /*引用HashMap集合中的entrySet()方法将,获取HashMap()集合中所有键值关系映射所在的
         * Set()集合*/
        Set<Map.Entry<Integer,String>> entry = map.entrySet();


        /*通过Set()集合中的Iterator()(迭代器)*/
        Iterator<Map.Entry<Integer,String>> it  = entry.iterator();

        /*,再通过Iterator(迭代器)获取到每一个键值映射关系,引用Map.EntrySet(K,v)中的
         * 方法将其元素输出*/
        while(it.hasNext()){
            Map.Entry<Integer, String> me = it.next();
            Integer key = me.getKey();
            String Value = me.getValue();
            System.out.println(key+", "+Value);
        }
    }

结果为:

1, wangcai
2, xiaoqing
3, hahah
4, xixi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值