集合
集合的数目是可变的,并且集合只能存储引用数据类型,不能存放基本数据类型.
数组的长度不可变,数组既可以存放基本数据类型,又可以存放引用数据类型.
集合类的继承关系:
java.util.Collection是集合类的顶层接口,Collection使用泛型技术.
使用建议:
- 保存自定义对象的时候使用List接口;
- 保存系统类信息的时候使用Set接口(避免重复)
List接口
List接口在集合中被作为首选,因为List接口相比于Collection接口有一个get方法,可以根据索引取得内容.
List集合允许有重复的元素
List接口的常用方法:
1.在结合指定位置插入一个元素
public void add(int index,E element)
2.在集合指定位置插入集合c的所有元素
public boolean addAll(int index,Collection<? extends E> c)
3.返回集合中指定位置的元素
public E get(int index)
4.返回集合中首次出现指定元素的索引,如果没有,返回-1.
public int indexOf(Object o)
5.返回列表中最后出现指定元素的索引,不包含返回-1.
public int lastIndexOf(Object o)
6.为ListIterator接口实例化,用于遍历集合中的元素.
public ListIterator<E> listIterator()
7.删除集合中指定位置的元素
public E remove(int index)
8.返回新的元素新的集合中包含start不包含end 的所有元素.
public List<E> subList(int fromIndex, int toIndex)
9.返回此列表中的元素数
public int size()
List方法应用
public class AddTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//向集合中添加元素
list.add("1");
list.add(1,"2");//向当前集合索引为1的位置添加元素
list.add("3");
list.add("4");
list.add("5");
System.out.println("List集合:"+list);
//向集合中的指定位置添加元素
list.add(0,"0");
list.add(0,"0");
System.out.println(list);
Collection<String> collection=new ArrayList<>();
collection.add("00");
collection.add("01");
collection.add("02");
//给集合中添加一个集合的所有内容,
// 若不指定位置,则在当前集合的最后依次添加
//向当前集合添加的集合,元素类型必须保持一致(当前都为String)
list.addAll(collection);
System.out.println(list);
//删除元素
list.removeAll(collection);//删除当前集合中指定集合的元素
list.remove(2);//删除索引为2的元素
list.remove("0");//删除内容为"00"的元素
System.out.println(list);//-->[0, 2, 3, 4, 5]
}
}
1.ArrayList类
ArrayList类是List的实现类,可以通过 ArrayList为List接口实例化, ArrayList是数组列表类,实现了可变长度的数组,允许对集合中的元素进行快速访问,但向ArrayList集合中插入或删除速度较慢.
ArrayList集合的新增方法:
1.如果需要,增加此 ArrayList实例的容量,以确保它可以至少保存最小容量参数指定的元素数
public void ensureCapacity(int minCapacity)
2.从这个列表中删除所有索引在 fromIndex (含)和 toIndex之间的元素
protected void removeRange(int fromIndex, int toIndex)
3.修改这个 ArrayList实例的容量是列表的当前大小。
public void trimToSize()
public static void main(String[] args) {
List<Integer> list=new ArrayList<>() ;
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.isEmpty());
System.out.println(list.contains("a"));
//通过调用集合的对象,可以打印出集合元素
System.out.println(list);
//通过for循环打印集合
for(int i=0;i<list.size();i++){
System.out.print(list.get(i));
}
System.out.println("----------------------");
//通过迭代方法打印集合,正向遍历
ListIterator<Integer> iterator=list.listIterator();
while(iterator.hasNext()){
System.out.print(iterator.next());
}
System.out.println(">>>>>>>>>>>");
//通过迭代方法打印集合,反向遍历
while(iterator.hasPrevious()){//此时游标已经移到了最末尾
System.out.print(iterator.previous());
System.out.print(" -> ");
}
//通过对象数组接收集合元素,foreach打印集合
//1.使用toArray方法需要强转(Collection接口中的内容),不推荐
//Integer[] integers1=(Integer[])list.toArray();//toArray, 返回值是Object[]
//2.优化toArray方法
Integer[] integers=new Integer[list.size()];
list.toArray(integers);
for(Integer i:integers){
System.out.println(i);;
}
向集合中保存简单的java类对象
public class SaveObject {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("jack",12));
people.add(new Person("jay",23));
people.add(new Person("Alice",33));
System.out.println(people);
//使用覆写的equals方法,返回值就为true
//equals方法与hashCode方法要一起覆写
//若不同时覆写,其hashCode的值依然不同,
// 在Map中,KEY的值由hashCode决定,因此会造成有相同的元素出现.
System.out.println(people.contains(new Person("jack", 12)));
people.remove(2);
}
}
class Person{
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//手工完成
//@Override
// public boolean equals(Object obj){
// if(obj==null){
// return false ;
// }
// if(this==obj){
// return true;
// }
// if(obj instanceof Person){
// Person that=(Person)obj;
// return this.getName().equals(that.getName()) &&
// this.getAge().equals(that.getAge());
// }
// return false;
//}
//工具生成
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (!name.equals(person.name)) return false;
return age.equals(person.age);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age.hashCode();
return result;
}
}
2.Vector
Vector类是从JDK1.0就提出了的,其方法继承了List的方法,与ArrayList使用基本相同.
请解释ArrayList与Vector区别
1.历史时间:ArrayList是从JDK1.2提供的,而Vector是从JDK1.0就提供了。
2. 处理形式:ArrayList是异步处理,性能更高;Vector是同步处理,性能较低。
3. 数据安全:ArrayList是非线程安全;Vector是线程安全。
4. 输出形式:ArrayList支持Iterator、ListIterator、foreach;Vector支持Iterator(也是一个接口)、ListIterator、 foreach、Enumeration 。
//Enumeration已经不使用了,目前输出集合首选迭代器
public class VectorTest {
public static void main(String[] args) {
List<String> vector=new Vector<>();
vector.add("hello");
vector.add("java");
vector.add("!!!");
//已弃用
Enumeration<String> enumeration=((Vector<String>) vector).elements();
System.out.println(enumeration);
//主要使用迭代器遍历输出集合
Iterator<String> iterator=vector.listIterator();
while (iterator.hasNext()){
((ListIterator<String>) iterator).add("---");
//修改集合元素不能在迭代之前,会报错
// ((ListIterator<String>) iterator).set("34");//error
System.out.println(iterator.next()+",");
//修改集合元素必须在遍历之后
((ListIterator<String>) iterator).set("***");
((ListIterator<String>) iterator).add("+");
}
for(int i=0,len=vector.size();i<len;i++){
System.out.println(vector.get(i));
// vector.add("sm");//添加删除操作不能在当前遍历打印下起作用
}
}
}
3. LinkedList类
LinkedList是一种链表实现
ArrayList与LinkedList的区别:
1.ArrayList里面存放的是一个数组
2.ArrayList的默认无参构造方法实例化,存储数据初始化是在第一次添加元素时进行的(lazy load)–扩容50%–默认容量10
3.ArrayList的初始容量的构造方法实例化,存储数据的数组立即初始化.
如果实例化此类对象时传入了数组大 小,则里面保存的数组就会开辟一个定长的数组,但是后面再进行数据保存的时候发现数组个数不够了 会进行数组动态扩充。 所以在实际开发之中,使用ArrayList最好的做法就是设置初始化大小。
set集合接口
set接口与list接口最大的不同在于set接口中的内容是不允许重复的,且set接口没有get()方法.set接口的两个子类:
- HashSet是无序存储
- Treeset是有序存储.
1.HashSet
HashSet的重复元素判断依赖于equals方法和hashCode方法。如果想要标识出对象的唯一性,一定需要equals方法和hashCode方法共同调用,只有当对象的equals方法和hashCode都相同时,才会将其判断为相同的对象。
public class HashSetTest {
public static void main(String[] args) {
Set set<String>=new HashSet<>();
set.add("hello");
set.add("bit");
set.add("hello");
set.add("java");
System.out.println(set);
}
}
运行结果:[java, hello, bit]
2.TreeSet
TreeSet的重复元素判断依赖于Comparable接口,因此利用TreeSet集合存储数据的数据类型必须实现Comparable接口
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("java");
set.add("hello");
set.add("java");
set.add("best");
System.out.println(set);
}
运行结果:[best, hello, java]
若需要TreeSet对指定普通泛型排序,就需要对对象数组进行排序,而对对象数组进行排序
TreeSet排序分析
TreeSet通过泛型指定数据类型,因此实质上TreeSet的排序是对对象数组(每一个类都是特殊的数据类型)进行的排序处理,因此要想实现排序,此类就得实现Comparable接口并且覆写compareTo方法(有必要覆写equals和hashCode方法)
方法一:在TreeSet的实例化对象构造方法中传入接口参数,利用匿名内部类或是lambda表达式实现Comparator接口
Set<Student> students=new TreeSet<>(
new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
}
);
// Set<Student> students=new TreeSet<>(
// (o1, o2) -> o1.getAge()-o2.getAge()
// );
students.add(new Student(12, "liu"));
students.add(new Student(13, "wang"));
students.add(new Student(24, "wang"));
students.add(new Student(14, "li"));
System.out.println(students);
//自定义数据类型
class Student{
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
方法二:自定义数据类型通过实现接口实现排序
class Person implements Comparable<Person>{
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public int compareTo(Person o) {
return this.age-o.getAge();//覆写compareTo方法定义比较策略
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//若想改变比较策略,可通过将TreeSet对象传入Comparator接口的方法改变
//这样改变的方法灵活,不需要去数据类型的内部改变compareTo方法
Set<Person> people1=new TreeSet<>(
new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return (o1.getName()).compareTo(o2.getName());
}
}
);