数组与集合
- 在创建Java数组时,数组的长度必需要指定,数组一旦创建好之后,长度不改变,在同一个数组中只能存放同一种类型的数据(基本类型和引用类型)
- 为了使程序能方便的存储和操作数目不固定的一组数据,JDK类库中提供了Java集合,所有的Java集合都在java.util包中,在集合中,只能存放对象的引用,而不能存放基本数据类型
- Java集合主要有3种重要的类型:
- List:是一个有序集合,可以存放重复的数据;
- Set:是一个无序集合,不允许存放重复的数据;
- Map:是一个无序集合,集合中包含一个键对象,一个值对象,键对象不允许重复,值对象可以重复(身份证号码–姓名)
集合整体结构图
Collection和Iterator
- Collection是List和Set的父接口,在Collection中定义了一些主要方法
List接口
- List接口是一个有序集合,可以放入重复数据;
- 下面主要有两个实现:ArrayList和LinkedList,他们都是有顺序的,也就是放进去是什么顺序,取出来还是什么顺序,也就是基于线性存储,可以看作是一个可变的数组
- ArrayList:查询数据比较快,添加和删除数据比较慢(基于可变数组)
- LinkedList:查询数据比较慢,添加和删除数据比较快(基于链表数据结构)
- Vector:Vector已经不建议使用,Vector中的方法都是同步的,效率慢,已经被ArrayList取代
List示例-String类型
public class Test01 {
public static void main(String[] args) {
String s1= new String("zhangsan");
String s2= new String("lisi");
String s3= new String("wangwu");
List l = new ArrayList();
l.add(s1);
l.add(s2);
l.add(s3);
l.remove(1);
// System.out.println(l.size());
// System.out.println(l.contains(s2));
// System.out.println(l.get(0));
// System.out.println(l.get(1));
// for (int i = 0; i < l.size(); i++) {
// System.out.println(l.get(i));
// }
Iterator it = l.iterator(); //迭代器
while(it.hasNext()){
String s =(String) it.next();
System.out.println(s);
}
}
}
遍历集合的方法
Iterator迭代器
Iterator<E> i = list.iterator();
public boolean hasNext();
public E next();
forEach循环
泛型的初步
泛型能更早的发现错误,如类型转换错误,通常在运行期才会发现,如果使用泛型,那么在编译器将会发现,通常错误发现的越早,越容易调试,越容易减少成本
为什么使用泛型
import java.util.*;
public class GenericTest01 {
public static void main(String[] args) {
List l = new ArrayList();
l.add(1);
l.add(2);
l.add(3);
for (Iterator iter=l.iterator(); iter.hasNext();) {
//出现了java.lang.ClassCastException异常
//这种转型错误在运行期被发现了
//错误发现的越早越好,最好在编译器能发现类似的错误
//如果想在编译器发现类似的错误,必须使用泛型
String s = (String)iter.next();
System.out.println(s);
}
}
}
使用泛型解决示例
import java.util.*;
public class GenericTest02 {
public static void main(String[] args) {
List<Integer> l = new ArrayList<Integer>();
l.add(1);
l.add(2);
l.add(3);
//不能将abc放到集合中,因为使用泛型,在编译器就可以返现错误
//l.add("abc");
for (Iterator<Integer> iter=l.iterator(); iter.hasNext();) {
//因为使用泛型,在编译器就可以发现错误
//String s = (String)iter.next();
//使用泛型可以不用进行强制转换
//Integer s = (Integer)iter.next();
//可以直接取得相应的元素,使用泛型返回的是真正的类型
Integer s = iter.next();
System.out.println(s);
}
}
}
List示例-Student类型
class Student {
String no;
String name;
int age;
public Student(String no,String name, int age) {
this.no = no;
this.name = name;
this.age = age;
}
@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;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (no == null) {
if (other.no != null)
return false;
} else if (!no.equals(other.no))
return false;
return true;
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student("001","zs", 15);
Student s2 = new Student("002","ls", 15);
Student s3 = new Student("003","ww", 15);
Student s4 = new Student("003","ww", 15);
List l = new ArrayList();
l.add(s1);
l.add(s2);
l.add(s3);
//针对对象类型,如果要使用contains方法,必须要重写equals
// if(!l.contains(s4)){
// l.add(s4);
// }
//
// System.out.println(l.size());
// for (Object o : l) {
// Student s = (Student)o;
// System.out.println(s.name);
// }
//
// System.out.println(l.contains(s4));
Iterator it = l.iterator();
while(it.hasNext()){
Student s = (Student)it.next();
System.out.println(s.name+":"+s.age);
}
}
}
List排序
void Collections.sort(List);
String person1 = "zhang3"; String person2 = "li4"; String person3 = "wang5"; List<String> list = new ArrayList<>(); list.add(person1); list.add(person2); list.add(person3); Collections.sort(list); Iterator<String> it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); }
Student stu1=new Student("zhang2",20);
Student stu2=new Student("zhang1",10);
Student stu3=new Student("zhang1",30);
List<Student> list1=new ArrayList<Student>();
list1.add(stu1);
list1.add(stu2);
list1.add(stu3);
//由于没有实现Comparable接口,无法通过编译
Collections.sort(list);
Iterator<Student> it=list.iterator();
while(it.hasNext()){
Student student=it.next();
System.out.println(student.getName());
}
- String+8种包装类默认已经实现了Comparable接口
先按年龄排序,再按序号
Student s = (Student)o; int i = this.age - s.age; if(i==0){ return this.no.compareTo(s.no); } return i;
List自定义排序
- Collection类的sort方法有个重载方法:sort(Listlist,Comparator
Comparator示例
- 可以通过实现Comparator自定义排序规则
Camparable和Comparator
- 一个类实现了Camparable接口则表明这个类的对象之间是可以相互比较的,这个类对象组成的集合就可以直接使用sort方法排序,如果集合中使用比较功能,必须保证集合中的数据类型是一致的。
- Comparator可以看成一种算法的实现,将算法和数据分离,Comparator也可以在下面两种环境下使用:
- 1.类没有考虑到比较问题而没有实现Comparable,可以通过Comparator来实现排序而不必改变对象本身
- 2.可以使用多种排序标准,比如升序、降序等
面试题
Set接口
- Set:是一个无序集合,不允许放重复的数据,主要有两个实现类–HashSet和TreeSet
哈希表
- 哈希表是一种数据结构,哈希表能够提供快速存取操作。哈希表是基于数组的,所以也存在缺点,数组一旦创建将不能扩展
- 正常的数组,如果需要查询某个值,需要对数组进行遍历,只是一种线性查找,查找的速度比较慢,如果数组中的元素值和下标能够存在明确的对应关系,那么通过数组元素的值就可以换算出数组元素的下标,通过下标就可以快速定位数组元素,这样的数组就是哈希表。一张哈希表:
HashSet
HashSet中的数据是无序的不可重复的。HashSet按照哈希算法存取数据的,具有非常好的性能,它的工作原理是这样的:当向HashSet中插入数据的时候,他会调用对象的hashCode得到该对象的哈希码,然后根据哈希码计算出该对象插入到集合中的位置
String person1=”zhang3”;
String person2=”li4”;
String person3=”wang5”;Set<String> set1=new HashSet<String>(); set1.add(person1); set1.add(person2); set1.add(person3); Iterator<String> it=set1.iterator(); while(it.hasNext()){ System.out.println(it.next());//输出是没有顺序的 }
HashSet 元素不可重复
String person1="zhang3"; String person2="li4"; String person3="wang5"; String person3="wang5"; Set<String> set1=new HashSet<String>(); set1.add(person1); set1.add(person2); set1.add(person3); set1.add(person4); Iterator<String> it=set1.iterator(); while(it.hasNext()){ System.out.println(it.next()); } zhang3 wang5 li4
HashSet 没有成功的去除重复元素
Student stu1=new Student(“zhang2",20); Student stu2=new Student("zhang1",10); Student stu3=new Student("zhang3",30); Student stu4=new Student("zhang3",30); Set<Student> set2=new HashSet<Student>(); set2.add(stu1); set2.add(stu2); set2.add(stu3); set2.add(stu4); Iterator<Student> it=set2.iterator(); while(it.hasNext()){ Student student=it.next(); System.out.println(student.getName());; }
是重写了Student的equals方法
public class Student1 implements Comparable<Student>{ String name; int age; @Override public boolean equals(Object obj){ System.out.println("equals方法被调用"); if(this==obj) return true; if(obj==null) return false; if(getClass()!=obj.getClass()) return false; Student1 other=(Student1)obj; if(age!=other.age) return false; if(name==null){ if(other.name!=null) return false; }else if(!name.equals(other.name)){ return false; } return true; } }
HashSet 仍然没有成功的去除重复元素,且equals没有调用
Student stu1=new Student("sun2",20); Student stu2=new Student("sun1",10); Student stu3=new Student("sun3",30); Student stu4=new Student("sun3",30); Set<Student> set2=new HashSet<Student>(); set2.add(stu1); set2.add(stu2); set2.add(stu3); set2.add(stu4); Iterator<Student> it=set2.iterator(); while(it.hasNext()){ Student student=it.next(); System.out.println(student.getName());; }
采取HashSet存储对象类型数据,除了重写equals(),还必须要重写了hashCode方法后
@Override public int hashCode() { System.out.println("hashCode方法被调用了"); final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; }
HashSet 怎样存储对象
- Object中定义了 publicinthashCode()
- HashSet怎样存储对象
- 调用hashCode()
- 当发现两个对象hashCode值相同时,再调用equals
- HashCode方法的覆盖建议
- 内容相同的对象,hashCode值一样
- 最佳实践:不要自己提供hashCode值得算法,二是使用IDE自动生成,这是hashCode数学专家提供的算法,更可靠
- hashCode和equals方法最好成对重写,不要只重写一个
TreeSet
- SortedSet接口的实现类
- 可以排序
- 必须:元素实现Comparable接口;或调用TreeSet(Comparator
Map接口
- 常用方法
- key不可以重复、value可以重复
- put(K key,Vvalue);
- get(Object key);
- remove(Object key);
- clear();
- isEmpty();
- size();
HashMap
HashMap的常规使用
Map<String,String> map=new HashMap<>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value2"); map.put("key1","value4");//替换了第一次放入的value1 System.out.println(map.get(“key1”));//value4 System.out.println(map.get("key2")); //value2 System.out.println(map.get("key3")); //value2 System.out.println(map.get(“key8”));//null
- HashMap的key也是通过Hash算法 过滤重复
- Map的key一般都应用String
- 如果想用自己写的类作为key值,那么就必须重写hashCode()方法和equals()方法,而且要保证对象不可变,也就是和String一样,一旦创建了这个对象,就不可修改。
Map的遍历
值遍历
Map<String,String> map=new HashMap<>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value2"); map.put("key1","value4");//替换了第一次放入的value1 Collection<String> collection=map.values(); for(String str:collection){ System.out.println(str); } /* * value2 * value2 * value4 */
键遍历
Map<String,String> map=new HashMap<String,String>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value2"); map.put("key1","value4");//替换了第一次放入的value1 Set<String> set=map.keySet(); for(String str:set){ System.out.println(str); } /* * key3 * key2 * key1 */
键值遍历一
Map<String,String> map=new HashMap<String,String>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value2"); map.put("key1","value4");//替换了第一次放入的value1 Set<String> set=map.keySet(); for(String key:set){ System.out.println(key+":"+map.get(key)); } /* * key3:value2 * key2:value2 * key1:value4 */
键值遍历二
Entry是Map接口的一个内部接口,即子接口。 先有Map集合再有映射关系,是Map集合的内部事务 Map.Entry中存的是映射关系这种数据类型。
Map<String,String> map=new HashMap<String,String>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value2"); map.put("key1","value4");//替换了第一次放入的value1 Set<String> set=map.keySet(); for(Entry<String,String> entry:map.entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue()); } /* * key3:value2 * key2:value2 * key1:value4 */
TreeMap
TreeMap 可以对key应用排序
Map<String,String> map1=new TreeMap<String,String>(); map1.put("b", "value1"); map1.put("d", "value2"); map1.put("c", "value2"); map1.put("a", "value4"); for(Entry<String,String> entry:map.entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue()); } /* * a:value4 * b:value1 * c:value2 * d:value2 */
TreeMap的key是通过Comparable接口 过滤重复 排序,也可以通过Comparator接口的实现类的对象来过滤重复排序
- Map的key一般都应用String多
HashMap与Hashtable
- Hashtable 与 HashMap的区别
Collections工具类
Collections位于java.util包中,提供了一系列实用的方法,如:对集合排序,对集合中的内容查找等
import java.util.*; public class CollectionsTest01 { public static void main(String[] args) { List l = new ArrayList(); l.add(5); l.add(1); l.add(4); l.add(2); for (Iterator iter=l.iterator(); iter.hasNext();) { System.out.println(iter.next()); } System.out.println(“—List排序---"); Collections.sort(l); for (Iterator iter=l.iterator(); iter.hasNext();) { System.out.println(iter.next()); } System.out.println("-----"); Set set = new HashSet(); set.add(10); set.add(1); set.add(4); set.add(9); //不能直接对set排序 //Collections.sort(set); List setList = new ArrayList(set); Collections.sort(setList); for (Iterator iter=setList.iterator(); iter.hasNext();) { System.out.println(iter.next()); } System.out.println(“---二分法查找--"); int index = Collections.binarySearch(setList, 9); System.out.println("index=" + index); System.out.println(“---反转集合元素--"); Collections.reverse(setList); for (Iterator iter=setList.iterator(); iter.hasNext();) { System.out.println(iter.next()); } } }