语法之集合Collection"/>
Java基础语法之集合Collection
目录
集合简介
Collection集合
list集合
Iterator的并发修改异常
增强版的for循环遍历数组或者遍历Collection集合
list实现类集合ArrayList和LinkList
ArrayList集合
引用数据类型概论
2.引用数据类型分类
引用数据类型和基本数据类型的区别
LinkList集合中特有的方法
set集合
hashSet集合
LinkedHashSet集合
判断集合元素是否唯一的原理
TreeSet集合
泛型
集合简介
java集合中提供了为Collection接口和Map接口
Colloction接口和Map接口的不同
Conlloction接口实现的子类时实现而Map的子类则是以键值对的形式存储的
接下来我们来看看集合体系
Collection集合
是接口 不能实力化对象,所以可以用它的子类实例化(向上转型)利用多态的形式
Collection集合的常用方法(前面是返回值类型)
方法名 | 说明 |
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定元素 |
void clear() | 清空集合中的所有元素 |
boolean contains(Object o) | 判断集合中是否包含此元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 获得集合的长度 |
C
Collection 集合的遍历
Iterator 迭代器 集合类通用的遍历方式 用迭代器迭代遍历
Iterator 接口也是java集合框架的成员,它的对象被称为迭代器
定义了如下几个方法
boolean hasNext(); 如果集合还没有遍历完则返回true
Object next() 从集合中获取下一个元素
void remove(); 删除集合里上一次next方法返回的元素
注意Iterator 必须依赖于集合对象是从集合中获取
案例代码
package day6;import java.util.*;public class Collection{public static void main(String[] args) {
//创建一个对象``````java.util.Collection<Student> c=new ArrayList<>();//创建学生对象Student s1=new Student("凌青霞",30);Student s2=new Student("李四",320);Student s3=new Student("王五",230);//添加元素c.add(s1);c.add(s2);c.add(s3);c.remove(s2);boolean isNull= c.isEmpty();boolean contains=c.contains(s1);int size=c.size();System.out.println("集合是否为空"+isNull);System.out.println("集合中是否包含s1"+contains);System.out.println("集合长度"+size);System.out.println("=======================");//遍历集合Iterator<Student> it=c.iterator();while (it.hasNext()){Student ss=it.next();System.out.println("name " +ss.getName());System.out.println("age "+ss.getAge());}}
}
运行结果
集合是否为空false
集合中是否包含s1true
集合长度2
=======================
name 凌青霞
age 30
name 王五
age 230
list集合
List集合是Collection集合的子接口 可以得到父接口的所有方法
接口不能实例化对象所以要依靠多态
List接口的常用子类有:
- ArrayList集合
- LinkedList集合
list集合的特点
- 可以重复
- 存储有序,可以序号遍历(索引是从0开始)
继承Collection集合
具有父类接口方法
List特有的方法
void add( int index,Object element); 将指定元素添加到指定位置
Object get(int index); 获得指定索引的元素
int indexOf(Object o); 获得指定元素第一次出现的索引
int lastIndex(Object o) 获得指定元素最后一次出现的索引
Object remove(int index); 删除指定索引的元素并返回
Object set(int index,Object o); 修改指定索引的元素并返回
案例使用
package day6;import java.util.ArrayList;
import java.util.Iterator;public class List {public static void main(String[] args) {//创建集合对象java.util.List<String> list=new ArrayList<String>();//添加元素list.add("hello");list.add("world");list.add("java");list.add("java");/*Void add(int index,E e); //插入指定元素
E remove(int index) //删除索引出指定元素
E set(int index,E e)//修改指定索引处的元素,返回修改后的元素
E get(int index)//获得索引的元素*/list.add(1,"插入到1位置的元素");list.remove(2);list.set(3,"修改后的java");String s =list.get(2);System.out.println("获得指定索引元素"+s);//可以重复//输出集合对象System.out.println(list);//迭代器遍历Iterator<String> it= list.iterator();while (it.hasNext()){String its=it.next();System.out.println(its);}}
}
运行结果
Iterator的并发修改异常
要求条件 在list集合中,对元素进行判断,一旦满足条件就新添加一个新的元素
public class IteratorDemo {
//在list集合迭代元素中,对元素进行判断,一旦条件满足就添加一个新元素public static void main(String[] args) {//创建List集合List<String> list = new ArrayList<String>();//给集合中添加元素list.add("abc1");list.add("abc2");list.add("abc3");list.add("abc4");//迭代集合,当有元素为"abc2"时,集合加入新元素"itcast"Iterator<String> it = list.iterator();while(it.hasNext()){String str = it.next();//判断取出的元素是否是"abc2",是就添加一个新元素if("abc2".equals(str)){list.add("itcast");// 该操作会导致程序出错}}//打印容器中的元素System.out.println(list);}
}
运行上述代码发生了错误 java.util.ConcurrentModificationException[L1] 这是什么原因呢?
在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。
经过查看Iterator源码可知
并发修改异常
/modCount:实际修改的次数 当调用add()方法时 ++;但是expectedModCount没有改变
//expectedModCount预期修改的次数
// it.next();
// 方法有一个判断 if(expectedModCount==modCount:)
如果两者不相等的就会抛出异常
1、for循环根据索引遍历修改
for (int i=0;i<list.size();i++){String s=list.get(i);if (s.equals("world")){list.add("javaEE") ;}}System.out.println(list);
}
2、
用ListIterator可以解决 ,其中含有add()方法
会把实际的修改值,赋值给预期的修改值;
ListIterator<String> list2=new list.listIterator();
while (list2.hasNext()){String s=it.next();if (s.equals("world")){list.add("javaEE");}
}
增强版的for循环遍历数组或者遍历Collection集合
增强版的for循环实现原理
实现类Iterable接口的类
- 其对象成为增强版的for语句的目标
- 其实他是JDK5之后出现的,其内部原理是一个Iterator迭代器
增强版的for循环格式
for(元素类型变量: 数组或Collection集合)
{
此处变量即可,该变量就是元素
}
for (int i=0;i<list.size();i++){System.out.println(list.get(i));
}for (String s:list){System.out.println(s+"世界正大");}//测试增强版的for循环是iterator实现类for (String s2:list){if (s2.equals("world")){list.add("javaEe");//报并发修改异常}}
结果
案例
package day6.StudentListBianli;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class students {public static void main(String[] args) {
//创建学生对象Student s=new Student("张三",15);Student s2=new Student("王五",15);Student s3=new Student("李四",15);
// String ss1=s.getName();
// String ss2=s2.getName();
// String ss3=s3.getName();//创建集合对象List<Student> list=new ArrayList<Student>();list.add(s);list.add(s2);list.add(s3);//普通遍历for(int i=0;i<list.size();i++){System.out.println(list.get(i).getAge());}//增强for循环for(Student n:list){System.out.println(n.getName());}//Iterator遍历Iterator <Student> it=list.iterator();while (it.hasNext()){System.out.println(it.next().getAge());}}
}
list实现类集合ArrayList和LinkList
ArrayList 和linkList 集合的特点
ArrayList 底层的数据结构是数组,查询快,增删慢
LinkList 底层是链表增删快,查询慢
ArrayList集合
特有的方法
- Object remve(int index) 从集合中删除指定index处的元素,返回该元素
ArrayList集合是程序中最常见的一种集合,它属于引用数据类型(类)。在ArrayList内部封装了一个长度可变的数组,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组。
声明格式
ArrayList<数据类型> 变量名 =new ArrayList<数据类型>;
<>数据类型的要求
- 集合中存储的元素,只能为<>括号中指定的数据类型元素;
- “<要存储元素的数据类型>”中的数据类型必须是引用数据类型,不能是基本数据类型;
那什么事引用数据类型呢
引用数据类型概论
- 引用数据类型 变量名 这样声明的时候变量为null。
-
引用数据类型 变量名=new 引用数据类型,例如String a=new String("hi~")这时候内存存储如图:
-
这时候String a 在栈内存中声明了 一个内存地址,内存地址指向堆内存中new String("hi~")声明的对象。即变量名为引用的内存地址。
2.引用数据类型分类
- 类
Object object= new Integer(1); //来定义一个Interger类 - 接口
接口不能直接new进行实例化,可以引用实现接口的类。 - 数组
int[] a=new int[10];
引用数据类型和基本数据类型的区别
一、从概念方面来说
基本数据类型:变量名指向具体的数值
引用数据类型:变量名指向存数据对象的内存地址,即变量名指向hash值
二、从内存构建方面来说
基本数据类型:变量在声明之后java就会立刻分配给他内存空间
引用数据类型:它以特殊的方式(类似C指针)指向对象实体(具体的值),这类变量声明时不会分配内存,只是存储了一个内存地址。
接下来我给出8中基本数据类型对应的引用数据类型
基本数据类型 | 对应的引用数据类型表示形式 |
byte | Byte |
short | Short |
Int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
LinkList集合中特有的方法
LinkList 底层是链表增删快,查询慢
public void addFirst(E e) 向列表中开头插入指定元素
public void addLast(E e) 向列表插入指定元素
public E getFist(); 返回列表中第一个元素
public E getLast(); 返回列表中末尾的一个元素
Public E removeFist(); 删除并返回第一个元素
Public E removeLast(e); 删除并返回最后一个元素
set集合
是Collection接口的子接口
set集合的特点
1、不能存储重复元素 ,元素的唯一
2、没有带索引的方法所以不能存取索引的方法遍历
package day7;import java.util.HashSet;public class Set {public static void main(String[] args) {//HashSet:对集合的迭代顺序不做保障//不包含重复元素java.util.Set <String> set=new HashSet<String>();//添加元素set.add("hello");set.add("he033");set.add("hjava");set.add("hjava");set.add("022");set.add("hjava");for(String s:set){System.out.println(s);}}
}
hashSet集合
首先我们来解释
一个概念 哈希表
如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。
HashSet 唯一性
HashSet集合 底层采取的是哈希表结构存储结构 依赖于hashCode()与equals()方法
同一个对象中多次调用hasCode();哈希值相同
默认情况下不同对象的哈希值是不同的但是可以相同,就是重写hasCode()方法
HashSet 存储元素
存储JavaAPI中的元素不需要重新hashCode();和equals()方法,api中已经重写完毕
存储自定义数据类型时要重写hashCode()和equals() 方法建立自己的比较方式才能保证集合对象的唯一性
public class Student {private String name;private int age;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;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if(!(obj instanceof Student)){System.out.println("类型错误");return false;}Student other = (Student) obj;return this.age == other.age && this.name.equals(other.name);}
} 创建HashSet集合,存储Student对象。
public class HashSetDemo {public static void main(String[] args) {//创建HashSet对象HashSet hs = new HashSet();//给集合中添加自定义对象hs.add(new Student("zhangsan",21));hs.add(new Student("lisi",22));hs.add(new Student("wangwu",23));hs.add(new Student("zhangsan",21));//取出集合中的每个元素Iterator it = hs.iterator();while(it.hasNext()){Student s = (Student)it.next();System.out.println(s);}}
}
结果
输出结果如下,说明集合中不能存储重复元素:
Student [name=lisi, age=22]
Student [name=zhangsan, age=21]
Student [name=wangwu, age=23]
LinkedHashSet集合
特点 既保证了元素的唯一性有保证了元素是有序的
底层是它是链表和哈希表组合的一个数据存储结构。
public class LinkedHashSetDemo {public static void main(String[] args) {Set<String> set = new LinkedHashSet<String>();set.add("bbb");set.add("aaa");set.add("abc");set.add("bbc");
Iterator it = set.iterator();while (it.hasNext()) {System.out.println(it.next());}}
}
结果
输出结果如下,LinkedHashSet集合保证元素的存入和取出的顺序:
bbb
aaa
abc
bbc
判断集合元素是否唯一的原理
ArrayList 的contains方法判断是否有重复元素
boolean contains(Object o);
返回列表中是否包含此元素
那么自定义类型中并没有重写eauals方法前,判断是否重复是地址值,那么如果要比较元素的内容是否相等就必须重写equals方法
HashSet的add/contains 方法判断
set集合不添加重复元素
HashSet 集合是无序的,
其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:
先判断新元素与集合内已经有的旧元素的HashCode值
- 如果不同,说明是不同元素,添加到集合。
如果相同,再判断equals比较结果。返回true则相同元素;返回false则不同元素,添加到集合。
自定义类型需要重写hashcode和equals方法
TreeSet集合
特点
1、元素有序 ,是按照一定的规则进行排序的,具体的排序方式取决于构造方法
2.TreeSet();根据器元素的字眼潘旭进行排序(默认)
3.TreeSet(Comparator comparator)指定比较器比较
案例
package day7;import java.util.HashSet;
import java.util.TreeSet;public class Set {public static void main(String[] args) {
//创建集合TreeSet<Integer> ts=new TreeSet<Integer>();//添加元素ts.add(10);ts.add(40);ts.add(30);ts.add(30);for (Integer s:ts){//自然排序从小到大System.out.println(s);//结果// 1// 0//30//40}}public class Generid<T>{private T t;public T getT() {return t;}public void setT(T t) {this.t = t;}public void show(T t){System.out.println(t);}}}
结果
//结果
// 1
// 0
//30
//40
案例2 指定规则排序
package day7;import java.util.Comparator;
import java.util.TreeSet;public class TreeSet02 {public static void main(String[] args) {//Comparable自然排序 该接口对实现它的每一个对象强加一个整体排序,这个排序称之为自然排序 并且可以去除重复元素TreeSet<Student> ts=new TreeSet<Student>(new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {int num=s1.getAge()-s2.getAge();int num2=num==0?s1.getName()pareTo(s2.getName()):num;return num2;}});//创建对象Student s=new Student("aaa",19) ;Student s2=new Student("zzzz",12) ;Student s3=new Student("cc",18) ;Student s4=new Student("ddd",56) ;Student s5=new Student("ee",20) ;ts.add(s);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);//遍历for (Student ss:ts){System.out.println("姓名"+ss.getName()+"年龄"+ss.getAge());}}
}
结果
姓名zzzz年龄12
姓名cc年龄18
姓名aaa年龄19
姓名ee年龄20
姓名ddd年龄56
Process finished with exit code 0
泛型
定义
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
具体使用
泛型的参数需要哪一种类型直接调用即可相当于一个参数
定义格式
修饰符 class 类名 <类型> {}
Public class Generic<T> {}
Gnerid<String> str =new Gnerid<String>();
Str.show(“字符串类型”);
Gnerid<Interger> i=new Gnerid <Interger>();
- show(100);
泛型接口实现泛型接口
public calss Gerneriidzilei <T> implements Gerneriid <T> {
System.out.println(t);
}
更多推荐
Java基础语法之集合Collection
发布评论