泛型
复习:
-
Map存储结构的特点是什么?并指明key、value、entry存储数据的特点
-
Map存储数据是双列数据,存储key-value对数据,key:无序的,不可重复的数据,用Set承装,方法是keySet();;value:无序的,可重复的,用Collection类承装,方法是values();entry:无序的,不可重复的,用Set承装,方法是entrySet()。
-
描述HashMap的底层实现原理(jdk8)。
-
new HashMap(),底层没有创建长度16的数组,在添加数据的时候才创建数组,
- 首先调用hashCode()方法计算key的哈希值,通过某种算法计算得到Node存放的位置,如果此位置上没有数据,添加数据成功
- 如果此位置上存在一个或多个数据,则判断此数据和一个或多个数据的的哈希值,如果哈希值不同,则添加成功,如果哈希值相同
- 则判断两者的equals()方法,返回false,则添加成功,如果返回true,使用value1替换value2
- 底层数据结构是数组+链表+红黑树,以链表形式存在的数据个数大于8,且数据长度大于64,就改用红黑树存储
-
Map中常用实现类有哪些?各自有什么特点?
-
HashMap:作为最常用的实现类,线程不安全,效率高,可以存储null的key和value
- LinkedHashMap:作为hashmap的子类,继承其方法,可以按照添加的顺序实现遍历,底层多了一对指针,在频繁的删除和添加过程中比hashmap的效率要高
-
Hashtable:古老的实现类,线程安全,效率低,不能存储null的key和value
- 子类:properties类,处理配置文件
-
TreeMap:保证按照添加的key-value进行排序,实现排序遍历,考虑key的自然排序和定制排序,调用Comparable和Comparator接口
-
底层数据结构是数组+链表+红黑树
-
如何实现Map中的key-value对,代码实现。
key:用Set存储,用keySet()方法
HashMap map = new HashMap();
map.put(key,value);
Set set = map.keySet();
Iterator iterator = set.itertor();
while(iterator.hasNext()){
Object key = iterator.next();
System.out.println(key);
//实现value方法一
Object value = map.get(key);
System.out.println(key + "--->" + value);
}
value://方法二:调用map.values()方法
HashMap map = new HashMap();
map.put(key,value);
Collection value = map.values();
Iterator iterator = value.itertor();
while(iterator.hasNext()){
System.out.println(irerator.next());
key-value:
Set set1 = map.entrySet();
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()){
Object obj = iterator2.next();
//强制转化,利用内部类定义的方法
Map.Entry entry = (Map.Entry)obj;
System.out.println(entry.getKey() +"-->" + entry.getValue());
}
-
Collection和Collections的区别?
-
Collection是存储单例数据的集合接口,Collections是实现Collection和Map的工具类。
-
常用方法?
-
添:put(OBject key,Object value)
-
删:remove(Object key)
-
改:put(OBject key,Object value)
-
查:get(Object key)
-
长度:size()
-
遍历:map.keySet(),map.values(),map.entrySet()
泛型
- 就像是标签:<>,在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型,这个类型参数在使用时(继承或者实现这个接口,用这个类型声明变量、创建对象时)确定。
package generic;
import java.util.*;
/*
在集合中泛型的使用:
1.集合接口或集合类在jdk5都修改为带泛型的结构
2.在实例化集合类可以指明具体的泛型类型
3.指明完后,在集合类或接口中凡是定义类或接口,
内部接口(方法,构造器,属性)使用到类的泛型的位置都指定为实例化的泛型类型
4.注意点:泛型类型必须是类,不能是基本数据类型,需要用到基本类型的时候用包装类
5.如果实例化没有指明泛型,默认是Object类型
自定义泛型结构:泛型类、泛型接口、泛型方法,见GenericTest1
自定义泛型中静态方法不能使用类的泛型;因为静态早于对象的创建
异常类不能是泛型的
泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有关系,
泛型方法在调用时,指明泛型参数的类型
泛型方法所属的类是不是泛型类都没有关系 ,见GenericTest1
可以使用static静态方法,E在调用方法的时候确定的,不是在实例化类时确定
*/
public class GenericTest {
//在集合中使用泛型之前情况:
public void test(){
ArrayList list = new ArrayList();
list.add(78);
list.add(68);
list.add(79);
list.add(98);
//问题一:没有限制存放数据类型,类型不安全
// list.add("Tom");
for (Object score : list) {
//问题二,强转时,可能出现ClassCastException异常
int stuScore = (Integer) score;
System.out.println(stuScore);
}
}
//在集合中使用泛型:在编译时保护数据的安全
public void test1(){
ArrayList<Integer> list = new ArrayList<>();
list.add(78);
list.add(68);
list.add(79);
list.add(98);
//方式一
for (Integer score : list) {
//避免强制转换
int stuScore = score;
System.out.println(stuScore);
}
//方式二
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
//以HashMap为例
public void test2(){
HashMap<String, Integer> map = new HashMap<>();
map.put("Tom",23);
map.put("Zom",22);
map.put("Jim",30);
//泛型的嵌套
Set<Map.Entry<String, Integer>> entry = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
while (iterator.hasNext()){
Map.Entry<String, Integer> e = iterator.next();
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key +"-- " +value);
}
}
//测试
public static void main(String[] args) {
GenericTest genericTest = new GenericTest();
genericTest.test2();
}
}
package generic;
import java.util.ArrayList;
import java.util.List;
public class GenericTest1 {
public void test(){
//如果定义了泛型类,实例化没有指明类的泛型,认为Object类型
//要求大家定义了类是带泛型的,建议在实例化时要指明类的泛型
Order<String> order = new Order<String>("orderAA",1001,"order:AA");
order.setOrderT("AA:hello");
}
public void test1(){
subOrder sub1 = new subOrder();
//由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不需要再指明类型
sub1.setOrderT(1122);
subOrder1<String> sub2 = new subOrder1<>();
sub2.setOrderT("sss");
}
//泛型不同的引用不能相互赋值
public void test2(){
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = null;
// list1 = list2;不能赋值了,因为类型不一样
}
//测试泛型方法
public void test3(){
Order<String> order = new Order<>();
Integer[] arr = {1, 2, 3, 4};
//泛型方法在调用时,指明泛型参数的类型
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
//测试
public static void main(String[] args) {
GenericTest1 genericTest1 = new GenericTest1();
genericTest1.test3();
}
}
泛型类
package generic;
import java.util.ArrayList;
import java.util.List;
//自定义泛型类
//接口中不能有构造器
public class Order<T> {
String orderName;
int orderId;
//类的内部结构可以使用类的泛型
T orderT;
//泛型类的构造器
public Order(){
//T是一个变量,不是类
//创建数组
T[] arr = (T[]) new Object[10];
};
//alt+insert +带参构造器
public Order(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
//alt+insert
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
//泛型方法,泛型参数
public <E> List<E> copyFromArrayToList(E[] arr){
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
}
- 泛型子类
package generic;
//subOrder1:仍然是一个泛型类
//子类保留父类的泛型
public class subOrder1<T> extends Order<T>{
//1.全部保留:class Son1<T1,T2,A,B> extends Father<T1,T2>{}
//2.部分保留:class Son2<T2,A,B> extends Father<Integer,T2>{}
}
如何使用泛型
package java;
import java.util.List;
//操纵数据库的操作(增删改查)
//有很多类就加<T>
public class DAO<T> {//表的共性操作的DAO
//添加一条记录
public void add(T t){
}
//删除一条记录
public void remove(int index){
}
//修改一条记录
public void update(int index,T t){
}
//查询一条记录
public T getIndex(int index){
return null;
}
//查询多条记录
public List<T> getForList(int index){
return null;
}
//泛型方法
//举例:获取表中一共有多少条记录?(long型)
// 获取最大员工入职时间?
public <E> E getValue(){
return null;
}
}
package java;
import java.util.List;
public class DAOTest {
public void test(){
CustomerDAO dao1 = new CustomerDAO();
dao1.add(new Customer());
//用增删改查
//操作customer表
List<Customer> list = dao1.getForList(10);
StudentDAO dao2 = new StudentDAO();
//操作student表
List<Student> list1 = dao2.getForList(10);
}
}
package java;
//对应数据库中另外一张表
public class Student {
}
package java;
public class StudentDAO extends DAO<Student>{//只能操作一个表
}
package java;
//此类对应数据库中的customers表
public class Customer {
}
package java;
//专门操作表的
public class CustomerDAO extends DAO<Customer> {//只能操作一个表
}
泛型在继承方面的使用及通配符的使用
package java1;
import java.util.*;
import static jdk.nashorn.internal.objects.Global.print;
/*/
1.泛型在继承方面的体现
类A是类B的父类,G<A> 和 G<B> 不具备子父类关系,不能赋值
类A是类B的父类或者接口,A<G> 是 B<G>的父类, 可以赋值
2.通配符的使用:造一个不具备子父类关系的共同父类
通配符:<?>
类A是类B的父类,G<A>和G<B>是没有关系的,两者的共同父类是G<?>
添加:对于List<?>就不能向内部添加数据,除了null外
读取:允许读取数据,读取的数据类型是Object
3.有限制条件的通配符的使用
? extends A:(-∞,A] :G< ? extends A> 可以作为G<A>和G<B>的父类,其中A是B的父类
也就是说extends:只能调用自己和自己的子类
? super A:[A,+∞) :G< ? extends A> 可以作为G<A>和G<B>的父类,其中B是A的父类
也就是说super:可以调用自己和自己的父类
*/
public class GenericTest {
public void test(){
Object obj = null;
String str = null;
obj = str;
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;
List<Object> list1 = null;
List<String> list2 = null;
//错误,不是子父类关系,编译不通过
//list1 = list2;
//错误,不是子父类关系,编译不通过
// Date date = new Date();
// str = date;
}
public void test1(){
AbstractList<String> list = null; //子父类
List<String> list2 = null;//接口
ArrayList<String> list3 = null;
list = list3;
list2 = list3;
}
public void test2(){
List<Object> list1 = null;
List<String> list2 = null;
//通配符:包括Object类和String类
List<?> list = null;
list = list1;
list = list2;
//
ArrayList<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
//添加:对于List<?>就不能向内部添加数据,除了null外
//list.add("DD");
list.add(null);
//读取:允许读取数据,读取的数据类型是Object
Object o = list.get(1);
System.out.println(o);
}
public void test3(List<?> list){
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}
public void test4(){
//? extends A:(-∞,A] ? super A:[A,+∞)
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
//?可以表示自己或者其子类,但不能表示Object类
list1 = list3;
list1 = list4;
//可以表示自己和自己的父类(Object类)
list2 = list4;
list2 = list5;
//读数据:读高的类型
list1 = list3;
Person p = list1.get(0);
Object o = list2.get(0);
//写数据
//编译不通过:小于等于Person,Person都不行,其子类更不行
// list1.add(new Person());
// list1.add(new Student());
//编译通过,大于等于Person,Person都可以,其子类也可以
list2.add(new Person());
list2.add(new Student());
}
public static void main(String[] args) {
GenericTest genericTest = new GenericTest();
genericTest.test2();
}
}
泛型练习题
- 定义个泛型类DAO,在其中定义一个Map成员变量,Map的键为String类型,值为T类型
- 创建方法:
- public void save(String id,entity);保存T类型的对象到Map成员变量中
- pubilc T get(String id);从Map中获取id对应的对象
- public void update(String id,T entity):替换map中key为id的内容,改为entity对象
- public List list[]:返回map中存放的所有T对象
- public void delete(String id): 删除指定id对象
- 定义一个User类:
- 该类 包含:private成员变量(int类型)id,age;(String类型):name
- 定义一个测试类:
- 创建DAO类的对象,分别调用其save,get,update,list,delete方法来操作User对象
- 使用Junit单元测试类进行测试
package exer1;
import java.util.*;
/*
- **定义个泛型类DAO<T>,在其中定义一个Map成员变量,Map的键为String类型,值为T类型**
- **创建方法:**
- **public void save(String id,T entity);保存T类型的对象到Map成员变量中**
- **pubilc T get(String id);从Map中获取id对应的对象**
- **public void update(String id,T entity):替换map中key为id的内容,改为entity对象**
- **public List<T> list():返回map中存放的所有T对象**
- **public void delete(String id): 删除指定id对象**
*/
public class DAO<T> {
private Map<String,T> map = new HashMap<String,T>();
//保存T类型的对象到Map成员变量中
public void save(String id,T entity){
map.put(id,entity);
}
//从Map中获取id对应的对象
public T get(String id){
return map.get(id);
}
//替换map中key为id的内容,改为entity对象
public void update(String id,T entity){
if (map.containsKey(id)){//先判断有没有id,有就改,没有就添加
map.put(id,entity);
}
}
//返回 map 中存放的所有 T 对象
public List<T> list(){
//正确的写法,先建立一个list,然后把集合中的values放入list中,不能作强转
ArrayList<T> list = new ArrayList<>();
Collection<T> values = map.values();
for (T t : values) {
list.add(t);
}
return list;
}
//删除指定id对象
public void delete(String id){
map.remove(id);
}
}
package exer1;
import java.util.HashMap;
import java.util.List;
/*
- **创建DAO类的对象,分别调用其save,get,update,list,delete方法来操作User对象**
- **使用Junit单元测试类进行测试**
*/
public class DAOTest {
public static void main(String[] args) {
DAO<User> dao = new DAO<>();
//保存
dao.save("1001",new User("周杰伦",1001,34));
dao.save("1002",new User("昆琳",1002,20));
dao.save("1003",new User("周小伦",1003,31));
//new一个具体的对象,使用一个带参的构造器
//map还没有实例化,没有赋值会报错:空指针异常
//解决方法:在DAO中对map实例化
//修改
dao.update("1003",new User("刘想",1003,24));
//删除
dao.delete("1002");
//获取
User user1 = dao.get("1001");
System.out.println(user1);
//遍历
List<User> list = dao.list();
for (User user : list) {
System.out.println(user);
}
}
}
package exer1;
/*
**该类 包含:private成员变量(int类型)id,age;(String类型):name**
*/
public class User {
private String name;
private int id;
private int age;
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (id != user.id) return false;
if (age != user.age) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + id;
result = 31 * result + age;
return result;
}
}