List接口
java.util.List
接口继承自Collection
接口,
List接口特点:
1、有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123)
2、有索引,包含了一些带索引的方法
3、允许存储重复的元素
List接口中常用方法
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。public E get(int index)
:返回集合中指定位置的元素。public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
public class ListDemo {
public static void main(String[] args) {
// 创建List集合对象
List<String> list = new ArrayList<String>();
// 往 尾部添加 指定元素
list.add("图图");
list.add("小美");
list.add("不高兴");
System.out.println(list);
// add(int index,String s) 往指定位置添加
list.add(1,"没头脑");
System.out.println(list);
// String remove(int index) 删除指定位置元素 返回被删除元素
// 删除索引位置为2的元素
System.out.println("删除索引位置为2的元素");
System.out.println(list.remove(2));
System.out.println(list);
// String set(int index,String s)
// 在指定位置 进行 元素替代(改)
// 修改指定位置元素
list.set(0, "三毛");
System.out.println(list);
// String get(int index) 获取指定位置元素
// 跟size() 方法一起用 来 遍历的
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
//还可以使用增强for
for (String string : list) {
System.out.println(string);
}
}
}
List的子类
ArrayList集合
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快。
1、存储结构为数组
2、查询快,增删慢
常用方法和list一样
LinkedList集合
java.util.LinkedList
集合数据存储的结构是链表结构。方便元素添加、删除的集合
1、存储结构为链表结构
2、增删快,查询慢
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可:
public void addFirst(E e)
:将指定元素插入此列表的开头。
相当于 push()
public void addLast(E e)
:将指定元素添加到此列表的结尾。
相当于add
-
public E getFirst()
:返回此列表的第一个元素。 -
public E getLast()
:返回此列表的最后一个元素。 -
public E removeFirst()
:移除并返回此列表的第一个元素。
相当于 pop()
-
public E removeLast()
:移除并返回此列表的最后一个元素。 -
public E pop()
:从此列表所表示的堆栈处弹出一个元素。 -
public void push(E e)
:将元素推入此列表所表示的堆栈。 -
public boolean isEmpty()
:如果列表不包含元素,则返回true。
package com.itheima_List;
import java.util.LinkedList;
public class LinkedListDemo01 {
public static void main(String[] args) {
LinkedList<String> link=new LinkedList<>();
link.add("a");
link.add("b");
link.add("v");
//开头,结尾插元素
link.addFirst("uu");
link.addLast("ooo");
System.out.println(link); //[uu, a, b, v, ooo]
//public E pop()`:从此列表所表示的堆栈处弹出一个元素。
System.out.println(link.pop()); //uu
System.out.println(link); //[a, b, v, ooo]
//`public E getFirst()`:返回此列表的第一个元素。
System.out.println(link.getFirst()); //a
//push(E e)`:将元素推入此列表所表示的堆栈
link.push("haha");
System.out.println(link); //[haha, a, b, v, ooo]
}
}
Set接口
java.util.Set
接口和java.util.List
接口一样,同样继承自Collection
接口,它与Collection
接口中的方法基本一致。
Set接口的特点:
1、Set接口中存入的元素不出现重复
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3、Set接口中元素无序
HashSet集合
java.util.HashSet
是implement Set接口
HashSet特点:
1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历(可以使用迭代器和增强for)
3、是一个无序的集合,存储的元素和取出的元素的顺序有可能不一致
4、底层是一个哈希表结构(查询的速度非常的快)
package com.itheima_Set;
import java.util.HashSet;
import java.util.Iterator;
public class SetDemo01 {
public static void main(String[] args) {
HashSet<Integer> hashSet=new HashSet<>();
hashSet.add(12);
hashSet.add(23);
hashSet.add(12);
hashSet.add(9);
//用迭代器遍历输出
Iterator<Integer> it = hashSet.iterator();
while (it.hasNext()){
Integer i = it.next();
System.out.println(i); //23,9,12 重复元素未存入
}
System.out.println("------");
//使用增强for遍历
for(Integer i:hashSet){
System.out.println(i); //23,9,12
}
}
}
HashSet集合存储数据的结构(哈希表)
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值
int hashCode() 返回该对象的哈希码值
hashCode方法的源码:
public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
字符串类的哈希值
String类重写了Object类的hashCode方法
哈希表
jdk1.8版本之前:哈希表=数组+链表
jdk1.8版本之后:哈希表=数组+红黑树(提高查询的速度)
哈希表的特点:速度快
数组结构:把元素进行了分组(相同哈希值的元素时一组)
链表/红黑树结构:把相同哈希值的元素连接到一起
Set集合存储元素不重复的原理
前提:存储的元素必须重写hashCode方法和equals方法
Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals方法,判断元素是否重复(先比较哈希值,当哈希值相等时,在调用equals方法比较元素是否相同,再决定是否要存储该元素)
当哈希值相等,调用equals方法还返回true,则二者只存储一个
HashSet存储自定义类型元素
Set集合保证元素唯一:
存储的元素(String,Integer,…Student,Person…),必须重写hashCode方法和equals方法
例如:用HashSet 存储Person,且要求同名字同年龄的人视为同一个人,只能存储一次
package com.itheima_Set;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写equals和hashCode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package com.itheima_Set;
import java.util.HashSet;
public class SetDemo02 {
public static void main(String[] args) {
HashSet<Person> hashSet=new HashSet<>();
Person p1=new Person("浩浩",11);
Person p2=new Person("昊昊",11);
Person p3=new Person("昊昊",11);
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
System.out.println(hashSet); //[Person{name='昊昊', age=11}, Person{name='浩浩', age=11}]
}
}
LinkedHashSet集合
java.util.linkedHashSet集合 extends HashSet 集合
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表,多了一个链表(记录元素的存储顺序),保证有序
package com.itheima_Set;
import java.util.HashSet;
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
public static void main(String[] args) {
HashSet<String> hashSet=new HashSet<>();
hashSet.add("aaa");
hashSet.add("ooo");
hashSet.add("bbb");
hashSet.add("ccc");
hashSet.add("aaa");
System.out.println(hashSet); //[aaa, ccc, bbb, ooo]无序,且不允许重复
LinkedHashSet<String> linked=new LinkedHashSet<>();
linked.add("aaa");
linked.add("ooo");
linked.add("bbb");
linked.add("ccc");
linked.add("aaa");
System.out.println(linked); //[aaa, ooo, bbb, ccc] 有序,但也不允许重复
}
}
可变参数
是jdk1.5之后出现的新特性
使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型...变量名){}
可变参数的原理:
可变参数底层是一个数组,根据传递参数个数不同,会创建不同长度的数组来存储这些参数。传递的参数个数可以是0个(不传递),1,2,3…多个
package com.itheima_Set;
/*
* 计算(0-n)整数和的方法
* 已知:计算整数的和,不知道要计算几个整数的和,就可以使用可变参数
* */
public class VarArgsDemo {
public static void main(String[] args) {
int result=sum(0,1,2,3,4,5);
System.out.println(result);//15
int s1=sum(1,2);
System.out.println(s1);//3
int s=sum();
System.out.println(s); //0,创建长度为0的数组
}
public static int sum(int...arr){
int s=0;
for(int i:arr){
s+=i;
}
//System.out.println(arr.length);
return s;
}
}
可变参数的注意事项:
1、一个方法的参数列表只能有一个可变参数
2、如果方法的参数有多个,那么可变参数必须写在参数列表的末尾