黑马程序员_毕向东JAVA基础_集合(2)Collection&&List&&Set&&泛型

时间:2023-02-17 09:25:49
------- android培训java培训、期待与您交流! ----------

  集合

1.为什么会出现集合类?

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

      2.数组和集合类同是容器,有何不同?      

         数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。

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

      4.集合框架的构成及分类。

                        黑马程序员_毕向东JAVA基础_集合(2)Collection&&List&&Set&&泛型

     5.为什么会出现这么多容器呢?

       因为每一个容器对数据的存储方式都有不同。这个存储的方式称之为:数据结构。

       集合中存放的不可能是对象实体,存放的都是地址。

     6.什么是迭代器呢?其实就是集合的取出元素的方式。

        就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内容的元素。那么取出方式就被定义成了内部类。而每个容器的数据结构不同,所以取           出的动作细节也不一样。但是都有共性内容判断和取出。那么可以将写共性抽取。那么这些内部类都符合一个规则。该规则就是Iterator。如何获取集合的取           出对象?通过一个对外提供的方法。iterator();

                 黑马程序员_毕向东JAVA基础_集合(2)Collection&&List&&Set&&泛型

     7.常见子接口:

        collection

            |------List:元素是有序的,元素可以重复。因为该集合体系有索引。由于底层数据结构不同,有三个子类。

                 |--ArrayList:底层数据结构使用的是数组结构。特点:查询速度快,但增删稍慢。线程不同步(建议使用)。

                 |--LinkedList:底层的数据结构是链表数据结构。特点:增删的速度快,查询稍慢。

                 |--Vector:底层是数组数据结构。线程同步。

                                      ArrayList默认长度是10,超出长度时,50%延长。

                                      Vector默认长度是10,超出长度时,100%延长。

           |------Set:元素是无序的,元素不可以重复。该集合体系无索引。Set集合的功能和Collection是一致的。

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

                |--TreeSet:可以对Set集合中的元素进行排序。按照字母的自然顺序排序。底层数据结构是二叉树,保证元素唯一性的依据是compareTo方法return 0。


     8.collection集合的功能,代码示例。

      代码(一)

import java.util.*;
/*
1.add方法的参数类型是Object,以便于接受任意的类型对象。
2.集合中存储的都是对象的引用(地址)。

*/
class CollectionDemo
{
public static void main(String[] args)
{
//创建一个集合容器,使用Collection接口的子类,ArrayList
ArrayList a1 = new ArrayList();
//1.添加元素
a1.add("java01");
a1.add("java02");
a1.add("java03");
a1.add("java04");
//打印集合
//sop("原集合:"+a1);//直接将对象封装在中括号中,打印出来

//2.获取个数,集合长度。
//sop("size:"+a1.size());
//3.删除元素
//a1.remove("java02");
sop(a1);
//4.清空集合
//a1.clear();
//5.判断元素。
sop("java03是否存在:"+a1.contains("java03"));
sop("集合是否为空?"+a1.isEmpty());
}

public static void sop(Object obj)
{
System.out.println(obj);
}
}

    代码(二)

import java.util.*;
class CollectionDemo2
{
public static void main(String[] args)
{
//method_1();
method_get();
}
//取交集。
public static void method_1()
{
ArrayList a1 = new ArrayList();
a1.add("java01");
a1.add("java02");
a1.add("java03");
a1.add("java04");

ArrayList a2 = new ArrayList();
a2.add("java03");
a2.add("java04");
a2.add("java05");
a2.add("java06");

//a1.retainAll(a2);//取交集,a1中只会保留和a2中相同的元素,
//若没有交集,存空。
a1.removeAll(a2);//将相同的元素删除。a1中只保存不同。
sop("a1="+a1);
sop("a2="+a2);
}
//取出元素
public static void method_get()
{
//添加元素
ArrayList a1 = new ArrayList();
a1.add("java01");
a1.add("java02");
a1.add("java03");
a1.add("java04");
/*Iterator it = a1.iterator();//获取迭代器,用于取出集合中的元素。迭代结束,it还在内存中。
while(it.hasNext())
{
sop(it.next());
}*/
for (Iterator it = a1.iterator(); it.hasNext() ; )//迭代结束,释放内存it
sop(it.next());
}



}

public static void sop(Object obj)
{
System.out.println(obj);
}
}

    9.List常见方法

      特有方法:凡是可以操作角标的方法都是该体系特有的的方法。

                   增:

                            add(index,element)//在指定位置添加元素。

                            addAll(index,Collection)//将指定 collection 中的所有元素都插入到列表中的指定位置

                   删:

                            remove(index)//删除指定位置的元素。

                   改:

                            set(index,element)//修改指定位置的元素

                   查:

                            get(index)//返回列表中指定位置的元素

                            subList(from,to)//返回列表中指定的from(包括 )和 to(不包括)之间的部分视图。

                            listIterator()// 返回按适当顺序在列表的元素上进行迭代的迭代器。

         List集合特有的迭代器.ListIterators是Iterator的子接口。

         在迭代时,不可以通过集合对象的方法操作集合中的元素。

         因为会发生ConcurrentModificationException异常。

         所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。

         只能对元素进行判读,取出,删除的操作,

         如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。

         该接口只能通过List集合的listIterator方法获取。

          ArrayList代码示例:

/*
将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
比如:存入对象。同姓名同年龄,视为同一个人。为重复元素

思路:
1.对人描述,将数据封装在人对象。
2.定义容器,将人存入。
3.取出。

List集合判断元素是否相同,依据的是元素的equals方法。
*/

import java.util.*;

class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public boolean equals(Object obj)//重写equals方法。
{

if (!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;//类型转换。
System.out.println(this.name+"::"+ p.name);
return this.name.equals(p.name) && this.age == p.age;
}
}
class ArrayListTest2
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();

al.add(new Person("lisi01",20));//al.add(Object obj)//Oject obj=new Person()类型提升
al.add(new Person("lisi01",20));
al.add(new Person("lisi02",40));
al.add(new Person("lisi02",40));
al.add(new Person("lisi03",35));
al.add(new Person("lisi03",35));

al = singleElement(al);//调用函数,去除相同元素,

Iterator it = al.iterator();//定义的迭代器
while (it.hasNext())
{
/*Object obj = it.next();//
Person p = (Person)obj;//类型转换。*/
Person p = (Person)it.next();
sop(p.getName()+"......"+p.getAge());
}

}
public static ArrayList singleElement(ArrayList al)
{
//定义一个临时容器
ArrayList newAl = new ArrayList();
//定义迭代器
Iterator it = al.iterator();
while (it.hasNext())
{
//定义一个obj对象
Object obj = it.next();
//当临时容器newAl不包含obj对象时,向临时容器传入obj对象。
if(!newAl.contains(obj))//调用contains,contains调用equals,比较对象。
newAl.add(obj);
}
return newAl;

}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
    

    10.LinkedList结构:

         LinkedList特有方法:

         addFirst():

         addLast():

         getFirst():

         getLast():获取元素,但不删除元素。如果集合中没有元素会出现NoSuchElementException。

         removeFisrt():

         removerLast():获取元素,删除元素。如果集合中没有元素会出现NoSuchElementException。

        在JDK1.6之后,出现了替代方法。

         offerFirst();

         offerLast();

         peekFirst();

         peekLast();获取元素,但不删除元素,如果集合中没有元素,会返回null。

         pollFirst();

         pollLast();获取元素,但是元素删除,如果集合中没有元素,会返回null。


    LinkedList代码示例

/*
使用LinkedList模拟一个堆栈或者队列数据结构。

堆栈:先进后出。
队列:先进先出。
*/
import java.util.*;
class DuiLie
{
private LinkedList link;
DuiLie()
{
link = new LinkedList();
}
public void myAdd(Object obj)
{
link.offerFirst(obj);
}
public Object get_1()
{
return link.pollFirst();
}
public Object get_2()
{
return link.pollLast();
}
public boolean isNull()
{
return link.isEmpty();
}
}

class LinkedTextDemo1
{
public static void main(String[] args)
{
DuiLie d = new DuiLie();
d.myAdd("java01");
d.myAdd("java02");
d.myAdd("java03");
d.myAdd("java04");

while (!d.isNull())
{
sop(d.get_1());// 模拟堆栈,先进后出
//sop(d.get_2())//模拟队列,先进先出。
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
    11.Vector取出方式:迭代器,遍历(for循环),索引,枚举。枚举是Vector特有的方式。

发现枚举和迭代器很像,其实枚举和迭代时一样的。因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。

import java.util.*;
class VectorDemo
{
public static void main(String[] args)
{
Vector v = new Vector();
v.add("Java01");
v.add("Java02");
v.add("Java03");
v.add("Java04");

Enumeration en = v.elements();
while (en.hasMoreElements())
{
System.out.println(en.nextElement());
}
}
}

    12.Set集合

     哈希表添加元素的返回值是boolean型,因为要判断地址和对象是否相同

    (1) HashSet如何保证元素的唯一性呢?是通过元素的两个方法,hashCode和equals来完成。

     如果元素的HashCode值相同,才会判断equals是否为true。如果元素的HashCode值不同,不会调用equals。

     注意:对于判断元素是否存在,以及删除等操作,依赖元素的HashCode和equals方法。

     (2)TreeSet中按照排序判断用了compareTo()方法。

      记住,在排序时,当主要条件相同时,一定要判断一下次要条件。

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

     TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。在集合初始化时就有了比较方式。

      定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

      代码示例(HashSet):

import java.util.*;
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
public int hashCode()//判断哈希地址
{
System.out.println(this.name+"...hashCode");
return name.hashCode()+age;
}
public boolean equals(Object obj)//判断对象
{
if(!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;//类型转换
System.out.println(this.name+"...."+p.name);
return this.name.equals(p.name) && this.age == p.age;
}
}
class HashCodeTest
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("lisi01",10));
hs.add(new Person("lisi02",11));
hs.add(new Person("lisi03",12));
hs.add(new Person("lisi01",10));

Iterator it = hs.iterator();
while (it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

    代码示例(TreeSet)

/*
需求:往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。

分析:我们输入学生的对象,不具备比较性,TreeSet调用compareTo方法对存储的数据进行排序。
我们存入的数据是一个对象,所以要重写compareTo方法,
让其可以处理对象。
*/

import java.util.*;

class Person implements Comparable//该接口强制让人具备比较性
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
public int compareTo(Object obj)
{

if (!(obj instanceof Person))
throw new RuntimeException("不是人的对象");
Person p = (Person)obj;
if(this.age > p.age)
return 1;
if(this.age == p.age)
return this.name.compareTo(p.name);//年龄相同时,比较姓名。
return -1;

}
}
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Person("lisi01",19));
ts.add(new Person("lisi02",20));
ts.add(new Person("lisi03",21));
ts.add(new Person("lisi02",19));

Iterator it = ts.iterator();
while (it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}


}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

/*
当元素自身不具备比较性,或者具备的比较性不是所需要的,
这是需要让容器自身具备比较性。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

当两种排序都存在时,以比较器为主。

定义一个类,实现Comparator接口,覆盖compare方法。
*/

import java.util.*;

class Person implements Comparable//该接口强制让人具备比较性
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
public int compareTo(Object obj)
{

if (!(obj instanceof Person))
throw new RuntimeException("不是人的对象");
Person p = (Person)obj;
if(this.age > p.age)
return 1;
if(this.age == p.age)
return this.name.compareTo(p.name);//年龄相同时,比较姓名。
return -1;

}
}

class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new MyCompare());
ts.add(new Person("lisi01",19));
ts.add(new Person("lisi02",20));
ts.add(new Person("lisi03",21));
ts.add(new Person("lisi02",19));

Iterator it = ts.iterator();
while (it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}

}
public static void sop(Object obj)
{
System.out.println(obj);
}
}

class MyCompare implements Comparator//定义一个比较器的类。
{
public int compare(Object o1,Object o2)
{
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int num = p1.getName().compareTo(p2.getName());
if (num == 0)
{
//将年龄封装为对象,进行比较。
return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
/*if (p1.getAge() > p2.getAge())
return 1;
if (p1.getAge() < p2.getAge())
return -1;
return 0;*/

}
return num;
}

}

13.泛型。

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

         好处:

         1. 将运行时出现问题ClassCastException,转移到了编译时期。方便于程序员解决问题。让运行时期问题减少,安全。

         2. 避免了强制转换。

 

         泛型的格式:通过<>来定义要操作的引用数据类型。

         在使用java提供的对象时,什么时候写泛型呢?

         通常在集合框架中很常见,只要见到<>就要定义泛型。

         其实<>就是用来接收类型的。当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。


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

        泛型方法:因为泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可         以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。(泛型放在返回值类型前面,修饰符后面。)

        泛型定义在接口上:

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

       泛型限定:用于泛型扩展用的。

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

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