8.3.3 泛型接口
如果接口中的方法的参数(形参、返回值)不确定时,可以考虑使用泛型接口。形式
public interface FanInterface {
public void showInfo(T t);
}
[1]实现类能确定泛型接口的类型
public class ImplClass implements FanInterface{
public void showInfo(String t) {
}
}
[2]实现类不能确定泛型接口的类型->继续泛。
public class ImplClass2 implements FanInterface{
public void showInfo(T t) {
}
}
8.3.4 泛型的上限和下限
public static void print(ArrayList extends Pet> list) {
for (Pet pet : list) {
pet.showInfo();
}
}
泛型的上限ArrayList(? extends Pet) list 声明了一个容器,容器中的元素类型一定要继承于Pet,我们称这种形式叫做泛型的上限。
泛型的下限ArrayList(? super Pet) list 声明了一个容器,容器中的元素类型一定要是Pet的父类,我们称这个形式为泛型的下限。
9. Set接口
Set接口表示一个唯一、无序的容器(和添加顺序无关)
9.1 Set接口提供的方法
public static void main(String[] args) {
/*** 增:add/addAll* 删:clear/remove/removeAll/retainAll* 改:* 查:contains/containsAll* 遍历:iterator* 其他:size/isEmpty*/
Set set = new HashSet();
// [1]添加// 无序set.add(10);
set.add(3);
set.add(20);
set.add(0);
// 不能添加重复元素boolean r = set.add(1);
System.out.println(r);//tureSystem.out.println(set);//[0, 1, 3, 20, 10]
// 【2】删除//set.remove(1);//set.clear();//System.out.println(set);
// 【3】查看是否包含System.out.println(set.contains(1));//true
// 【4】其他System.out.println(set.size());//5System.out.println(set.isEmpty());//false}
9.2 Set接口的遍历
public static void main(String[] args) {
Set set = new HashSet();
set.add("banana");
set.add("apple");
set.add("coco");
// 快速遍历for (String item : set) {
System.out.println(item);
}
// 迭代器Iterator it = set.iterator();
while(it.hasNext()) {
String item = it.next();
System.out.println(item);
}
}
Set接口的实现类常见的有HashSet、LinkedHashSet、TreeSet。
10. HashSet
HashSet是Set接口的实现类,底层数据结构是哈希表。
HashSet是线程不安全的(不保证同步)
10.1 哈希表工作原理
10.2 添加自定义对象
根据哈希表的工作原理,请存储一个自定义对象到HashSet中。
package cn.sxt03.hashset;
public class Student {
private String id;
private String name;
private int age;
// …
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@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 (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
总结:
[1]如果向HashSet中存储元素时,元素一定要实现hashCode方法和equals方法。
[2] 优点:添加、删除、查询效率高;缺点:无序
11. LinkedHashSet
LinkedHashSet是Set接口的实现类,底层数据结构哈希表+链表
哈希表用于散列元素;链表用于维持添加顺序。
如果要添加自定义对象元素,也需要重写hashCode和equals方法
12. TreeSet
TreeSet 是Set接口的实现类,底层数据结构是二叉树。
TreeSet 存储的数据按照一定的规则存储。存储规则让数据表现出自然顺序。
12.1 TreeSet工作原理
添加一个新元素t的存储的步骤
[1] 如果集合无元素,t直接加入;如果集合有元素,t和根节点比较;[2] 如果t小于根节点;把t放到根节点的左子树上;重复1-3步骤;[3] t大于根节点;把t放到根节点的右子树上;重复1-3步骤
输出时按照一定的规则:左子树->根节点->右子树
根据TreeSet的工作原理,向TreeSet添加自定义元素。
向TreeSet中添加元素时,一定要提供比较策略,否则会出现ClassCastException(类转换异常)。
比较策略分两种:内部比较器和外部比较器
12.2 内部比较器
当一个自定义对象实现Comparable并实现compareTo方法时,通过指定具体的比较策略,此时称为内部比较器。
package cn.sxt05.treeset;
public class Student implements Comparable{
private String id;
private String name;
private int age;
// 。。。
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student o) {
if(this.getAge()
return -1;
}else if(this.getAge() == o.getAge()) {
return 0;
}else {
return 1;
}
}
}
比较策略的几种情况
[1]比较策略一般当前对象写在前面,待比较对象也在后面,比较结果默认升序。
return this.getAge() - o.getAge() ;
如果想要降序,改变两个比较对象的位置即可。
[2] 多种比较因素
public int compareTo(Student o) {
/*if(this.getAge()
// return this.getAge() - o.getAge() ;
if(this.getAge()
return -1;
}else if(this.getAge() == o.getAge()) {
return this.getName().compareTo(o.getName());
}else {
return 1;
}
}
12.3 外部比较器
当实际开发过程中不知道添加元素的源代码、无权修改别人的代码,此时可以使用外部比较器。
Comparator 位于java.util包中,定义了compare(o1,o2) 用于提供外部比较策略。
TreeSet接受一个指定比较策略的构造方法,这些比较策略的实现类必须实现Comparator
接口。
需求:按照字符串的长度比较
public class Test01 {
public static void main(String[] args) {
LenComparator lenComparator = new LenComparator();
TreeSet set2 = new TreeSet(lenComparator);
set2.add("banana");
set2.add("coco");
set2.add("apple");
set2.add("apple");
System.out.println(set2);
}
}
class LenComparator implements Comparator{
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
使用匿名内部类优化
public class Test02 {
public static void main(String[] args) {
TreeSet set2 = new TreeSet(new Comparator() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
set2.add("banana");
set2.add("coco");
set2.add("apple");
set2.add("apple");
System.out.println(set2);//[coco, apple, banana]}
}
Collection总结:
13. Map接口
Map接口称为键值对集合或者映射集合,其中的元素(entry)是以键值对(key-value)的形式存在。
Map 容器接口中提供了增、删、改、查的方式对集合进行操作。
Map接口中都是通过key来操作键值对,一般key是已知。通过key获取value。
13.1 Map常用方法
public static void main(String[] args) {
/*** 增:put/putAll* 删:clear/remove* 改:put* 查:get/containsKey/containsValue* 其他:isEmpty/size*/
Map map = new HashMap();
// 【1】putmap.put("A", "apple");
map.put("B", "banana");
map.put("C", "coco");
// 【2】删除// map.clear();// smap.remove("A");
// 【3】修改//map.put("A", "apple x");
// 【4】查看String val = map.get("A");
System.out.println(map.containsKey("D"));
System.out.println(map);
}
13.2 map接口的遍历
通过keySet() 返回map中键的set集合。
public static void main(String[] args) {
Map map = new HashMap();
map.put("B", "banana");
map.put("A", "apple");
map.put("C", "coco");
// map无序// 可以根据key的自然顺序 让map有序 => 一般用string作为keySystem.out.println(map);//{A=apple, B=banana, C=coco}
// 遍历Set keys = map.keySet();
for (String key : keys) {
System.out.println(key+"=>"+map.get(key));
}
Iterator it = keys.iterator();
while(it.hasNext()) {
String key = it.next();
System.out.println(key+"=>"+map.get(key));
}
}
map中以键值对作为元素,键值对在map中称为entry,entrySet返回键值对的set集合。
public static void main(String[] args) {
Map map = new HashMap();
map.put("B", "banana");
map.put("A", "apple");
map.put("C", "coco");
// map无序// 可以根据key的自然顺序 让map有序 => 一般用string作为keySystem.out.println(map);
// entrySetSet> entrySet = map.entrySet();
for (Entry entry : entrySet) {
System.out.println(entry.getKey()+"=>"+entry.getValue());
}
Iterator> it2 = entrySet.iterator();
while(it2.hasNext()) {
Entry entry = it2.next();
System.out.println(entry.getKey()+"=>"+entry.getValue());
}
}
Map接口的实现类HashMap、LinkedHashMap、TreeMap
14. HashMap
HashMap 是Map的实现类,key以HashSet存储。
public static void main(String[] args) {
/*HashMap map = new HashMap();ArrayList list1 = new ArrayList();list1.add("alex");list1.add("alice");list1.add("allen");map.put("A", list1);ArrayList list2 = new ArrayList();list2.add("ben");list2.add("bill");map.put("B", list2);System.out.println(map);*/
HashMap map = new HashMap();
ArrayList list1 = new ArrayList();
list1.add("alex");
list1.add("alice");
list1.add("allen");
Student s1 = new Student("001", "大狗", 20);
map.put(s1, list1);
ArrayList list2 = new ArrayList();
list2.add("ben");
list2.add("bill");
Student s2 = new Student("001", "大狗", 20);
// 修改map.put(s2, list2);
System.out.println(map);
}
总结:
[1] 向HashMap中存储元素时,key一定要实现hashCode和equals。
[2] 一般建议使用String作为Map接口的key。
15. LinkedHashMap
LinkedHashMap是Map接口的实现类,key以LinkedHashSet存储。
哈希表散列key,链表维持key的添加顺序。
public static void main(String[] args) {
/*LinkedHashMap map = new LinkedHashMap();ArrayList list2 = new ArrayList();list2.add("ben");list2.add("bill");map.put("B", list2);ArrayList list1 = new ArrayList();list1.add("alex");list1.add("alice");list1.add("allen");map.put("A", list1);System.out.println(map);*/
HashMap map = new HashMap();
ArrayList list1 = new ArrayList();
list1.add("alex");
list1.add("alice");
list1.add("allen");
Student s1 = new Student("001", "大狗", 20);
map.put(s1, list1);
ArrayList list2 = new ArrayList();
list2.add("ben");
list2.add("bill");
Student s2 = new Student("001", "大狗", 20);
// 修改map.put(s2, list2);
System.out.println(map);
}
16. TreeMap
TreeMap是Map的实现类,key以TreeSet存储。
public static void main(String[] args) {
/*TreeMap map = new TreeMap(new Comparator() {@Overridepublic int compare(String o1, String o2) {return o1.length() - o2.length();}});ArrayList list2 = new ArrayList();list2.add("ben");list2.add("bill");map.put("Aa", list2);ArrayList list1 = new ArrayList();list1.add("alex");list1.add("alice");list1.add("allen");map.put("B", list1);System.out.println(map);*/
TreeMap map = new TreeMap(new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
ArrayList list1 = new ArrayList();
list1.add("alex");
list1.add("alice");
list1.add("allen");
Student s1 = new Student("001", "大狗", 20);
map.put(s1, list1);
ArrayList list2 = new ArrayList();
list2.add("ben");
list2.add("bill");
Student s2 = new Student("001", "2狗", 20);
// 修改map.put(s2, list2);
System.out.println(map);
}
17. 总结