ArrayList、LinkedList、Vector
它们三都实现了list接口,首先都是有序的、可重复的,可变数组
一.ArrayList:最为常用的list接口实现类
①首先是线程不安全的,所以效率较高
②底层是Object[ ] elementdata 数组,所以适合于多查询的场景
在jdk1.7中:
new ArrayList():默认声明一个长为10的数组
add()方法:添加一个超过容量的对象时,默认的扩容机制是:1.5n(n为原来容量)
在jdk1.8中:
new ArrayList():声明的是Object [ ] elementdata={},再调用的add()方法时才声明其长度,
add()方法的扩容 机制与jdk7相同
二、ArrayList的常用方法
1.增add(Object )2.删 remove(Objcet o) \ remove(int index)3.改 set(int index,Objcet o)
4.查 get(int index) 5.插 add(int index,Object o) 6.个数 size() 7.遍历 for\foreach\iterator
@Test
public void test1() {
// 1.增 add
ArrayList list=new ArrayList();
list.add(123);
list.add("abc");
list.add(456);
list.add("def");
System.out.println(list);
//2.删 remove(Object o)/remove(int index)
list.remove(0);
list.remove("abc");
System.out.println(list);
//3.改set(int index,Object o)
list.set(0, 789);
System.out.println(list);
//4.查 get(int index)
System.out.println(list.get(1));
}
@Test
public void test2() {
//5.插 add(int index ,Object o)
ArrayList list=new ArrayList();
list.add(123);
list.add("abc");
list.add(456);
list.add(1, "hhhhhhhhh");
System.out.println(list);
//6.返回添加元素的个数:size
System.out.println(list.size());
//7.遍历
for(int i=0;i<list.size();i++) {
System.out.print(list.get(i)+"\t");
}
System.out.println();
for(Object l1:list) {
System.out.print(l1+"\t");
}
System.out.println();
Iterator iterator=list.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next()+"\t");
}
}
三、LinkedList:线程不安全的,效率较高,底层是双链表结构,适合于多插入、删除的场景
四、Vector:较为古老的list实现类
1.线程安全的,效率较低
2.底层是数组,new Vector():默认声明一个长度为10的数组 add():扩容机制为2n(n为原来的两倍)
五、HashSet、LinkedHashSet、TreeSet
首先实现set接口,都是无序的、不可重复
如何解释无序性?
存放的元素的位置都是根据hash值算出来的,所以存放的位置是无序的
六、HashSet:线程不安全的,可以存放null
HashSet的底层实现:数组+链表
当HashSet添加元素时,根据元素所属类的hashCode方法获取hash值,将得到的hash值根据相应的算法算出对应数组中的位置。情况1:如果数组中此位置没有元素,则直接添加。情况2:否则,需要根据元素所属类的equals方法进行比较,返回true添加失败,返回false添加成功。
在jdk1.7中,情况二时,将需要添加的元素添加到数组中并指向原来数组中该位置上的元素
在jdk1.8中,情况二时,将数组中该位置上的元素指向需要添加的元素
HashSet set=new HashSet();
set.add(123);
set.add("abc");
set.add(456);
set.add("def");
set.add(null);
System.out.println(set);
七、LinkedHashSet:作为HashSet的子类,可以根据添加顺序进行输出
底层:数组+双链表 前一引用指向上一个添加元素的地址,后一个引用指向下一个添加元素的地址
LinkedHashSet linkedSet=new LinkedHashSet();
linkedSet.add("uio");
linkedSet.add(8888);
linkedSet.add("qwe");
for(Object o:linkedSet) {
System.out.print(o+"\t");
}
八、TreeSet:
1.可以根据添加对象的属性,进行排序(根据Comparable、Comparator进行排序)
2.必须添加相同类型的元素
TreeSet treeSet=new TreeSet();
treeSet.add(new Student("黄晓明",38));
treeSet.add(new Student("范冰冰",18));
treeSet.add(new Student("刘亦菲",25));
Iterator i=treeSet.iterator();
while(i.hasNext()) {
System.out.print(i.next()+"\t");
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;
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
return age == other.age && Objects.equals(name, other.name);
}
}
实现Comparable接口进行自然排序:
TreeSet treeSet=new TreeSet();
treeSet.add(new Student("HXM",38));
treeSet.add(new Student("FBB",18));
treeSet.add(new Student("FBB",20));
treeSet.add(new Student("LYF",25));
Iterator i=treeSet.iterator();
while(i.hasNext()) {
System.out.print(i.next()+"\t");
}
class Student implements Comparable{
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;
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
return age == other.age && Objects.equals(name, other.name);
}
@Override
public int compareTo(Object o) {
// TODO 自动生成的方法存根
// return 0;
if(o instanceof Student) {
Student s=(Student) o;
if(this.name.compareTo(s.name)==0) {
if(this.age>s.age) {
return 1;
}else if(this.age<s.age) {
return -1;
}else {
return 0;
}
}else {
return this.name.compareTo(s.name);
}
}else {
throw new RuntimeException("输入数据异常");
}
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
使用Comparator工具类:
Comparator comparator=new Comparator() {
@Override
public int compare(Object o1, Object o2) {
// TODO 自动生成的方法存根
//姓名从大到小,年龄从大到小
if(o1 instanceof Student && o2 instanceof Student) {
Student s1=(Student)o1;
Student s2=(Student)o2;
if(s1.getName().compareTo(s2.getName())==0)
{
if(s1.getAge()>s2.getAge()) {
return -1;
}else if(s1.getAge()<s2.getAge()) {
return 1;
}else {
return 0;
}
}else {
return -s1.getName().compareTo(s2.getName());
}
}else {
throw new RuntimeException("输入数据异常");
}
}
};
TreeSet treeSet=new TreeSet(comparator);
treeSet.add(new Student("HXM",38));
treeSet.add(new Student("FBB",18));
treeSet.add(new Student("FBB",20));
treeSet.add(new Student("LYF",25));
Iterator i=treeSet.iterator();
while(i.hasNext()) {
System.out.print(i.next()+"\t");
}
九、面试题
public class test {
public void method1(List list) {
list.remove(2);
}
public void method2(List list) {
list.remove(new Integer(2));
}
@Test
public void test1() {
ArrayList list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
method1(list);
System.out.println(list); //[1,2]
//考察知识点: remove(int index) remove(Object o)
//显然:method1中的remove方法的形参是下标
method2(list);
System.out.println(list); //[1] remove 删除对象要用new
}
}
//去除list中的重复元素,效率越高越好
public void method3(List list) {
HashSet set=new HashSet();
set.addAll(list);
list.clear();
list.addAll(set);
}
@Test
public void test2() {
ArrayList list=new ArrayList();
list.add(123);
list.add("abc");
list.add(123);
list.add("abc");
method3(list);
System.out.println(list);
}
public void test3() {
HashSet set=new HashSet();
Person p1=new Person(1001,"AA");
Person p2=new Person(1002,"BB");
p1.setName("CC");
set.add(p1);
set.add(p2);
set.remove(p1);
// System.out.println(set.remove(p1));
System.out.println(set); //[Person [1001,CC] , Person [1002,BB]]
set.add(new Person(1001,"CC"));
System.out.println(set);
set.add(new Person(1001,"AA"));
System.out.println(set);
/*
* p1是以(1001,"AA")计算出的hash值并得到的数组坐标,remove(p1)是以(1001,CC)计算出hash值并得到相应数组的坐标。
* 因此,(1001,CC)对应的下标上没有元素所以删除失败
* 同样的,以(1001,CC)计算出的hash值得到的下标中没有元素,添加成功
* (1001,AA)计算出的hash值得到的下标,并添加元素(1001,AA)后改为(1001,CC)
* 再次添加(1001,AA)时,虽然根据hash值得出的下标一致,但是通过equals方法比较的结果为false,以链表的方式添加成功
*
*/
}
class Person{
private int id;
private String name;
public Person() {
super();
}
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
return id == other.id && Objects.equals(name, other.name);
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}