黑马程序员——Java基础---集合1
来源:互联网 发布:c语言input是什么意思 编辑:程序博客网 时间:2024/06/16 08:45
-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
集合框架
为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
Collection
Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
常见操作
1、添加元素
add(Objectobj); //add方法的参数类型是Object。以便于接收任意类型对象。
/*
* 接口方法
* add方法,将元素添加到集合
* 存储对象到集合
* add(Object o)
*/
public static void method(){
//Collection接口,指向自己的实现类对象ArrayList
Collection col = new ArrayList();
//调用接口Collection方法add,存储对象,add方法运行起来可以实现类重写
col.add("abc");
col.add(123);
col.add(false);
//输出集合,看到的是集合中存储的元素
//不等于获取集合中的元素
//输出集合,方便观看而已,不称为获取,获取需要使用迭代器
System.out.println(col);
}
2、清空集合
/*
* 接口方法
* clear() 清空集合中的所有元素
* 集合容器可以继续使用
*/
public static void method_1(){
Collection col = new ArrayList();
col.add("abc1");
col.add("abc2");
col.add("abc3");
col.add("abc4");
System.out.println("原始集合 "+col);
//调用接口方法clear()
col.clear();
System.out.println("清空后集合 "+col);
}
3、删除元素
remove(Objectobj);
/*
* 接口方法
* boolean remove(Object obj)
* 删除指定的元素,删除成功返回true
* 多个,元素一样,删除第一个元素
*/
public static void method_4(){
Collection col = new ArrayList();
col.add("abc1");
col.add("abc3");
col.add("abc2");
col.add("abc3");
col.add("abc4");
//调用接口方法remove移除,abc2
boolean b = col.remove("abc3");
System.out.println(b);
System.out.println(col);
}
4、判断元素
contains(Objectobj);//判断是否存在obj这个元素
isEmpty();//是否为空
/*
* 接口方法
* boolean contains(Object o)
* 判断集合中是不是包含这个对象,如果包含返回true
*/
public static void method_2(){
Collection col = new ArrayList();
col.add("abc1");
col.add("abc3");
col.add("abc2");
col.add("abc3");
col.add("abc4");
//接口方法contains判断对象 "abc3"有还是没有
boolean b = col.contains("abc3");
System.out.println(b);
}
/*
* 接口方法
* boolean isEmpty()
* 判断集合中有没有元素,如果没有返回true
*/
public static void method_3(){
Collection col = new ArrayList();
//调用接口方法isEmpty,判断集合有没有元素
boolean b = col.isEmpty();
System.out.println(b);
}
5、获取个数,集合长度
size();
/*
* 接口方法
* int size()
* 返回集合中元素个数
*/
public static void method_5(){
Collection col = new ArrayList();
col.add("fh");
col.add(123);
col.add(1.1);
col.add(true);
col.add('a');
int size = col.size();
System.out.println(size);
}
Collection接口中带有All的方法
/*
* 接口方法
* boolean retainAll(Collection c)
* 参数是Collection接口类型,传递实现类对象
* 获取两个集合交集
* 返回值: 调用者集合元素没变过就是false
* 返回值: 调用者集合元素发生了变化就是true
*/
public static void method_3(){
Collection co1 = new ArrayList();
Collection co2 = new ArrayList();
//存储2个集合的中元素
co1.add(123);
co1.add(456);
co1.add(789);
co2.add("abc");
co2.add("bcd");
co2.add(123);
co2.add(456);
//调用接口方法retainAll获取两个集合交集
//co1调用方法retainAll传递co2
//将两个集合中的相同元素,保存到co1中
boolean b = co1.retainAll(co2);
System.out.println(b);
System.out.println(co1);
}
/*
* 接口方法
* boolean removeAll(Collection c)
* 参数是Collection接口类型,传递实现类对象
* 移除,两个集合中相同的元素
*/
public static void method_2(){
Collection co1 = new ArrayList();
Collection co2 = new ArrayList();
//存储2个集合的中元素
co1.add(123);
co1.add(456);
co1.add(456);
co2.add("abc");
co2.add("bcd");
co2.add(123);
co2.add(456);
//调用接口方法removeAll移除两个集合相同元素
//co1调用方法removeAll传递co2
boolean b = co1.removeAll(co2);
System.out.println(b);
System.out.println(co1);
}
/*
* 接口方法
* boolean containsAll(Collection c)
* 参数是Collection接口类型,传递实现类对象
* 判断一个集合中,是否包含另一个集合
* 判断是集合中的元素是不是包含,完全包含返回true
*/
public static void method_1(){
Collection co1 = new ArrayList();
Collection co2 = new ArrayList();
//存储2个集合的中元素
co1.add(123);
co1.add(456);
co1.add("abc");
co1.add("bcd");
co2.add("abc");
co2.add("bcd");
//调用接口方法containsAll
//co1调用方法containsAll传递co2
//判断co1中的元素,是不是完全包含co2的元素
boolean b = co1.containsAll(co2);
System.out.println(b);
}
/* 接口方法
* addAll(Collection c)
* 参数是Collection接口类型,传递实现类对象
* 将一个集合存储到另一个集合
*/
public static void method(){
//创建2个集合
Collection co1 = new ArrayList();
Collection co2 = new ArrayList();
//存储2个集合的中元素
co1.add(123);
co1.add(456);
co2.add("abc");
co2.add("bcd");
//调用接口方法addAll
//co1调用自己的方法addAll,传递co2
//将co2中的元素存储到co1中
co1.addAll(co2);
System.out.println(co1);//[123,456,abc,bcd]
// add(Object )
//co1.add(co2);
//System.out.println(co1);//[123,456,[abc,bcd]]
}
迭代器
概述
迭代器,就是获取出集合中存储元素的一种方式 (遍历)
集合顶层接口中定义iterator() 方法,整个Collection的实现类都具备
Iterator iterator()作用,返回迭代器对象,返回值是接口类型
接口是没有对象,返回接口实现类对象
Iterator接口方法
boolean hasNext() 判断集合中有没有下一个被取出的元素,如果有返回true
Object next() 获取出集合中的元素
void remove() 移除集合中的元素
迭代器的源代码实现 -- ArrayList
interface Iterator{
boolean hasNext();
Object next();
void remove();
}
interface Collection{
Iterator iterator();
}
//List extends Collection
public class ArrayList implements List{
public Iterator iterator(){
// 返回 Iterator 实现类对象
return new Itr();
}
//定义类内部类,实现接口Iterator
private class Itr implements Iterator{
//重写了Iterator接口的三个抽象方法
}
}
main(){
Collection col = new ArrayList();
Iterator it = col.iterator();
}
演示用例:
Collection col = new ArrayList();
col.add("abc1");
col.add("abc4");
col.add("abc3");
col.add("abc2");
//1. 集合方法iterator()获取迭代器对象
Iterator it = col.iterator();
//2. 循环调用hasNext方法,判断集合中有没有下一个元素
while(it.hasNext()){
//3. 调用迭代器方法next取出集合中的元素
System.out.println(it.next());
}
System.out.println("=====for循环编写方式=========");
for(Iterator it2 = col.iterator(); it2.hasNext(); ){
System.out.println(it2.next());
}
测试用例:
集合存储字符串并取出
集合存储自定义对象Student,并取出
/*
* 集合存储自定义对象
* Student对象,迭代器
* 迭代器: 一次使用迭代器,不能出现多次next 只能有1次
* 如果集合中,没有元素,继续使用next,出现没有元素被取出的异常
* NoSuchElementException
*/
public static void test_1(){
Collection col = new ArrayList();
col.add(new Student("zhangsan",20));
col.add(new Student("lisi",22));
col.add(new Student("wangwu",19));
col.add(new Student("zhaoliu",18));
col.add(new Student("huaqiangu",15));
Iterator it = col.iterator();
while(it.hasNext()){
//使用Student类的方法getName ,getAge,不在使用toString
//多态好处,无限扩展子类,弊端,调用子类父类共有内容
//Object o = new Student();
/*System.out.println(((Student)it.next()).getName()+"..."
+((Student)it.next()).getAge());发现打印结果:zhangsan...22
wangwu...18*/
//用变量,接收next的结果
Student stu =(Student) it.next();
System.out.println(stu.getName()+".."+stu.getAge());
}
}
/*
* 集合存储字符串并迭代
*/
public static void test(){
Collection col = new ArrayList();
col.add("abc1");
col.add("qqq");
col.add("www");
col.add("itcast");
Iterator it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
迭代器使用注意事项
一次循环,使用一次next
没有元素被取出的异常
迭代中,不允许使用集合的方法改变集合长度
如果改了出现了ConcurrentModificationException (并发修改异常)
演示用例:
/*
* 迭代中,使用迭代器的方法remove删除集合中的元素
*/
public static void method_1(){
Collection col = new ArrayList();
col.add("abc1");
col.add("abc2");
col.add("abc3");
Iterator it = col.iterator();
while(it.hasNext()){
Object obj = it.next();
if("abc2".equals(obj))
it.remove();
}
System.out.println(col);
}
private static void method() {
Collection col = new ArrayList();
col.add("abc1");
col.add("abc2");
col.add("abc3");
//迭代过程中,判断集合中是否包含abc2这个对象
//如果包含,添加abc22
Iterator it = col.iterator();
while(it.hasNext()){//ConcurrentModificationException
Object obj = it.next();
//判断obj是不是abc2
if("abc2".equals(obj))
col.add("abc22");
}
}
List
有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
与 set 不同,列表通常允许重复的元素。
List的特有方法
凡是可以操作角标的方法都是该体系特有的方法。
1、增
boolean add(index,element);//指定位置添加元素
/*
* List接口方法
* add(int index,Object obj)
* 将对象存储到指定的索引上
*
* IndexOutOfBoundsException -- 集合中的
* |-- ArrayIndexOutOfBoundsException -- 数组
* |-- StringIndexOutOfBoundsException -- 字符串
*/
public static void method(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
//集合对象调用方法add(int index,Object o)
//第2个索上,添加元素wasd
list.add(2, "wasd");
System.out.println(list);
}
2、删
boolean remove(index);//删除指定位置的元素
/*
* List接口方法
* Object remove(int index)
* 移除指定索引上的元素
* 返回值,返回被删除之前的元素
*/
public static void method_2(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
//调用List接口方法remove(int index)
//移除集合中的第3索引上的元素
Object obj = list.remove(3);
System.out.println(obj);
System.out.println(list);
}
3、改
set(index,element);//修改指定位置的元素。
/*
* List接口方法
* Object set(int index,Object o)
* 修改指定索引上的元素
* 返回被修改之前的元素
*/
public static void method_3(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
//调用List接口方法 set修改元素
//修改0索引上的元素,修改成itcast
Object obj = list.set(0, "itcast");
System.out.println(obj);
System.out.println(list);
}
4、查
get(index);//通过角标获取元素
/*
* List接口方法
* Object get(int index)
* 根据索引获取集合中的元素
* 对于List集合获取,2种方法
* 迭代器--通用的
* List -- size+get
*/
public static void method_1(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
//调用List接口方法get,传递索引
//获取集合第1个索引上的元素
Object o = list.get(1);
System.out.println(o);
//利用数组中的索引思想,遍历集合
for(int x = 0 ; x < list.size() ; x++){
System.out.println(list.get(x));
}
}
subList(from,to);//获取部分对象元素
/*
* List接口方法
* List subList(int begin,int end)
* 获取集合的一部分,开始索引,结束索引,包含头,不包含尾
* 返回新集合
*/
public static void method_4(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
list.add("abc5");
list.add("abc6");
System.out.println(list);
//调用List接口方法subList获取集合中的一部分,截取了集合
//String类的substring效果一致
//获取 1-5索引
List list2 = list.subList(1, 5);
System.out.println(list2);
}
常见数据结构
栈 数据先进后出
队列 数据先进先出
数组
链表 记录地址
树 分支结构,排序
哈希表 存储哈希值的数组
ListIterator
1、概述
ListIterator是List集合特有的迭代器,是Iterator的子接口。
List集合方法 listIterator()获取到ListIterator接口的实现类对象
/*
* 使用List特有迭代器,实现集合逆向遍历
* boolean hasPrevious() 等同于hasNext
* Object previous() 等同于next
*/
public static void method_1(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
//集合方法listIterator获取特有迭代器接口ListIterator实现类对象
ListIterator lit = list.listIterator();
while(lit.hasNext()){
System.out.println(lit.next());
}
//逆向遍历集合
while(lit.hasPrevious()){
System.out.println(lit.previous());
}
for(int x = list.size()-1 ; x >= 0 ; x--){
System.out.println(list.get(x));
}
}
/*
* 获取List接口特有迭代器
* 迭代器中的方法 add set
* 迭代过程中,使用迭代器方法,添加元素,修改元素
*/
public static void method(){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
//集合方法listIterator获取特有迭代器接口ListIterator实现类对象
ListIterator lit = list.listIterator();
//迭代过程中,判断如果有abc4这个元素,添加abc44
//判断有没有abc3这个元素,如果有就修改成abc300
while(lit.hasNext()){
Object o = lit.next();
if("abc3".equals(o))
lit.set("abc300");
}
System.out.println(list);
}
ArrayList
集合自身特性
ArrayList集合底层数据结构, 是数组,可变长度数组(复制方式)
集合线程不安全集合(不同步),运行速度快
默认容量10个,增长率每次50%
查询快,增删速度慢
一个实际的项目中,查询功能占总功能50%以上
//ArrayList存储自定义对象,迭代器
public static void method_1(){
ArrayList array = new ArrayList();
array.add(new Student("a",101));
array.add(new Student("b",102));
array.add(new Student("c",103));
array.add(new Student("d",104));
Iterator it = array.iterator();
while(it.hasNext()){
Student s = (Student)it.next();
System.out.println(s.getName()+".."+s.getAge());
}
}
//ArrayList集合存储字符串,迭代器
public static void method(){
ArrayList array = new ArrayList();
array.add("qwe");
array.add("asd");
array.add("zxc");
Iterator it = array.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
Vector类
Vector类,也是List接口实现类,怎么操作List,就怎么操作Vector
集合框架出现版本,1.2
Vector类,1.0
Vector底层数据结构也是可变长度数组
默认容量10个,增长100%
是线程安全的集合,运行速度慢
查询快,增删慢
在没有集合框架之前,存储对象,只能依靠Vector实现
有了集合,更先进的ArrayList取代
Vector v = new Vector();
v.add("abc");
v.add("bcd");
Iterator it = v.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
LinkedList
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
一些特有的方法
/*
* Object pollFirst 替换 removeFirst
* Object polllast 替换 removeLast
*/
public static void method_5(){
LinkedList link = new LinkedList();
link.add("abc1");
link.add("abc2");
//link.clear();
Object o = link.pollFirst();
System.out.println(o);
o = link.pollLast();
System.out.println(o);
}
/*
* Object peekFirst() 替换 getFirst
* Object peekLast() 替换 getLast
*/
public static void method_4(){
LinkedList link = new LinkedList();
link.add("abc1");
link.add("abc2");
link.clear();
Object o = link.peekFirst();
System.out.println(o);
o = link.peekLast();
System.out.println(o);
System.out.println(link);
}
/*
* boolean offerFirst() 替换addFirst
* boolean offerLast() 替换 addLast
*/
public static void method_3(){
LinkedList link = new LinkedList();
link.offerFirst("abc1");
link.offerFirst("abc2");
System.out.println(link);
}
/*
* Object removeFirst()移除并获取链表开头
* Object removeLast() 移除并获取链表结尾
* 集合没有元素,抛出没有元素被取出异常
*/
public static void method_2(){
LinkedList link = new LinkedList();
link.add("abc1");
link.add("abc2");
link.add("abc3");
link.add("abc4");
//移除链表的开头
Object o = link.removeFirst();
System.out.println(o);
//移除链表的结尾
o = link.removeLast();
System.out.println(o);
System.out.println(link);
}
/*
* Object getFirst()获取链表开头
* Object getLast() 获取链表结尾
* 集合没有元素,抛出没有元素被取出异常
*/
public static void method_1(){
LinkedList link = new LinkedList();
link.add("abc1");
link.add("abc2");
link.add("abc3");
link.add("abc4");
//获取链表的开头
Object o = link.getFirst();
System.out.println(o);
//获取链表的结尾
o = link.getLast();
System.out.println(o);
System.out.println(link);
}
/*
* addFirst(Object o)在链表的开头添加元素
* addLast(Object o) 在链表的结尾添加元素
*/
public static void method(){
LinkedList link = new LinkedList();
/*link.add("abc");
link.add("bcd");
link.addFirst("www");
link.addLast("itcast");*/
link.addLast("abc1");
link.addLast("abc2");
link.addLast("abc3");
link.addLast("abc4");
System.out.println(link);
}
对自定义类的操作
/*
* 存储Person对象
* name age 值,采用键盘输入
* 姓名和年龄,一起输入的 abvc 123 切割字符串
*/
import java.util.*;
import cn.itcast.beans.*;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<Person> array = new ArrayList<Person>();
Scanner sc = new Scanner(System.in);
//接收输入,两个数据一起写,空格分开,做字符串切割
while(true){
String line = sc.nextLine();
if("over".equals(line))
break;
//按照空格,进行字符串切割
String[] str = line.split(" +");
//数组的每个元素,存储到Person对象,Person存储到集合
array.add(new Person(str[0],Integer.parseInt(str[1])));
}
//迭代集合
Iterator<Person> it = array.iterator();
while(it.hasNext()){
Person p = it.next();
System.out.println(p.getName()+".."+p.getAge());
}
}
}
/*
* 集合嵌套,一个List集合中,存储了3个List集合
*/
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayArrayTest {
public static void main(String[] args) {
/*
* 大集合,存储的是小集合
* 泛型ArrayList,每个小集合,存储字符串
*/
ArrayList<ArrayList<String>> array = new ArrayList<ArrayList<String>>();
ArrayList<String> a1 = new ArrayList<String>();
ArrayList<String> a2 = new ArrayList<String>();
ArrayList<String> a3 = new ArrayList<String>();
ArrayList<String> a4 = new ArrayList<String>();
a1.add("11");
a1.add("12");
a2.add("21");
a2.add("22");
a3.add("31");
a3.add("32");
a4.add("41");
a4.add("42");
array.add(a1);array.add(a2);array.add(a3);array.add(a4);
//迭代集合array
Iterator<ArrayList<String>> it = array.iterator();
while(it.hasNext()){
//it.next获取出来的是什么,4个小集合
ArrayList<String> al = it.next();
//迭代每个小集合 al
Iterator<String> alIt = al.iterator();
while(alIt.hasNext()){
//next方法,获取小集合存储的字符串
System.out.println(alIt.next());
}
}
}
}
Set
概述
一个不包含重复元素的 collection。
Set:元素是无序(取出的顺序和存入的顺序无关),元素不可以重复。
Set派系:
|--HashSet:
底层数据结构是哈希表。
线程不同步。
不保证 set 的迭代顺序
特别是它不保证该顺序恒久不变。
|--TreeSet:
使用元素的自然顺序对元素进行排序
或者根据创建 set 时提供的 Comparator 进行排序
具体取决于使用的构造方法。
|--LinkedHashSe:
元素有序唯一
由链表保证元素有序
由哈希表保证元素唯一
Set接口派系特点:
元素是无序(取出的顺序和存入的顺序无关)
元素不可以重复
没有索引值
Set集合的功能和Collection是一致的。
new操作开辟空间,分配地址,对象会把地址值传给引用变量c,c就指向了开辟的内存。当对对象进行输出操作是,输出的不是地址而是一个哈希值,因为在输出语句中要走toString方法,toString方法会调用一个hashcode算法获得一个十进制的数。哈希值我们可以理解为对象的辨认编号,就如同我们的身份证号码一样,人在出生之后就会有一个具体的住址,但是却与身份证号没有直接的关系。可以看做一个虚拟的或者假的内存地址。
HasSet
HashSet:
HashSet底层哈希表结构,依靠对象的哈希值
集合线程不安全,存取速度快。
要特别注意的是为了要保证元素的唯一性,所以一般在操作自定义对象时都会重写hashCode方法和equals方法,一般在元素的HashCode值相同时,会判断equals是否为true。如果元素的hashCode值不同,就不必调用equals。并且八个基本类型+String,重写hashCode和equals。
哈希表底层默认数组,默认长度为16,位一个链表数组,存的是一个链表地址。链表中存储的是对象并且还要哈希值,若哈希值一样,就将对象一次连接存储。
演示用例:
import java.util.HashSet;
import java.util.Set;
import cn.itcast.beans.Person;
public class HashSetDemo {
public static void main(String[] args) {
method_1();
}
public static void method_1(){
Set<Person> set = new HashSet<Person>();
set.add(new Person("a",10));
set.add(new Person("b",9));
set.add(new Person("b",9));
System.out.println(set);
}
public static void method(){
Set<Integer> set = new HashSet<Integer>();
set.add(123);
set.add(new Integer(123));
System.out.println(set);
}
}
存储对象调用hashCode方法获取对象的哈希值,然后判断内存中是否存在该哈希值,若不存在,则直接将对象存入,若存在则判断该对象与内存中对象是否相同,如果不想同就将该对象挂靠在前一个对象的下面,若相同则不操作。
重写对象方法
public int compareTo(Person p){
//调用者this对象,传递的参数p对象进行比较
//比较的姓名
int num = this.name.compareTo(p.name);
return num==0?this.age-p.age:num;
}
public int hashCode(){
return name.hashCode() + age*31;
}
public boolean equals(Object obj){
if(obj == null)
return false;
if(this == obj)
return true;
if(obj instanceof Person){
Person p = (Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
return false;
}
public String toString(){
return "Person " + name +".."+age;
}
TreeSet
特点
a)底层的数据结构为二叉树结构(红黑树结构)
b)可对Set集合中的元素进行排序
c)集合线程不安全
d)TreeSet的两种实现排序的方式
一种是实现Comparable接口,重写 compareTo方法,使类中的元素具备类自然顺序,然后让元素按照自然顺序进行排序。
另一种是自定义比较器,要实现Comparator接口,并重写其中的抽象方法,根据自定义的方法进行排序。
注意:排序时,当主要条件相同时,再判断次要条件。
演示用例:
/*
* TreeSet存储字符串并迭代
*/
public static void method(){
Set<String> set = new TreeSet<String>();
set.add("grrhefd");
set.add("qwedsf");
set.add("nhbgvc");
set.add("ewds");
set.add("nbgvdc");
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
第一个对象作为根进内存,然后是第二个对象调用自身的compareTo方法,并把根对象作为参数传入进行比较,若结果为整数,说明比对象1大,就放在对象一的右边,如图中的字符串“qwedsf”,若结果为0,则不进行操作,若结果为负数,说明对象一大,那么就放在对象1的左边,如图中字符串“ewds”;再对第三个对象操作,方法同上,若结果为正,再与存入的“qwedsf”,原来相同。这是按照元素的自然顺序进行的排序。
自定义对象排序:
/*
* TreeSet存储自定义对象并迭代
* 不靠对象的自然顺序(Comparable接口)
* TreeSet还可以另一种形式排序,比较器形式
* TreeSet构造方法
* TreeSet(Comparator comparator) 传递接口,传递实现类对象
* 接口Comparator比较器接口
* 自定义比较器,实现Comparator,重写抽象方法
*/
public static void method_3(){
Set<Person> set = new TreeSet<Person>(new PersonComparator());
set.add(new Person("abc",10));
set.add(new Person("abb",20));
set.add(new Person("abb",18));
set.add(new Person("aaa",15));
set.add(new Person("aaa",15));
set.add(new Person("lisi",18));
for(Person p : set){
System.out.println(p);
}
}
自定义比较器
public class PersonComparator implements Comparator<Person>{
public int compare(Person p1, Person p2){
//比较两个对象的年龄
//不允许直接调用Person类的成员变量
//获取年龄差
int num =p1.getAge() - p2.getAge();
return num==0?p1.getName().compareTo(p2.getName()):num;
}
操作原理同上,不同的是比较原则不再是自然顺序,而是自己定义的,根据年龄排序,年龄相同的再比较名字。
LinkedHashSet继承HashSet(了解即可)
自身特性:
底层是基于链表的哈希表结构
线程不安全,运行速度快
保证元素的迭代顺序 -- 有序的Set集合
Set本身为无序集合 -- HashSet 出现在JDK1.2版本
LinkedHashSet 有序集合 出现在JDK1.4版本
演示用例:
LinkedHashSet<String> link = new LinkedHashSet<String>();
link.add("abc");
link.add("bcd");
link.add("qaz");
link.add("wsx");
for(String s : link){
System.out.println(s);
}
运行结果为:
abc
bcd
qaz
wsx
泛型(Generic)
概述
早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。
JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。
没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全。
泛型应用
泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型
演示用例:
//定义泛型类
class Demo<QQ>{
public void show(QQ q){
System.out.println(q);
}
}
class GenericClass<E>{
private E e;
public E getE(){
return e;
}
public void setE(E e){
this.e =e;
}
public void show(E e){
System.out.println(e);
}
//泛型类的使用
Demo<Integer> d = new Demo<Integer>();
d.show(890);
GenericClass<Integer> generic = new GenericClass<Integer>();
generic.show(123);
GenericClass<Character> generic2 = new GenericClass<Character>();
generic2.show('a');
GenericClass<String> generic3 = new GenericClass<String>();
generic3.setE("abc");
String s = generic3.getE();
System.out.println(s);
注意:
1、在对泛型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
2、当一个变量被声明为参数时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用,因为静态成员是被所有参数化的类共享的,所以静态成员不应该有类级别的类型参数。
泛型方法
把泛型定义在方法上
格式:public <泛型类型> 返回类型 方法名(泛型类型 .)
泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所以要操作的类型就已经固定了。
类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的
class GenericMethod<QQ>{
public void show(QQ q){
System.out.println(q);
}
//方法中的泛型E,不跟随类走
//对于方法中泛型,单独定义
public <E> void function(E e){
System.out.println(e);
}
//静态方法泛型,不能和类的方法一样
//静态方法泛型,定义只能在方法上
public static <SSH> void method(SSH q){
System.out.println(q);
}
}
//泛型类和泛型方法的使用
GenericMethod.method('w');
GenericMethod<String> generic = new GenericMethod<String>();
generic.show("abc");
generic.function(new String("qq"));
特殊之处:
静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
泛型方法的特点:
1、位置:用于放置泛型的类型参数的<>应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前,按照惯例,类型参数通常用单个大写字母表示。
2、只有引用类型才能作为泛型方法的实际参数。
3、除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。例如,Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,如<V extends Serializable& cloneable> void method(){}。
4、普通方法、构造函数和静态方法中都可以使用泛型。
5、在泛型中可同时有多个类型参数,在定义它们的<>中用逗号分开。
泛型接口
把泛型定义在接口上
格式:public interface 接口名<泛型类型1…>
interface MyInter<QQ>{
public void show(QQ q);
}
class MyImpl<QQ> implements MyInter<QQ>{
public void show(QQ q){
System.out.println(q);
}
}
class MyImpl2 implements MyInter<String>{
public void show(String s){
System.out.println(s);
}
}
public class GenericInterfaceDemo {
public static void main(String[] args) {
MyInter<String> my = new MyImpl<String>();
my.show("abc");
}
}
将对集合定义泛型,保证数据安全
集合类<数据类型> 变量 = new 集合类<数据类型>();
泛型通配符<?>
当传入的类型不确定时,可以使用通配符。使用通配符提高了代码的扩张性,可以在不明确传入的类型时,使用泛型类或者泛型方法。
Iterator<?> it 可以与任意参数化的类型匹配,但到底匹配的是什么类型,取决于你最后限定的类型。
演示用例:
定义方法,实现同时遍历多个带有泛型的集合
List<String> array = new ArrayList<String>();
List<Integer> link = new LinkedList<Integer>();
array.add("abc");
array.add("qqq");
link.add(123);
link.add(456);
iterator(array);
iterator(link);
}
/*
* 定义方法,实现同时遍历多个带有泛型的集合
* ? 通配符 遍历
*/
public static void iterator(List<?> list){
Iterator<?> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
泛型限定
? extends E
可以传递E类型,传递E的子类类型,泛型上限限定
? super E
E 可以传递E类型,传递E的父类类型,泛型下限限定
演示用例:
定义2个集合
分别存储员工对象,和经理对象
一个方法同时迭代2个集合,迭代过程中,调用方法job
//创建集合,存储员工对象
ArrayList<Employee> employee = new ArrayList<Employee>();
employee.add(new Employee("张三", "开发部001", 12345.67));
employee.add(new Employee("李四", "开发部002", 12545.67));
//创建集合,存储经理对象
ArrayList<Manager> manager = new ArrayList<Manager>();
manager.add(new Manager("王五","董事会001",120.98,567890.98));
manager.add(new Manager("赵六","董事会002",122.98,667890.98));
iterator(employee);
iterator(manager);
}
/*
* 定义方法,同时迭代2个集合
* 调用方法job
*/
public static void iterator(ArrayList<? extends Company> array){
Iterator<? extends Company> it = array.iterator();
while(it.hasNext()){
//next()获取出来的数据类型?
Company c = it.next();
c.job();
}
}
7、好处
a、将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题。让运行时期问题减少、安全。
b、避免了强制转换的麻烦。如在实现某一个接口时,指定传入接口方法的实参的类型的话,在复写该接口方法时就可以直接使用指定类型,而不需要强制转换。
小结:
第一、定义泛型:当又不确定的类型需要传入到集合中,需要定义泛型。
第二、定义泛型类:如果类型确定后,所操作的方法都是属于此类型,则定义泛型类。
第三、定义泛型方法:如果定义的方法确定了,里面所操作的类型不确定,则定义泛型方法。
增强for概述
JDK5版本出现的新特性。
1.5版本为Collection接口增加了一个父接口java.lang.Iterable,凡是这个接口下的所有子接口和实现类,都可以使用增强for循环。
目的就在于:简化数组和Collection集合的遍历。
格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
演示用例:
/*
* 增强for遍历数组
* 能做数组排序吗? NO
* 方便遍历而已,不能动数组里面的任何内容
*/
public static void method(){
int[] arr = {1,5,7,2};
for(int i : arr){
System.out.println(i+1);
}
String[] str = {"abc","abcdef","www.baidu.com"};
for(String s : str){
System.out.println(s.length());
}
}
注意事项:增强for的目标要判断是否为null。
静态导入
JDK5出现新特性
导入是包中的所有类
格式:import static 包名….类名.方法名;
可以直接导入到方法的级别
注意事项
方法必须是静态的
如果有多个同名的静态方法,容易不知道使用谁?这个时候要使用,必须加前缀。由此 可见,意义不大,所以一般不用,但是要能看懂。
演示用例:
import static java.lang.System.out;
import static java.util.Arrays.sort;
public class ImportStaticDemo {
public static void main(String[] args) {
out.println("hello world");
int[] arr = {3,1};
sort(arr);
}
}
但是要注意自定义方法和静态方法重名时存在的安全问题。
可变参数
我们在定义方法的时候不知道该定义多少个参数,这时,我们就可以使用可变参数来解决这一问题。JDK5新特性
格式
修饰符 返回值类型 方法名(数据类型… 变量名){}
注意:
这里的变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个,且只能有一个
演示用例:
public class ArgumentsDemo {
public static void main(String[] args) {
int sum = getSum(1,4,6);
System.out.println(sum);
method("a","b","cvc");
show(1,2,3,4,5,6);
}
public static void show(int a,int b,int...c){//一个方法中,可变参数,只能出现在参数列表的最后一位
}
public static void method(String...s){//一个方法中,可变参数只能有1个
}
/*
* 定义方法,计算整数求和,多少个整数都行
*/
public static int getSum(int...a){
int sum = 0 ;
/*for(int x = 0 ; x < a.length ;x++){
sum = sum + a[x];
}*/
for(int x : a){
sum = sum +x;
}
return sum;
}
-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——java基础: 集合
- 黑马程序员——Java基础 ---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——java基础--集合
- 黑马程序员——Java基础---集合
- 黑马程序员——java基础-集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础---集合
- 黑马程序员——Java基础--------集合
- Restore IP Addresses
- Coreseek的使用步骤
- [LeetCode] Valid Anagram
- Visual Studio 遇到了异常。这个可能是由某个扩展导致的
- tar 的用法介绍
- 黑马程序员——Java基础---集合1
- Android PopupWindow的使用
- Atom飞行手册翻译: 3.1 ~ 3.2
- IOS 开发xcode 6.3以后 自制FrameWork教程
- mysql悲观锁总结和实践
- VS2003中DLL断点调试,不执行断点
- javaEE项目中常用的包含上下文路径的代码
- Qt中的二维图形(二)
- linux下查看中断请求记录 IRQ