一、List列表迭代器
-
List集合的获取功能(List集合的专有遍历方式):
ListIterator listIterator() :获取列表迭代器
ListIterator
正向遍历
boolean hasNext():判断是否有下一个可以迭代的元素
E next():获取下一个元素逆向遍历 boolean hasPrevious():判断是否有上一个可以迭代的元素 E previous():获取上一个元素
先有正向遍历,才能逆向遍历
举例:
public class ListDemo {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<String>() ;
//添加字符串元素
list.add("hello") ;
list.add("world") ;
list.add("java") ;
list.add("javaEE") ;
//获取列表迭代器
ListIterator<String> lit = list.listIterator();
//遍历
while(lit.hasNext()){
String s = lit.next();
System.out.println(s);
}
System.out.println("-------------------------------");
while(lit.hasPrevious()){
String s = lit.previous() ;
System.out.println(s);
}
}
}
二、ArrayList/Vector/LinkedList对比
- ArrayList
举例:
/*ArrayList一般默认情况没有明确使用什么集合的时候,默认使用它
*/
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
//默认容量大小就是10个,当传递容量大小(有参构造方法)会自动扩容grow方法: 1.5倍的机制来进行扩容
arrayList.add("hello") ;
arrayList.add("world") ;
arrayList.add("javaee") ;
arrayList.add("javaee") ;
System.out.println(arrayList);
for(String s: arrayList){
System.out.println(s);
}
//for循环的写法
/* for(Iterator<String> it = arrayList.iterator() ;it.hasNext();){
String next = it.next();
System.out.println(next);
}*/
}
}
- Vector
举例:
程安全的类
* StringBuffer:字符串缓冲区
* Vector集合(将元素都称为 "组件")
* 特有功能
* public void addElement(Object obj):添加元素
* public Enumeration<E> elements():获取向量组件的枚举 (类似于 Iterator iterator())
* Enumeration:
* boolean hasMoreElements():判断是否有很多的元素---类似于:boolean hasNext()
* Object nextElement(): ---- 类似于:Object next()
*
* public E elementAt(int index):-------类似于:List集合中的get(int index)
* 获取索引值对应的"组件"
* 和size()相结合----普通for循环的遍历方式
*/
public class VectorDemo {
public static void main(String[] args) {
//创建一个Vector集合
Vector<String> vector = new Vector<String>() ;
//添加字符串元素,特有功能
vector.addElement("hello");
vector.addElement("world");
vector.addElement("JavaEE");
// System.out.println(vector);
//获取它的Enurmation: 向量组件的枚举
Enumeration<String> enumeration = vector.elements();
while(enumeration.hasMoreElements()){
//获取
String s = enumeration.nextElement();
System.out.println(s);
}
System.out.println("----------------------------------");
//普通for循环
for(int x = 0 ; x < vector.size() ; x ++){
String s = vector.elementAt(x);
System.out.println(s);
}
}
}
-
LinkedList
LinkedList特有功能:
public void addFirst(E e):将元素添加到开头
public void addLast(E e):将元素添加到链表的末尾
public Object removeFirst():删除列表的第一个元素,并返回的是第一个元素
public Object removeLast():获取
public E getFirst():获取列表的开头元素
public E getLast()
举例:
/* 需求:
* 使用LinkedList来模拟栈结构特点:先进后出!
* 自定义栈集合:MyStack 类
* 提供add()
* 依赖于LinkedList集合的特有功能
* 提供get()
* 依赖于LinkedList的特有功能
*/
public class LinkedListDemo {
public static void main(String[] args) {
//创建LinkedList集合对象
LinkedList<String> link = new LinkedList<String>() ;
//添加
link.addFirst("hello");
link.addFirst("world");
link.addFirst("javaEE");
// public Object removeFirst():
/*System.out.println(link.removeFirst());
System.out.println(link.removeFirst());*/
System.out.println(link.getFirst());
System.out.println(link);
}
}
练习:
public class MyStackTest {
public static void main(String[] args) {
//创建MyStack:栈集合类对象
MyStack myStack = new MyStack() ;
myStack.add("hello");
myStack.add("world");
myStack.add("javaee");
//获取元素
/* Object obj = myStack.get();
System.out.println(obj);
System.out.println(myStack.get());
System.out.println(myStack.get());
System.out.println(myStack.get());*/ //此时元素已经取完了
//为了不会出现异常,所有在获取元素的时候,加入判断
/* if(!myStack.isEmpty()){
System.out.println(myStack.get());
}
if(!myStack.isEmpty()){
System.out.println(myStack.get());
}
if(!myStack.isEmpty()){
System.out.println(myStack.get());
}
if(!myStack.isEmpty()){
System.out.println(myStack.get());
}*/
//循环改进
while(!myStack.isEmpty()){
System.out.println(myStack.get());
}
}
}
import com.sun.corba.se.spi.ior.ObjectKey;
import java.util.LinkedList;
/* 使用LinkedList来模拟栈结构特点:先进后出!
*/
public class MyStack {
private LinkedList link = null ;
//无参构造方法
public MyStack(){
link = new LinkedList() ;
}
//提供一个方法:每次调用这个方法的时候,将元素添加到开头
public void add(Object obj){ //模拟栈:进栈的方式压栈
link.addFirst(obj);
}
//提供一个方法:每次调用,获取元素,同时删除链表开头元素( 栈:出栈的方式叫弹栈)
public Object get(){
return link.removeFirst() ; //将列表的开头元素删除,返回被删除的元素!
}
//判断集合是否空
public boolean isEmpty(){
return link.isEmpty() ;//为空,则返回true/不为空,则返回false
}
}
三、增强for循环
-
JDK5以后:增强for循环
一般场景:
遍历集合或者数组:遍历集合居多,增强for是为了简化迭代器的书写方式,替代集合的迭代器集合中使用较为广泛
格式:
for(集合中存储的数据类型 变量名 : 集合对象){
使用变量名
}使用List集合来存储String类型/Student类型(自定义类型)
注意事项:
要使用增强for,前提条件就是集合不能为空
举例:
public class Student {
private String name ;
private int age ;
public Student() {
}
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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ForEachDemo {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<String>() ;
//添加元素
list.add("hello") ;
list.add("world") ;
list.add("java") ;
//增强for----就是迭代器
//需求:如果集合中有一个"world",给集合中添加一个javaee
/* for(String s : list ){
//获取到s
if("world".equals(s)){
list.add("javaee") ;
}
}*/
//集合遍历,集合添加
for(int x = 0 ; x < list.size() ;x ++){
String s = list.get(x);
if("world".equals(s)){
list.add("javaee") ;
}
}
System.out.println(list);
System.out.println("---------------------------------------------------------");
//创建一个新的List集合对象
List<Student> stuList = new ArrayList<Student>() ;
//创建三个学生
Student s1 = new Student("刘备",30) ;
Student s2 = new Student("关羽",25) ;
Student s3 = new Student("张飞",20) ;
stuList.add(s1) ;
stuList.add(s2) ;
stuList.add(s3) ;
stuList = null ;
//要使用增强for,必须集合不能空,否则空指针异常
if(stuList!=null){
for(Student s : stuList){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
}
四、Set集合
- Collection的toString()方法
public String toString() {
Iterator<E> it = iterator();//this.iterator() //获取Collection集合迭代器
if (! it.hasNext()) //如果当前迭代器没有下一个可以遍历元素
return "[]"; // 返回 "[]"
StringBuilder sb = new StringBuilder(); //创建字符串缓冲区对象
sb.append('['); //追加左"["
for (;;) { //死循环for
E e = it.next(); //获取迭代器中的元素 E ---Object
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext()) //没有下一个元素:获取末尾
return sb.append(']').toString();
sb.append(',').append(' '); //追加逗号和空格
}
}
- HashSet的add方法的源码
interface Set<E>{
}
class HashSet<E> extends AbstractSet<E> implements Set{
//自定义常量!
private static final Object PRESENT = new Object(); //创建Object了对象
//成员变量
//transient:被他修饰的变量不会被进行序列化
private transient HashMap<E,Object> map;
//无参构造方法
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) { //hello = e
return map.put(e, PRESENT)==null;
}
}
//HashMap集合:双列集合 存储一系列的键值对元素
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>{
public V put(K key, V value) { //key -->添加的 "hello","hello","world"
//value = PRESENT---
return putVal(hash(key), key, value, false, true);
}
//hash方法
static final int hash(Object key) { //key: "hello","hello","world"
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
//添加的元素都是不为null的,都是有值
计算每一个对象的哈希码值
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//HashMap(哈希表----桶状结构)集合它会将键值对元素-----在 Node<K,V>存储起来
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
....
put方法依赖于 putVal方法
hash()方法需要计算每一个元素的哈希码值
如果哈希码值,比较内容是否相同,如果相同了就认为是同一个元素,所以每次 出现元素,都不会添加进去
元素是唯一的!
}
//set.add("hello") ;
//set.add("hello") ;
- TreeSet的add方法的源码
class TreeSet<E> implements Set<E>{
private transient NavigableMap<E,Object> m; 红黑树 Map的结构
private static final Object PRESENT = new Object();
//无参构造方法
public TreeSet() {
this(new TreeMap<E,Object>());
}
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
//添加元素
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
}
//TreeMap<K,V>
class TreeMap<K,V> implements NavigableMap<K,V>{
private transient Entry<K,V> root; 根节点对象(键值映射项:键值对)
public V put(K key, V value) { //key = 20,17,23,21,22...
Entry<K,V> t = root; //将第一个元素作为根节点root
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent; //声明键值对:父节点
// split comparator and comparable paths
//比较器排序
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException(); //如果key为空,就出现空指针异常
@SuppressWarnings("unchecked")
//将key---->存储的键 :20,17,23,22... (Integer)
//强制类型转换
//当前key:集合存储的数据类型的指定的元素: 存储的数据类型必须实现Comparable
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t; //将第一个元素作为根节点
cmp = k.compareTo(t.key); //使用当前元素(根节点)和传递进来的元素进行比较
if (cmp < 0)
t = t.left; 小于0,作为左孩子(左节点)
else if (cmp > 0) 大于0,作为右节点
t = t.right;
else
return t.setValue(value);//相等:就赋值一次
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
如果我们现在使用TreeSet集合存储自定义对象,并自然排序 应该注意什么?
}
-
使用Set集合存储自定义对象并遍历,并且保证Student元素唯一的!
当使用set集合存储自定义对象,要保证元素唯一,
就需要set集合底层依赖于hashCode和equals方法!Set集合特点:它不保证遍历顺序恒久不变(哈希表决定的)
-
Set集合和List集合区别
1). List有序(存储和取出一致)
允许元素重复
Set无序(存储和取出不一致)
不允许元素重复
2). Set接口不能实例化,最具体的子类:使用HashSet以及TreeSet
HashSet(线程不安全的类:它允许null元素可以出现,执行效率高)----底层由HashMap实现
3). HashSet的add方法—依赖于HashMap的put方法
依赖于:hash方法需要计算每一个元素的hash码值(hashCode())
依赖equals方法:比较内容是否相同
举例1:
public class Student {
private String name ;
private int age ;
public Student() {
}
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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class SetTest {
public static void main(String[] args) {
HashSet<Student> hashSet = new HashSet<Student>() ;
//添加一些学生对象
Student s1 = new Student("文章",35) ;
Student s2 = new Student("文章",35) ;
Student s3 = new Student("文章",30) ;
Student s4 = new Student("高圆圆",41) ;
Student s5 = new Student("高圆圆",41) ;
Student s6 = new Student("吴奇隆",50) ;
Student s7 = new Student("成龙",60) ;
Student s8 = new Student("成龙",60) ;
//添加到set集合
hashSet.add(s1) ;
hashSet.add(s2) ;
hashSet.add(s3) ;
hashSet.add(s4) ;
hashSet.add(s5) ;
hashSet.add(s6) ;
hashSet.add(s7) ;
hashSet.add(s8) ;
//遍历
for(Student s: hashSet){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
举例2:
public class HashSetDemo {
public static void main(String[] args) {
//创建Set集合对象
Set<String> set = new HashSet<String>() ;
System.out.println(set);
//添加元素
/*set.add(null) ;
set.add("hello") ;
set.add("hello") ;
set.add("world") ;
set.add("JavaEE") ;
set.add("JavaEE") ;
set.add("world") ;
set.add("hello") ;*/
set.add("hello") ;
set.add("world") ;
set.add("world") ;
set.add("world") ;
set.add("JavaEE") ;
set.add("hello") ;
set.add("hello") ;
set.add("hello") ;
System.out.println(set);
//遍历
for(String s : set){
System.out.println(s);
}
}
}
举例3:
/* 实现一个接口Comparebale
*/
public class Student implements Comparable<Student>{
private String name ;
private int age ;
public Student() {
}
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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student s) {
//gaoyuanyuan,41 :根节点
// 按照学生的年龄从小到大排序
int num = s.age - this.age ; //后面的元素和当前元素节点的元素进行比较
//学生的年龄相同,不一定是同一个人(次要条件)
int num2 = (num==0)? this.name.compareTo(s.name):num ; //String类的compareTo():按照字典顺序比较
//排序条件
return num2 ;
}
}
/* TreeSet集合:
* 基于TreeMap的实现(红黑树结构:自平衡的二叉树结构)
* 自然排序 public TreeSet()
* 比较器排序 public TreeSet(Comparator<? super E> comparator)
* 取决于使用的构造方法!
*/
public class TreeSetDemo {
public static void main(String[] args) {
//现在使用TreeSet集合存储Integer类型元素
TreeSet<Integer> ts = new TreeSet<Integer>() ;//自然排序
//添加元素
ts.add(20) ;
ts.add(17) ;
ts.add(23) ;
ts.add(22) ;
ts.add(21) ;
ts.add(18) ;
ts.add(19) ;
ts.add(24) ;
ts.add(18) ;
//遍历
for(Integer i : ts){
System.out.println(i);
}
}
}
/* 如果我们现在使用TreeSet集合存储自定义对象,并自然排序 应该注意什么?
* 存储自定义对象所在的类必须实现一个接口:Comparable接口:实现自然排序----->
* 必须要给定一个排序的主要条件!
* 现在的主要条件:按照学生的年龄从小到大排序
* 次要条件:
* 学生年龄相同,比较姓名的内容是否相同
* 自然排序:执行无参构造方:TreeSet<E>()
* TreeSet集合:存储元素之后,按照某种规则排序输出! 而规则:题意明确给出"主要条件"
* T
*/
public class TreeSetDemo2 {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>() ;//自然排序
//创建学生对象
Student s1 = new Student("gaoyuanyuan",41) ;
Student s2 = new Student("gaoyuanyuan",35) ;
Student s3 = new Student("gaoyuanyuan",35) ;
Student s4 = new Student("liushishi",45) ;
Student s5 = new Student("zhangsans",35) ;
Student s6 = new Student("wenzhang",34) ;
Student s7 = new Student("lisi",25) ;
Student s8 = new Student("wenzhang",34) ;
Student s9 = new Student("wawo",23) ;
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
ts.add(s8) ;
ts.add(s9) ;
for(Student s : ts){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
举例4:
/* 实现一个接口Comparebale
*/
public class Student implements Comparable<Student>{
private String name ;
private int age ;
public Student() {
}
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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student s) {
//主要条件:按照学生的姓名长度从小到大
int num = this.name.length() - s.name.length() ;
//次要条件:如果姓名长度相同,比较姓名的内容是否一样
int num2 = (num==0)?this.name.compareTo(s.name):num ;
//如果姓名长度相同,姓名内容也一样,比较年龄是否一样
int num3 = (num2==0)? this.age-s.age : num2 ;
return num3 ;
}
}
/* TreeSet<Student>:主要条件:按照姓名的长度:从小到大排序 (用自然排序实现)
*/
public class TreeSetTest {
public static void main(String[] args) {
//创建TreeSet集合对象
TreeSet<Student> ts = new TreeSet<Student>() ;
//创建学生对象
Student s1 = new Student("gaoyuanyuan",41) ;
Student s2 = new Student("gaoyuanyuan",35) ;
Student s3 = new Student("gaoyuanyuan",35) ;
Student s4 = new Student("liushishi",45) ;
Student s5 = new Student("zhangsans",35) ;
Student s6 = new Student("wenzhang",34) ;
Student s7 = new Student("lisi",25) ;
Student s8 = new Student("wenzhang",34) ;
Student s9 = new Student("wawo",23) ;
Student s10 = new Student("wuqilong",34) ;
Student s11 = new Student("fengqingj",38) ;
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
ts.add(s8) ;
ts.add(s9) ;
ts.add(s10) ;
ts.add(s11) ;
for(Student s: ts){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
举例5:
public class Student{
private String name ;
private int age ;
public Student() {
}
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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
/* TreeSet存储自定义对象有两种排序:
* 自然排序---->自定义对象所在类必须实现一个接口:Comparable,重写接口中的compareTo(T t)
* 比较器排序---->
* 方式1:自定义一个类实现Comparator接口,重写接口中的compare(T o1,T o2)
* 方式2:直接使用Comparator接口匿名内部类
*
*/
public class MyCoparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
//s1---->this
//s2---->s
//按照学生的年龄从小到大排序
int num = s1.getAge() - s2.getAge() ;
/**
* 自己分析 次要条件:
* 学生年龄相同,比较姓名的内容是否相同
*/
int num2 = (num==0)?(s1.getName().compareTo(s2.getName())):num ;
return num2;
}
}
/* 一个排序的主要条件!
* 现在的主要条件:按照学生的年龄从小到大排序
*
* 自己分析 次要条件:
* 学生年龄相同,比较姓名的内容是否相同
*
* 使用TreeSet集合的比较器进行排序!
*
* public TreeSet(Comparator comparator):有参构造方法
*
*
*/
public class TreeDemo {
public static void main(String[] args) {
//public TreeSet(Comparator comparator):有参构造方法
//创建TreeSet集合对象TreeSet
//方式1:定义Comparator比较器函数的接口的子实现类
// MyCoparator myCoparator = new MyCoparator() ;
// TreeSet<Student> ts = new TreeSet<Student>(myCoparator) ;
//方式2:接口匿名内部类----本质就是当前Compartor接口的子实现类对象!
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){
@Override
public int compare(Student s1, Student s2) {
//s1---->this
//s2---->s
//按照学生的年龄从小到大排序
int num = s2.getAge() - s1.getAge() ;
/**
* 自己分析 次要条件:
* 学生年龄相同,比较姓名的内容是否相同
*/
int num2 = (num==0)?(s1.getName().compareTo(s2.getName())):num ;
return num2;
}
}) ;
//创建学生对象
Student s1 = new Student("gaoyuanyuan",41) ;
Student s2 = new Student("gaoyuanyuan",35) ;
Student s3 = new Student("gaoyuanyuan",35) ;
Student s4 = new Student("liushishi",45) ;
Student s5 = new Student("zhangsans",35) ;
Student s6 = new Student("wenzhang",34) ;
Student s7 = new Student("lisi",25) ;
Student s8 = new Student("wenzhang",34) ;
Student s9 = new Student("wawo",23) ;
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
ts.add(s8) ;
ts.add(s9) ;
for(Student s : ts){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}