文章目录
传送门:
07 JAVA容器
1.容器概念
如果并不知道程序运行会需要多少对象,或者需要更复杂方式存储对象,就需要使用Java集合框架。
2.容器API
Java集合框架提供了一套性能优良、使用方便的接口和类,位于java.util
包中。其中,Collection接口存放单一数据;Map接口存放键值对(k-v)数据。
Collection接口:
-
子接口
-
List
- ArrayList
- LinkedList
-
Set
- HashSet
- TreeSet
-
-
迭代器
- Iterator接口
- Iterable接口
- 增强for循环
-
比较器:当存储某些元素的时候,需要对集合中的元素进行排序,此时需要比较器
- 内部比较器:Comparable接口
- 外部比较器:Comparator接口
-
泛型
- 泛型类
- 泛型接口
- 泛型方法
-
数据结构
- 数组
- 链表
- 哈希表
- 红黑树
3.Collection接口
集合作为容器应该具有(不一定全有)的功能:增删改查。Collection接口存储一组不唯一、无序的对象。集合的基本操作有:增加、删除、判断、取出。
/*
* java集合框架:
* Collection:存放单一的值
* 特点:
* 1.可以存放不同类型的数据,而数组只能存放固定类型的数据
* 2.当使用ArrayList子类实现的时候,初始化长度为10,当长度不够的时候使用grow方法自动进行扩容操作
*
* api方法:
* 增加:
* add:要求必须传入的参数为Object对象,因此,当写入基本数据类型的时候包含了自动拆箱和自动装箱的过程
* addAll:添加另一个集合的元素到此集合中
* 删除:
* clear:只是清空集合中的元素,但是此集合对象并没有被回收
* remove:删除指定元素
* removeAll:从此集合中删除指定集合中包含的所有元素
* removeIf:从集合中删除给定预期的所有元素
* 判断(查询数据):
* contains:判断集合中是否包含指定的元素值
* containsAll:判断此集合中是否包含另一个集合
* equals:比较两个集合的元素是否相等
* hashcode:返回集合中元素对应的hashcode
* isEmpty:判断集合是否为空
* retainAll:保留此列表中包含在指定集合中的元素
* size:返回当前集合的大小
* 集合转数组的操作
* toArray:将当前集合转换为数组
* */
package com.mashibing;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionsDemo {
public static void main(String[] args) {
//新建可动态修改数组ArrayList
Collection collection = new ArrayList();
collection.add(1);
//collection.add(new Integer(1)); 上述步骤涉及自动装箱,将基本数据类型转换为包装类
collection.add(true);
collection.add("abc");
System.out.println(collection);
//在某个固定位置添加元素
//需要先进行强制类型转换,因为add(int index, E element)不是Collection中的方法而是ArrayList中的方法
((ArrayList) collection).add(0,"mashibing");
System.out.println(collection);
Collection collection1 = new ArrayList();
collection1.add('a');
collection1.add('b');
collection1.add('c');
collection1.add('d');
//添加另一个集合的元素到此集合中
collection.addAll(collection1);
System.out.println(collection);
//清空元素
// collection.clear();
// System.out.println(collection);
//判断某个元素是否包含在集合中
System.out.println(collection.contains('a'));
//判断此集合中是否包含另一个集合
System.out.println(collection.containsAll(collection1));
//判断集合是否为空
System.out.println(collection.isEmpty());
//删除指定元素
collection.remove('a');
System.out.println(collection);
System.out.println(collection1);
//保留此集合中包含在指定集合中的元素
System.out.println(collection.retainAll(collection1));
System.out.println(collection);
//将集合转换为数组
Object[] objects = collection.toArray();
System.out.println(objects);
}
}
[1, true, abc]
[mashibing, 1, true, abc]
[mashibing, 1, true, abc, a, b, c, d]
true
true
false
[mashibing, 1, true, abc, b, c, d]
[a, b, c, d]
true
[b, c, d]
[Ljava.lang.Object;@14ae5a5
4.Iterator接口
所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的子类实例对象。Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。所有的集合类均未提供相应的遍历方法,而是把遍历交给迭代器完成。迭代器为集合而生,专门实现集合遍历。Iterator接口定义了如下方法:
-
boolean hasNext();
判断是否有元素没有被遍历 -
Object next();
返回游标当前位置的元素并将游标移动到下一个位置 -
remove();
删除游标左面的元素,在执行完next之后该操作只能执行一次
/*
* 在java代码中包含三种循环的方式:
* - do...while
* - while
* - for
* 还有一种增强for循环的方式,可以简化循环的编写
*
* 在所有的集合类都默认实现了Iterable的接口,实现此接口意味着具备了增强for循环的能力,也就是for-each
* 增强for循环本质上使用的也是iterator的功能
* - iterator():返回迭代器
* - forEach():对Iterable的每个元素执行给定操作,直到所有元素都被处理或者引发异常
* 在iterator的方法中,要求返回一个Iterator的接口子类实例对象,此接口中包含了
* - hasNext():首先判断是否有值,如果有值则调用next()方法
* - next()
* */
package com.mashibing;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorDemo {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
//for循环
for (int i = 0;i < arrayList.size();i++) {
System.out.println(arrayList.get(i));
}
//迭代器:iterator
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//增强for循环
for (Object i : arrayList) {
System.out.println(i);
}
}
}
其中,ArrayList类中iterator方法实现为:
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
其对应结构图为:
4.1 ListIterator
在迭代时,不可能通过集合对象的方法(al.add(?))操作集合中的元素,会发生并发修改异常。所以,在迭代时只能通过迭代器的方法操作元素,但是Iterator的方法是有限的,只能进行判断(hasNext),取出(next),删除(remove)的操作。如果想要在迭代的过程中向集合中添加,修改元素等就需要使用在使用ListIterator接口中的方法。
- ListIterator迭代器提供了向前和向后的两种遍历方式。是通过cursor和lastret的指针来获取元素值及向下的遍历索引。当使用向前遍历的时候,必须保证指针在迭代器的结尾,否则,无法获取结果值。
package com.mashibing;
import java.util.ArrayList;
import java.util.ListIterator;
public class IteratorDemo {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
//迭代器:iterator
ListIterator iterator = arrayList.listIterator();
while (iterator.hasNext()) {
Object o = iterator.next();
//删除数组中的元素
if (o.equals(1)) {
iterator.remove();
}
System.out.println(o);
}
System.out.println("------------------");
//增强循环
for (Object o : arrayList) {
System.out.println(o);
}
System.out.println("------------------");
//从后往前遍历
while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}
}
}
1
2
3
4
------------------
2
3
4
------------------
4
3
2
4.2 上机练习
创建一个Dog类,包含昵称、颜色两属性;创建测试类,完成以下需求:
- 把多个Dog信息添加到集合中
- 查看Dog的数量及所有Dog的信息
- 删除集合中部分Dog的元素
- 判断集合中是否包含指定Dog
Dog.java
:
package com.mashibing;
import java.security.Principal;
import java.util.Objects;
public class Dog {
private String name;
private String color;
//无参构造方法
public Dog() {
}
//有参构造方法
public Dog(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//重写toString方法,打印具体值
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
//重写
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return Objects.equals(name, dog.name) && Objects.equals(color, dog.color);
}
@Override
public int hashCode() {
return Objects.hash(name, color);
}
}
ListTest.java
:
package com.mashibing;
import javax.xml.transform.Source;
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
List list = new ArrayList();
Dog d1 = new Dog("大黄","red");
Dog d2 = new Dog("二黄","blue");
Dog d3 = new Dog("三黄","yellow");
//把多个Dog信息添加到集合中
list.add(d1);
list.add(d2);
list.add(d3);
//查看Dog的数量及所有Dog信息
System.out.println(list);
System.out.println(list.size());
//删除集合中部分Dog元素
list.remove(d1);
System.out.println(list);
//判断集合中是否包含指定Dog
System.out.println(list.contains(d2));
Dog d4 = new Dog("二黄","blue");
//在未重写equals方法前,比较的是对象地址;在重写equals方法后,比较的是两个对象的属性值
System.out.println(list.contains(d4));
}
}
[Dog{name='大黄', color='red'}, Dog{name='二黄', color='blue'}, Dog{name='三黄', color='yellow'}]
3
[Dog{name='二黄', color='blue'}, Dog{name='三黄', color='yellow'}]
true
true
5.Iterable接口
可以使用Iterator遍历的本质是实现Iterable接口。
6.Set接口
Set接口存储一组唯一、无序的对象。存入和取出的顺序不一定一致。操作数据的方法与List类似,Set接口不存在get()方法。
6.1 HashSet
HashSet采用Hashtable哈希表(HashMap)存储结构。优点是添加速度快、查询速度快、删除速度快。缺点是无序。其中,LinkedHashSet采用哈希表存储结构,同时使用链表维护次序,其添加顺序是有序的。
Person.java
:
package com.mashibing;
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 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 && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
主程序
:
package com.mashibing;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*
* 1.Set中存放的是无序、唯一的元素,
* 2.Set不可以通过下标获取对应位置的元素的值,因为Set存放的是无序的元素
* 3.使用treeSet底层的实现是treemap;利用红黑树来进行实现
* 4.设置元素时,如果自定义对象,会查找对象中的equals和hashcode方法。如果没有,比较的是对象的地址
* 5.树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器
* */
public class SetDemo {
public static void main(String[] args) {
Set set = new HashSet();
set.add("123");
set.add(1);
set.add(true);
System.out.println(set);
//iterator迭代器
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("---------------------------------");
//将while循环改成for循环,会节省内存空间
for (Iterator iter = set.iterator();iter.hasNext();) {
System.out.println(iter.next());
}
HashSet hashSet = new HashSet();
hashSet.add(new Person("zhangsan",12));
hashSet.add(new Person("zhangsan",12));
hashSet.add(new Person("lisi",13));
System.out.println(hashSet);
}
}
[1, 123, true]
1
123
true
---------------------------------
1
123
true
[com.mashibing.Person@a8e9e1d9, com.mashibing.Person@623659b]
HashSet是如何保证元素的唯一性的呢?
是通过元素的两个方法:hashCode和equals方法来完成。如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashCode值不同,不会调用equals方法。
Hash表原理:
6.2 TreeSet接口
TreeSet接口采用二叉树(红黑树)的存储结构。优点是有序(排序后的升序)查询速度比List快。缺点是查询速度没有HashSet快。红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体性能上来说优于AVL树。
/*
* 使用treeSet底层的实现是treemap;利用红黑树来进行实现,
* 树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器
* 比较器分类:
* 内部比较器:定义在元素的类中,通过实现Comparable接口中的comparaTo方法进行实现
* 外部比较器:定义在当前类中,通过实现Comparator接口来实现,但是要将该比较器传递到集合中
* new TreeSet(new SetDemo());
* 外部比较器可以定义为工具类,此时所有需要比较的规则如果一致的话,可以复用;而内部比较器
* 只有在存储当前对象的时候才可以使用。
* 如果两者同时存在,使用外部比较器
* 当使用比较器的时候,不会调用equals方法
*/
Person.java
:
package com.mashibing;
import java.time.OffsetDateTime;
import java.util.Objects;
public class Person implements Comparable {
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 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 && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//定义比较器,此比较器按照name的长度进行比较
@Override
public int compareTo(Object o) {
Person p = (Person) o;
if (p.name.length() > this.name.length()) {
return -1;
} else if (p.name.length() < this.name.length()) {
return 1;
} else {
return 0;
}
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
主程序
:
package com.mashibing;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
//必须放置同一类型的数据
treeSet.add(34);
treeSet.add(1);
treeSet.add(65);
System.out.println(treeSet);
TreeSet treeSet = new TreeSet();
treeSet.add(new Person("zhangsan",12));
treeSet.add(new Person("zhangsan",12));
treeSet.add(new Person("lisi",13));
treeSet.add(new Person("wangwu",13));
treeSet.add(new Person("maliu",13));
System.out.println(treeSet);
}
}
[1, 34, 65]
//只打印一个"zhnagsan",compareTo方法中兼具去重功能
[Person{name='lisi', age=13}, Person{name='maliu', age=13}, Person{name='wangwu', age=13}, Person{name='zhangsan', age=12}]
外部比较器的实现:
Person.java
:
package com.mashibing;
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 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 && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//定义比较器,此比较器按照name的长度进行比较
// @Override
// public int compareTo(Object o) {
// Person p = (Person) o;
// if (p.name.length() > this.name.length()) {
// return -1;
// } else if (p.name.length() < this.name.length()) {
// return 1;
// } else {
// return 0;
// }
// }
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
主程序
:
package com.mashibing;
import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;
/*
* 使用treeSet底层的实现是treemap;利用红黑树来进行实现,
* 树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器
* 比较器分类:
* 内部比较器:定义在元素的类中,通过实现Comparable接口中的comparaTo方法进行实现
* 外部比较器:定义在当前类中,通过实现Comparator接口来实现,但是要将该比较器传递到集合中
* new TreeSet(new SetDemo());
* 外部比较器可以定义为工具类,此时所有需要比较的规则如果一致的话,可以复用;而内部比较器
* 只有在存储当前对象的时候才可以使用。
* 如果两者同时存在,使用外部比较器
* 当使用比较器的时候,不会调用equals方法
*/
public class SetDemo implements Comparator<Person> {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new SetDemo());
treeSet.add(new Person("zhangsan",19));
treeSet.add(new Person("zhangsan",12));
treeSet.add(new Person("lisi",15));
treeSet.add(new Person("wangwu",13));
treeSet.add(new Person("maliu",17));
System.out.println(treeSet);
}
@Override
public int compare(Person o1, Person o2) {
if (o1.getAge() > o2.getAge()) {
return -1;
} else if (o1.getAge() < o2.getAge()) {
return 1;
} else {
return 0;
}
}
}
[Person{name='zhangsan', age=19}, Person{name='maliu', age=17}, Person{name='lisi', age=15}, Person{name='wangwu', age=13}, Person{name='zhangsan', age=12}]
7.Comparable接口
所有可以排序的类都实现了java.lang.Comparable 接口,Comparable接口中只有一个方法:public int compareTo(Object obj);
。实现了Comparable 接口的类通过实现 comparaTo 方法
从而确定该类对象的排序方式。该方法有以下几种情况:
-
this == obj
返回0
-
this > obj
返回正数
-
this < obj
返回负数
实例见上述代码
8.List接口
List接口存储一组不唯一(可重复)、有序(插入顺序)的对象。List接口的方法如下:(凡是可以操作索引的方法都是该体系特有的方法)
增:
-
add(element):在list尾部添加元素
-
add(index,element):在指定索引的位置上插入元素
-
addAll(index,Collection):在指定的引的位置上插入整个集合的元素
-
addAll(Collection):在结束插入整个集合的元素
-
copyof(Collection):从一个集合复制到另一个集合里面
删:
- remove(index):根据索引删除指定的元素
- clear():删除list中的所有元素
改:
- set(index,element) :使用element替换指定索引位置上的元素
查:
- get(index):获取指定索引位置的元素
- contains(Object o):判断list中是否包含指定元素
- containsAll(Collection):判断list中是否包含指定集合中的所有元素
- equals(Object o):判断两个对象元素是否相等
- isEmpty():判断list是否为空
8.1 ArrayList
ArrayList实现了长度可变的数组,在内存中分配连续的空间。
- 优点:遍历元素和随机访问元素的效率比较高(数组的原因)
- 缺点:添加和删除需要移动大量移动元素,效率低,按照内容查询效率低
/*
* java集合框架:
* List:存放单一的值
* 特点:
* 1.可以存放不同类型的数据,而数组只能存放固定类型的数据
* 2.当使用ArrayList子类实现的时候,初始化长度为10,当长度不够的时候使用grow方法自动进行扩容操作
* */
使用:
package com.mashibing;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListResourceBundle;
public class ListDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add(1);
list.add("a");
list.add(true);
System.out.println(list);
//get(index)获取某个位置的元素,不能超过索引边界
System.out.println(list.get(0));
//indexOf(Object o):返回指定元素的索引(从前找)
System.out.println(list.indexOf("a"));
//lastIndexOf(Object o):返回指定元素的索引(从后找)
System.out.println(list.lastIndexOf("a"));
//set(index,E):使用element替换指定索引位置上的元素
list.set(0,"mashibing");
System.out.println(list);
//subList(begin,end):截取从begin到end-1的list
List list1 = list.subList(0,2);
System.out.println(list1);
//of:JDK12
List<Object> of = List.of(1,2,3,4);
System.out.println(of);
}
}
[a, 1, a, true]
a
0
2
[mashibing, 1, a, true]
[mashibing, 1]
[1, 2, 3, 4]
8.2 LinkedList
LinkedList采用链表存储方式。又分为单向链表、双向链表
- 优点:插入、删除元素时效率比较高
- 缺点:遍历和随机访问元素效率低下
LinkedList特有的方法:
package com.mashibing;
import java.util.LinkedList;
/*
* LinkedList拥有更加丰富的方法实现,需要使用的时候查询api即可,不需要记忆
* */
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(123);
linkedList.add(false);
linkedList.add("abc");
linkedList.add(123);
System.out.println(linkedList);
//往链表指定位置添加元素
linkedList.add(2,"mashibing");
System.out.println(linkedList);
//往链表头部添加元素
linkedList.addFirst("1111");
System.out.println(linkedList);
//往链表尾部添加元素
linkedList.addLast("2222");
System.out.println(linkedList);
//获取链表的第一个元素
System.out.println(linkedList.element());
//get(index)获取链表指定位置的元素
System.out.println(linkedList.get(0));
//indexOf(O)获取指定元素的下标位置(从前找)
System.out.println(linkedList.indexOf(123));
//lastindexOf()获取指定元素的下标位置(从后找)
System.out.println(linkedList.lastIndexOf(123));
//offer(E)添加元素
linkedList.offer("3333");
System.out.println(linkedList);
//peek获取链表元素
System.out.println(linkedList.peek());
//poll()获取链表元素
System.out.println(linkedList.poll());
}
}
[123, false, abc, 123]
[123, false, mashibing, abc, 123]
[1111, 123, false, mashibing, abc, 123]
[1111, 123, false, mashibing, abc, 123, 2222]
1111
1111
1
5
[1111, 123, false, mashibing, abc, 123, 2222, 3333]
1111
1111
8.3 vector
- Vector也是List接口的一个子类实现
- Vector跟ArrayList一样,底层都是使用数组进行实现的
- 面试经常问区别:
- ArrayList是线程不安全的,效率高;Vector是线程安全的,效率低
- ArrayList在进行扩容操作时,扩容至原容量的1.5倍;Vector在进行扩容时,扩容至原容量的2倍
9.泛型
为什么需要泛型?
- 解决数据数据类型不统一产生的异常
- 使用泛型可以更好地去保护数据类型
/*
* 当做一些集合的统一操作时,需要保证集合的类型是统一的,此时,需要泛型来限制
* 优点:
* 1.数据安全
* 2.获取数据时,效率比较高
* 给集合中的元素设置相同的类型就是泛型的基本需求
* 在定义对象的时候,通过<>中设置合理的类型来进行实现,相当于类型需要用户动态传参来设置
*
* 泛型的高阶应用:
* 1.泛型类
* 在定义类的时候,在类名的后面添加<E(E还是A只是起到占位的作用)>;类中的方法的返回值类型和属性的类型都可以使用泛型
* 2.泛型接口
* 在定义接口的时候,在接口的名称后添加<E.K.V.A.B>
1.子类在进行实现的时候,可以不填写泛型的类型,此时,在创建具体的子类对象时才决定使用什么类型
2.子类在实现泛型接口的时候,只在实现父类的接口的时候指定父类的泛型类型即可,此时,测试方法中的泛型类型必须要跟子类保持一致
* 3.泛型方法
* 在定义方法的时候,指定方法的返回值和参数是自定义的占位符,可以是类名中的T,也可以是自定义的Q,
* 只不过在使用Q的时候需要使用<Q>定义在返回值的前面
* 好处:由传递进方法的参数来决定参数的类型
* 4.泛型的上限
* 工作中不会用到
* 如果父类确定了,所有的子类都可以直接使用
* 5.泛型的下限
* 工作中不会用到
* 如果子类确定了,子类的所有父类都可以直接传递参数使用
* */
泛型讲解实例:
FanXingClass.java
:
package com.mashibing;
public class FanXingClass <A>{
private int id;
private A a;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public void show() {
System.out.println("id:"+id+"A:"+a);
}
public A get() {
return a;
}
public void set(A a) {
System.out.println("执行set方法:"+a);
}
}
FanXingInterface.java
:
package com.mashibing;
public interface FanXingInterface<B> {
public B test();
public void test2(B b);
}
FanXingInterfaceSub1.java
:
package com.mashibing;
public class FanXingInterfaceSub1<B> implements FanXingInterface<B>{
@Override
public B test() {
return null;
}
@Override
public void test2(B o) {
System.out.println(o);
}
}
FanXingInterfaceSub2.java
:
package com.mashibing;
public class FanXingInterfaceSub2 implements FanXingInterface<String>{
@Override
public String test() {
return null;
}
@Override
public void test2(String o) {
System.out.println(o);
}
}
FanXingMetho.java
:
package com.mashibing;
public class FanXingMethod<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public <Q> void show(Q q) {
System.out.println(q);
System.out.println(t);
}
}
FanXingTest.java
:
package com.mashibing;
import java.lang.ref.SoftReference;
public class FanXingTest {
public static void main(String[] args) {
//1.泛型类的使用
FanXingClass<String> fanXingClass = new FanXingClass<String>();
fanXingClass.setA("mashibing");
fanXingClass.setId(1);
fanXingClass.show();
FanXingClass<Integer> fanXingClass1 = new FanXingClass<Integer>();
fanXingClass1.setId(34);
fanXingClass1.setA(2);
fanXingClass1.show();
FanXingClass<Person> fanXingClass2 = new FanXingClass<Person>();
fanXingClass2.setA(new Person("aaa",12));
fanXingClass2.setId(3);
fanXingClass2.show();
System.out.println(fanXingClass2.get());
fanXingClass2.set(new Person("bbb",14));
//2.泛型接口的使用1
FanXingInterface<String> fanXingInterface = new FanXingInterfaceSub1<String>();
fanXingInterface.test2("abc");
//泛型接口的使用2
FanXingInterface fanXingInterface1 = new FanXingInterfaceSub2();
fanXingInterface1.test2("123");
//3.泛型方法
FanXingMethod<String> fanXingMethod = new FanXingMethod<>();
fanXingMethod.setT("ttt");
fanXingMethod.show(123);
fanXingMethod.show(true);
}
}
id:1A:mashibing
id:34A:2
id:3A:Person{name='aaa', age=12}
Person{name='aaa', age=12}
执行set方法:Person{name='bbb', age=14}
abc
123
123
ttt
true
ttt
9.1 使用泛型集合解决实际问题
- 声明员工类Employee包含如下属性:id,name,age,gender(枚举类型)
- 声明程序员类SE,含有属性popularity人气值
- 声明项目经理类PM,含有属性workOfYear工作年限
- 程序员与项目经理都继承自Employee
需求说明:
- 使用泛型集合ArrayList,LinkedList,HashSet,TreeSet完成员工的添加、删除;
- 判断,集合中元素个数的判断
10.Map接口
Map接口存储一组键值对象,提供key到value的映射。
-
HashMap:底层结构是哈希表
- Key无序且唯一
- Value无序不唯一
-
LinkedHashMap:底层结构是链表
有序的HashMap,速度快
-
TreeMap:底层结构是红黑树
有序,速度没有hash快
问题:Set与Map有什么关系?
- 采用了相同的数据结构,Set集合只用于map的key
/*
* map存储的是k-v键值对映射的数据
* 实现子类:
* HashMap:数组+链表(1.7);数组+链表+红黑树(1.8)
* LinkedHashMap:链表
* TreeMap:红黑树
*
* 基本api操作:
* 增:
* put(k,v):添加数据
* 删:
* clear():清空map中的元素
* remove():删除指定元素
* 改:
*
* 查:
* isEmpty():判断map是否为空(查)
* containsKey():判断map中是否含有某个key值
* containsValue():判断map中是否含有某个value值
* get():获取map中某个key值对应的value值
* entrySet():
* Map.entry表示的是K-V组合的一组映射关系,key和value成组出现
* Hashmap与Hashtable的区别:
* - HashMap线程不安全,效率高;Hashtable线程安全,效率低
* - Hashmap中key和value都可以为空;Hashtable中key和value都不可以为空
*
* */
10.1 Map中的方法及其实例
MapDemo.java
:
package com.mashibing.map;
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String,Integer>();
//put(key,value)添加元素
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
System.out.println(map);
//isempty()判断是否为空
System.out.println(map.isEmpty());
//size:大小
System.out.println(map.size());
//map
// map.clear();
// System.out.println(map);
//判断:containsKey和containsValue
System.out.println(map.containsKey("a"));
System.out.println(map.containsValue(1));
//get()获取对应key的value值
System.out.println(map.get("a"));
System.out.println(map.getOrDefault("e",-1));
//remove():删除元素
map.remove("a");
System.out.println(map);
//遍历操作
Set<String> keys = map.keySet();
for(String key :keys) {
System.out.println(key+"="+map.get(key));
}
//只能获取对应的value值,不能根据value值获取key
Collection<Integer> values = map.values();
for(Integer i:values) {
System.out.println(i);
}
//迭代器
Set<String> keys2 = map.keySet();
Iterator<String> iterator = keys2.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
System.out.println(key+"="+map.get(key));
}
//entrySet
//Map.Entry<String, Integer>:泛型套了一个泛型
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
while(iterator1.hasNext()) {
Map.Entry<String, Integer> next = iterator1.next();
System.out.println(next.getKey()+"--"+next.getValue());
}
}
}
{a=1, b=2, c=3, d=4}
false
4
true
true
1
-1
{b=2, c=3, d=4}
b=2
c=3
d=4
2
3
4
b=2
c=3
d=4
b--2
c--3
d--4