泛型
什么是泛型
泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候可以使用泛型表示,泛型也可以看做是一个变量用来接收其他人定义的数据类型;
E e:Eelement元素 T t:Type 类型
创建对象使用泛型和不使用的区别
创建对象时不使用泛型:
- 【好处】:集合不使用泛型,默认类型就是Object,可以存储任意类型的数据
- 【坏处】:不安全会引发运行时异常
ArrayList list = new ArrayList();
list.add("abc");
list.add(1);
// 想要使用String类型必须进行向下强制转换(多态)
// 但是如果不是String类型将会抛出异常
Iterator it = list.iterator();
while (it.hasNext()) {
Object next = it.next();
String s = (String) next;
System.out.println("====>"+s)
}
使用泛型创建对象
- 【好处】:把运行时异常提升到了编译时异常,不需要对象进行强制转换
- 【坏处】:只能存储规定的类型(利大于弊)
ArrayList<String> obj = new ArrayList<>();
obj.add("1");
obj.add("2");
obj.add("3");
for (String s : obj) {
System.out.println(s.length());
}
泛型的使用以及定义
1、泛型类的定义
// 定义泛型类
@Data class GenericClass<T> {
private T userName;
}
@Test public void test01() {
// 不使用泛型默认为Object类型
GenericClass g1 = new GenericClass();
g1.setUserName("张三");
System.out.println(g1.getUserName());
// 使用泛型的JavaBean
GenericClass<Integer> g = new GenericClass<>();
g.setUserName(10086);
System.out.println(g.getUserName());
}
<T>
中括号的 “T” 可以为其他的、M、S等等自定义,属性需要和定义的 <T>
的名字一直即可,如果创建该实体,不指定类型默认为Object类型。
2、泛型方法的定义
class GenericMethod {
// 定义一个泛型的成员方法返回的名字可以随意 T E M 等等
public <M> void method01(M params) {
System.out.println(params);
}
// 静态方法定义
public static <T> T methodStatic(T ts) {
System.out.println(ts);
return ts;
}
}
---- 测试定义的泛型方法
@Test public void testMethod() {
GenericMethod method = new GenericMethod();
method.method01(1);
method.method01("abc");
method.method01(true);
GenericMethod.methodStatic(1,"2",'c',true);
}
格式:访问修饰符 <泛型> void|泛型 方法名(泛型 参数名称)
3、泛型的接口以及实现类定义
接口定义:
interface GenericInter<T>{
public abstract void interMethod01(Integer i);
public abstract void interMethod02(T t);
}
【注意事项】
-
泛型接口中的方法若想使用泛型参数,必须指定接口为泛型的。
-
泛型接口中仍然可以使用非泛型的成员方法。
实现类定义:
实现类定义有两种方式,1.直接在实现接口的时候指定泛型的类型,2.在实现接口的同时指定实现类的泛型和接口一致,在创建对象的时候指定类型。如果都不指定默认为object
// 实现类直接指定
class GenericInterImpl implements GenericInter<String>{
@Override
public void interMethod01(Integer i) {
System.out.println(i);
}
@Override
public void interMethod02(String s) {
System.out.println(s);
}
}
-----
// 实现类同样使用泛型,创建对象指定泛型类型
class GenericInterImplement<T> implements GenericInter<T> {
@Override
public void interMethod01(Integer i) {
System.out.println(i);
}
@Override
public void interMethod02(T t) {
System.out.println(t);
}
}
-----
/**
* 测试定义的泛型接口
*/
@Test public void testInter() {
// 实现类指定泛型类型
GenericInterImpl generic = new GenericInterImpl();
generic.interMethod01(1);
generic.interMethod02("2");
// 创建对象时指定泛型类型
GenericInter<Integer> ge = new GenericInterImplement<>();
ge.interMethod02(1);
ge.interMethod01(2);
}
泛型的通配符 ?
泛型的通配符:【?】
作用:一般用于指定传入的集合属于什么类型,不能创建对象使用,只能作为参数使用。
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
ArrayList<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
printArray(list1);
printArray(list2);
}
// 使用泛型通配符?只能作为方法的参数使用
// 我们此时不知道到底使用什么类型进行接收使用?
public static void printArray(List<?> list) {
for (Object o : list) {
System.out.println(o);
}
}
通配符的高级用法
- 泛型的上限限定: ? extends T --> 代表【?】只能是【T本身 || T类型的子类】
- 泛型的下限限定: ? super T --> 代表【?】只能是【T本身 || T类型的父类】
@Test public void test() {
// Integer extends Number -- Number extends Object
List<Integer> integers = new ArrayList<>();
List<String> strings = new ArrayList<>();
List<Number> numbers = new ArrayList<>();
List<Object> objects = new ArrayList<>();
// 上限限定:参数只能是子类或者本类
getElementsUnderNumber(integers);
// getElementsUnderNumber(strings); 编译报错
getElementsUnderNumber(numbers);
// getElementsUnderNumber(objects); 编译报错
// 下限限定:参数之类是父类或者本类
// getElementsSuperNumber(integers); 编译报错
// getElementsSuperNumber(strings); 编译报错
getElementsSuperNumber(numbers);
getElementsSuperNumber(objects);
}
// 上限规定:list只能是Number本身或者Number的子类
public void getElementsUnderNumber(List<? extends Number> list) { }
// 下限规定:list只能是Number本身或者Number的父类
public void getElementsSuperNumber(List<? super Number> list) { }
集合
集合中的总体体系 — 分为单列集合,Collection接口
,双列集合:Map接口
,现在主要记录的是单列集合。
单列集合: 又划分为List、Set集合,同样这两个都是接口,下面有几个实现类。
-
List
特性:有序,可重复,实现类如下:- ArrayList:动态数组结构, 查找快,增删慢
- linkendList:链表结构,增删快,查找慢
- Vector:和【ArrayList】一样的实现,但是线程安全,所以效率低下
-
Set
特性:无序,不可重复。- HashSet:底层数据结构是一个哈希表通过 hashcode() 和equals()来保证元素的唯一性,线程不安全 存取速度快
- treeSet:底层数据结构是一个红黑树 默认对元素进行自然排序,如果在比较的时候两个对象返回值为0,那么元素重复。
- linkendSet
共性方法: 单列集合的所有共性方法,适合所有的单列集合,其实无法就是增删改查CRUD。
方法名 | 方法作用 |
---|---|
add(E e) | 添加元素 |
remove(E e) | 移除元素 |
clear() | 清空元素 |
addAll(Collection<? extends E> e) | 添加另外一个集合的所有内容 |
contains(E e) | 是否包含 |
isEmpty() | 是否为空 |
size() | 获取大小长度 |
toArray() | 转化数组 |
iterator() | 返回迭代器 |