天天看点

黑马程序员——黑马学习日志之十 集合(一)

------- android培训、java培训、期待与您交流! ----------

黑马学习日志之十 集合(一)

1 集合

集合就是一种容器,用来存放对象。

集合类的出现:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的  操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

集合的特点:只用于存储对象,集合长度可变,可以存储不同类型的对象。

集合和数组的区别:集合和数组都是容器。

                  数组虽然也可以存储对象,但长度是固定的,可以存储基本数据类型

                  集合长度是可变的,集合只能存储对象。

                  在实际使用中,如果长度固定,建议使用数组;如果长度不固定,建议使用集合。

2 集合框架

JDK为我们提供了一套完整的容器类库,这些类统称为集合类,它们都位于java.util包中。

整个集合类按照存储结构被分为单列集合和双列集合,单列集合的的根接口是Collection,双列集合的根接口是Map集合。在Collection接口中主要有两个子接口,分别是List和Set。Map接口的主要子接口有HashMap和TreeMap。

黑马程序员——黑马学习日志之十 集合(一)

3 Collection

  根接口:  Collection

  子接口:    丨—— List  可重复, 有存储顺序,有索引 

               丨—— Set   元素无序 不可重复

由于Collection是个接口,所以它没有构造方法,演示它的基本方法,只能通过其子类来验证。如ArrayList

方法实例:

class  CollectionDemo

{

public static void main(String[] args) 

{

method_get();

}

public static void method_get()

{

ArrayList al = new ArrayList();

//1,添加元素。add(Object obj);

al.add("java01");

al.add("java03");

al.add("java04");

sop(al);

}

public static void method_2()

{

ArrayList al1 = new ArrayList();

al1.add("java01");

al1.add("java02");

al1.add("java03");

al1.add("java04");

ArrayList al2 = new ArrayList();

al2.add("java03");

al2.add("java04");

al2.add("java05");

al2.add("java06");

al1.retainAll(al2); //去交集,al1中只会保留和al2中相同的元素。

al1.removeAll(al2);

sop("al1:"+al1);

sop("al2:"+al2);

}

public static void base_method()

{

//创建一个集合容器。使用Collection接口的子类。ArrayList

ArrayList al = new ArrayList();

//1,添加元素。

al.add("java01");//add(Object obj);

al.add("java02");

al.add("java03");

al.add("java04");

//打印原集合。

sop("原集合:"+al);

//3,删除元素。

al.remove("java02");

al.clear();//清空集合。

//4,判断元素。

sop("java03是否存在:"+al.contains("java03"));

sop("集合是否为空?"+al.isEmpty());

//5,获取个数。集合长度。

sop("size:"+al.size());

//打印改变后的集合。

sop(al);

}

public static void sop(Object obj)

{

System.out.println(obj);

}

}

注意:1,add方法的参数类型是Object。以便于接收任意类型对象。

      2,集合中存储的都是对象的引用(地址)

4 迭代器

什么是迭代器呢?

迭代器就是集合取出元素的方式。取出方式定义在集合内部,这样取出方式可以直接访问集合内容元素,那么取出方式就被定义成了内部类。

每一个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容判断和取出,那么可以将共性取出。

这些内部类都符合一个规则,就是Iterator.获取集合的取出对象,通过一个对外提供的方法iterator。

迭代器是取出方式,会直接访问集合中的元素。所以将迭代器通过内部类的形式来进行描述。通过容器的iterator()方法获取该内部类的对象。

如同抓娃娃游戏机中的夹子,夹子是迭代器,取出方式被定义在容器内部,夹子的实现方式不同,但封装在内部。

例子:

class  CollectionDemo

{

public static void main(String[] args) 

{

method_get();

}

public static void method_get()

{

ArrayList al = new ArrayList();

//添加元素。

al.add("java01");//add(Object obj);

al.add("java02");

al.add("java03");

al.add("java04");

Iterator it = al.iterator();//获取迭代器,用于取出集合中的元素。

while(it.hasNext())

{

sop(it.next());

}

// 迭代的另一种用法

for(Iterator it = al.iterator(); it.hasNext() ; )

{

sop(it.next());

}

}

public static void sop(Object obj)

{

System.out.println(obj);

}

}

5 List集合

List集合是Collection的一个子接口,继承了Collection中的方法。

List集合:元素有序,可重复,该集合体系有索引

List子类:Vector:底层是数组数据结构,线程同步,但增删查询速度慢,被ArrayList替代。

          ArrayList:底层是数组数据结构,线程不同步,查询速度快。默认容量为10

          LinkedList:底层使用链表数据结构,增删速度快

List集合的特有方法:凡是可以操作角标的方法,都是该体系特有方式。

add(int i,Object obj):在指定位置添加元素

addAll(int I,Collection):在指定位置添加一堆的元素

get  使用size和get方法可以遍历集合中的元素

int indexOf(Object o):返回此列表中第一次出现的指定元素的索引,如果此列表中不包    含该元素,则返回-1

int lastIndexOf(Object o):返回此列表中最后出现的指定元素的索引:如果列表中不包    含此元素,则返回-1;

List subList(int fromIndex, int toIndex):返回列表中指定的fromIndex和toIndex之间的           部分的集合。

boolean add(E e):向list里添加元素

void add(index,E e):在index索引位插入元素

boolean remove(E e):删除元素,有这个值就返回真,没有这个值就返回假

Object remove(int index):根据索引位(角标)删除,会把删除的元素返回

E set(int index, E element):对索引位置的元素进行修改。会返回你传入的元素.

E get(int index):通过索引位(角标)获取到对应的元素

List subList(int fromIndex, int toIndex):根据指定的头尾角标获取子列表

例子:

import java.util.*;

class ListDemo 

{

public static void sop(Object obj)

{

System.out.println(obj);

}

public static void method()

{

ArrayList al = new ArrayList();

//添加元素

al.add("java01");

al.add("java02");

al.add("java03");

sop("原集合是:"+al);

//在指定位置添加元素。

al.add(1,"java09");

//删除指定位置的元素。

//al.remove(2);

//修改元素。

//al.set(2,"java007");

//通过角标获取元素。

sop("get(1):"+al.get(1));

sop(al);

//获取所有元素。

for(int x=0; x<al.size(); x++)

{

System.out.println("al("+x+")="+al.get(x));

Iterator it = al.iterator();

while(it.hasNext())

{

sop("next:"+it.next());

}

//通过indexOf获取对象的位置。

sop("index="+al.indexOf("java02"));

List sub = al.subList(1,3);

sop("sub="+sub);

}

public static void main(String[] args) 

{

 method();

}

}

6 ListIterator

ListIterator是List集合特有的迭代器,ListIterator是Iterator的子接口。

在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生并发修改异常(ConcurrentModificationException)。

所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作如果想要其他的操作 如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取。

例子:

public static void main(String [] args){

     ArrayList al = new ArrayList();

   //添加元素

   al.add("java01");

   al.add("java02");

   al.add("java03");

   al.add("java04");

   sop(al);

        //迭代器获取所有元素

   Iterator it = al.iterator(); 

   while (it.hasNext())

   {

    Object obj = it.next();

    if (obj.equals("java02"))

   {

    //al.add("java08");//并发同步异常。迭代器和集合操作不能同    时来执行 

it.remove();  //iterator只能对元素进行判断取出删除操作

  }

   sop("obj"+obj);

 }

  sop(al);

}

Iterator例子:

public static void main(String[] args) {

List li = new ArrayList();

li.add("a");

li.add("A");

li.add("b");

li.add("c");

li.add("d");

ListIterator lit = list.listIterator();

while(li.hasNext())

  {

    Object obj =li.next();

     if(obj.equals("A"))

    {

     li.add("e");//在java02后添加Java09

      li.set("a2");//将java02改为Java006

    }

 }

System.out.println("----------------------------");

while(lit.hasPrevious()) { //倒序遍历

System.out.println(lit.previous());

}

7 vector

Vector是List集合的一个子类。底层是数组数据结构,线程同步,但增删查询速度慢,被ArrayList替代。

Vector中提供了一个独特的取出方式,就是枚举Enumeration。此接口Enumeration的功能与 Iterator 接口的功能是重复的Enumeration的名称和方法的名称过程,书写很麻烦。所以被Iterator所取代.

例子:

class VectorDemo{

public static void main(String[] args) {

Vector v = new Vector();

v.addElement("abc1");

v.addElement("abc2");

v.addElement("abc3");

Enumeration en = v.elements();

while(en.hasMoreElements()){

System.out.println(en.nextElement());

}

}

}

8 LinkedList

 LinkedList是List的子类,底层是链表数据结构,增删快,查询慢。

 LinkedList的特有方法: 

添加

void addFirst(Object o): 把元素添加到第一个位置

void addLast(Object o): 把元素添加到最末的位置

获取

Object getFirst(): 获取LinkedList中的第一个元素

Object getLast(): 获取LinkedList中的最后一个元素

Peakfirst()  peaklast() 也是获取元素

对于get的方法,如果集合中没有元素,就会抛出异常,

对于peak的方法,如果集合中没有元素,就会出现null

删除(通过指针被删除的元素都会返回被删除的元素)

  removeLast()   removeFirst():  如果集合中没有元素,返回异常

  pollLast()      pollFirst():如果集合元素没有,该方法不会抛异常,null

例子:

import java.util.*;

class Duilie

{

private LinkedList list;

Duilie()

{

list = new LinkedList();

}

public void myAdd(Object obj)

{

list.addFirst(obj);

}

public Object myGet()

{

return list.removeFirst();.//先进后出

  //return list.removeLast();  //先进先出

}

public boolean isNull()

{

return list.isEmpty();

}

public static void sop(Object obj)

{

System.out.println(obj);

}

}

class LinkedListTest 

{

public static void main(String[] args) 

{

Duilie dl =new Duilie();

dl.myAdd("java01");

dl.myAdd("java02");

dl.myAdd("java03");

dl.myAdd("java04");

while(!dl.isNull())

{

Duilie.sop(dl.myGet());

}

}

}

9 Set集合

set是根接口collection的一个子接口,继承了collection的方法。

set集合:元素无序(存入和取出顺序不一致),不可重复,没有索引。

Set子类:

HashSet:底层是哈希表数据结构,线程非同步。

TreeSet:底层是二叉树数据结构,可以对set集合中的元素进行排序

10 HashSet

HashSet是set集合的子类,底层是哈希表数据结构。其集合中没有重复元素。

保证元素唯一:哈希表存储结构,其实就是哈希值的存储,每个对象都有一个哈希值通过equals方法和hashCode方法来保证元素的唯一性。hash算法时计算元素的地址值的,它在对对象的存储的时候是先调用hashCode方法,然后再执行重写equals方法。

HashSet集合保证元素唯一性,依赖的是元素的hashCode方法和euqals方法。

当元素的哈希值不同时,元素都有自己的独立位置。不需要在判断元素的equals方法,

当元素的哈希值相同时,这时元素在哈希表中位置相同,这时就需要在判断一次元素的内容是否相同。就需要调用元素的equals方法进行一次比较。如果equals返回是true。那么视为两个元素为重复元素。只储存一个。如果返回是false,那么这两个元素不是重复元素,会存储在同一个哈希值上。

 HashSet原理

我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低。

哈希算法提高了去重复的效率, 降低了使用equals()方法的次数。当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是 否有哈希值相同的对象,如果没有哈希值相同的对象就直接存入集合;如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存。

注意:

类中必须重写hashCode()和equals()方法

hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)

equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储

例子:

class HashSetTest 

{

public static void sop(Object obj)

{

System.out.println(obj);

}

public static void main(String[] args) 

{

HashSet hs = new HashSet();

hs.add(new Person("a1",11));

hs.add(new Person("a2",12));

hs.add(new Person("a3",13));

hs.add(new Person("a2",12));

hs.add(new Person("a4",14));

Iterator it = hs.iterator();

while(it.hasNext())

{

Person p = (Person)it.next();

sop(p.getName()+"::"+p.getAge());

}

}

}

class Person

{

private String name;

private int age;

Person(String name,int age)

{

this.name = name;

this.age = age;

}

public int hashCode()

{

System.out.println(this.name+"....hashCode");

return name.hashCode()+age*37;

}

public boolean equals(Object obj)

{

if(!(obj instanceof Person))

return false;

Person p = (Person)obj;

System.out.println(this.name+"...equals.."+p.name);

return this.name.equals(p.name) && this.age == p.age;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

}            

11 TreeSet

TreeSet是set集合的子类,底层是二叉树数据结构可以对set集合中的元素进行排序,默认自然排序。

保证数据唯一性:

compareTo方法return 0为同一个元素return 1 放元素二叉树右边 return -1放元素左边

TreeSet排序方式:

TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法,这种方式也成为元素的自然顺序 或者叫做默认排序。

例子:

import java.util.*;

class Student implements Comparable

{

private String name; 

private int age;

Student(String name,int age)

{

this.name = name;

this.age = age;

}

public int compareTo(Object obj)   

{                  

if(!(obj instanceof Student))

throw new RuntimeException("对象类型错误");

Student stu = (Student)obj;

if(this.age > stu.age)

return 1;

if(this.age == stu.age)              //主要特征比较不出来,用次要特征。

return this.name.compareTo(stu.name); //String类也有compareTo方法。

return -1;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

}

class TreeSetTest

{

public static void main(String[] args) 

{

TreeSet ts = new TreeSet();

ts.add(new Student("sun01",22));

ts.add(new Student("sun02",21));

ts.add(new Student("sun04",21));

ts.add(new Student("sun05",20));

Iterator it = ts.iterator();

while(it.hasNext())

{

               Student s = (Student)it.next();

   sop(s.getName()+"======"+s.getAge());

}

}

public static void sop(Object obj)

{

System.out.println(obj);

}

}

TreeSet排序的第二种方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时需要让集合自身具备比较性(好比集合里面有个刻度板)。在集合的初始化时,就有了比较方式 此时要参阅集合的构造方法。

例子:

import java.util.*;

class Student 

{

private String name;

private int age;

Student(String name,int age)

{

this.name = name;

this.age = age;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

}

class TreeSetTest2 

{

public static void main(String[] args) 

{

TreeSet ts = new TreeSet(new MyComparator());

ts.add(new Student("sun001",15));

ts.add(new Student("sun002",12));

ts.add(new Student("sun006",10));

ts.add(new Student("sun002",19));

ts.add(new Student("sun004",11));

Iterator it = ts.iterator();

while(it.hasNext())

{

Student stu = (Student)it.next();

sop(stu.getName()+"====="+stu.getAge());

}

}

public static void sop(Object obj)

{

System.out.println(obj);

}

}

//TreeSet的第二种排序方式。 集合自身具备比较性。

class MyComparator implements Comparator

{

public int compare(Object o1,Object o2)

{

Student s1 = (Student)o1;

Student s2 = (Student)o2;

int num = s1.getName().compareTo(s2.getName());

if(num == 0)

{

if(s1.getAge()>s2.getAge())

return 1;

if(s1.getAge()<s2.getAge())

return -1;

return 0;

}

return num;

}

}

12 泛型

  集合在初始化时没有定义数据类型,潜在安全隐患,出现了泛型。

泛型:jdk1.5版本后出现的新特性。用于解决安全问题,是一个安全机制。

泛型好处:(1)运行期间的classCastException转移到编译时期,方便程序员解决问题,让 运行期问题减少,较安全。

           (2)避免强制转换麻烦。

泛型格式:通过< >来定义要操作的引用数据类型。其实< >就是来接收数据类型的。

例子:

import java.util.*;

class GenericDemo 

{

    public static void main(String[] args) 

{

 ArrayList<String> al1 = new ArrayList<String>();

 al1.add("sss");

 al1.add("sqq");

 al1.add("saa");

 sop(al1);

 ArrayList<Integer> al2 = new ArrayList<Integer>();

 al2.add(1);

 al2.add(2);

 al2.add(3);

sop(al2);

}

public static<T> void sop(ArrayList<T> al) //T代表一个明确类型

{

Iterator<T> it = al.iterator();

while(it.hasNext())

{

T t = it.next();

System.out.println(t.length());

}

}

}

泛型类

什么时候定义泛型类:当类中要操作的引用数据类型不确定的时候。早期定义Object 来完成扩展,现在定义泛型来完成扩展。

例子:

class Worker

{

}

class Student

{

}

class Utils<QQ>

{

 private QQ q;

 public void setObject(QQ q){

   this.q = q;

 }

 public QQ getObject(){

   return q;

 }

}

class GenerinDemo3

{

  public static void main(String [] args){

   Utils<Worker>  u= new Utils<Worker>();

   u.setObject(new Worder());

    Worker w = u.getObject();

     }

}

泛型方法:

泛型类定义的泛型,在整个类中有效。泛型类的对象明确要操作的具体类型后,所有要操做的类型就已经固定了。

为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。

例子:

class Demo

{

 public <T> void show(T t){

    System.out.println("show:"+t);

  }

 public <Q> void print(Q q){//该泛型只在这个方法中有效

   System.out.println("print:"+t);

 }

}

class GenericDemo4

{

 public static void main(String [] args){

  Demo d = new Demo();

  d.show(new Integer(4));

    d.print("hehe");

  d.show("hahah");

 }

静态泛型方法:

静态方法不可以访问类上定义的泛型

如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上

例子:

class Demo1<T>

{

  public  void show(T t){

   System.out.println("show:"+t);

 }

     public <Q> void print(Q q){

    System.out.println("print:"+q);

 }

 public  static <W> void method(W t){

   System.out.println("method::"+t);

  }

}

public class GenericDemo5

{

  public static void main(String [] args){

    Demo1<String> d1 = new Demo1<String>();

    d1.print(5); 

d1.show("hahah");

   Demo1.method("hehehehe");

 }

   }

泛型限定

? 通配符,也可以理解为占位符。

?extends E:可以接受E类或者E的子类型 上限

?super E:可以接受E类型或者E的父类型 下限

例子:

import java.util.*;

class Person

{

private String name;

Person(String name)

{

this.name = name;

}

public String getName()

{

return name;

}

}

class Student extends Person

{

private String name;

Student(String name)

{

super(name);

}

}

class GenericTest 

{

public static void main(String[] args) 

{

ArrayList<Person> al = new ArrayList<Person>();

al.add(new Person("sun01"));

al.add(new Person("sun02"));

al.add(new Person("sun03"));

sop(al);

ArrayList<Student> al1 = new ArrayList<Student>();

al1.add(new Student("sss01"));

al1.add(new Student("sss02"));

al1.add(new Student("sss03"));

sop(al1);

}

public static void sop(ArrayList<? extends Person> al)

{

Iterator<? extends Person> it = al.iterator();

while(it.hasNext())

{

System.out.println(it.next().getName());

}

}

}

------- android培训、java培训、期待与您交流! ----------