【Java基础】- 泛型
1.什么是泛型
JAVA 1.5的重大改变就是泛型的引入,实现了参数化类型的概念,使代码适用于多种类型,是通过解耦类、方法与所使用类型之间的约束。
使得类型范围在接口的实现和类的集成之上。
2.泛型类
泛型类就是将泛型定义在类上,使用类时才会确定类型,类中的属性、方法也可以使用泛型
2.1泛型类的定义
public class GenericityClass<T> {
//属性和方法可以直接使用泛型
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
注意:类上声明泛型只对非静态成员、非静态方法有效
泛型类中的静态方法不能直接使用类的泛型,可以声明为静态泛型方法再使用
//编译报错
public static void getT(T t){
}
//编译正常
public static <T> void getT(T t){
}
泛型的类型未确定时,只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
例如集合的add()方法
public static void main(String[] args) {
List<? extends Number> testList = new ArrayList<>();
testList.get(0);
testList.add(1);//error
}
2.2泛型的使用
使用时声明类型,类中的方法、属性都会为该类型。
public static void main(String[] args) {
GenericityClass<Integer> genericityClass = new GenericityClass<>();
genericityClass.setData(10);
System.out.println(genericityClass.getData());
}
3.泛型方法
有时不需要将整个类定义为泛型,只需要将方法定义为泛型即可。
3.1 泛型方法的定义
public class GenericityFunc {
public <T> void print(T t){
System.out.println(t.toString());
}
}
3.2 泛型方法的使用
public static void main(String[] args) {
GenericityFunc genericityFunc = new GenericityFunc();
genericityFunc.print("hello genericity function ");
genericityFunc.print(10);
genericityFunc.print(new int[]{1,2,3,4,5,6});
}
4.泛型的继承
只要是Java类就可以存在继承关系,泛型的继承可以
- 1.明确泛型类
- 2.不明确泛型类
//泛型父类
public abstract class FooClass<T> {
public abstract T getT();
}
//子类不明确类型
public class SonClass<T> extends FooClass<T>{
private T t;
@Override
public T getT() {
return t;
}
}
//子类指定类型
public class SonClass2 extends FooClass<String>{
private String data = "this is SonClass2";
@Override
public String getT() {
return data;
}
}
5.类型通配符
T,E,K,V,?的区别
本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替T,在可读性上可能会弱一些。通常情况下,T,E,K,V,?是这样约定的:
- ?表示不确定的 java 类型
- T (type) 表示具体的一个java类型
- K V (key value) 分别代表java键值中的Key Value
- E (element) 代表Element
通配符 "?",通常是在变量赋值或变量声明时用的,?通配符来表示任意类型。
用在声明泛型类或泛型方法会报错 即不能用于定义泛型
List<?> unknownList;
List<? extends Number> unknownNumberList; //上界
List<? super Integer> unknownBaseLineIntgerList; //下界
当使用通配符作为形参时,只有变量明确定义了类型且不符合方法的声明才会编译异常
public static void main(String[] args) {
List commonList = new ArrayList();
List<? extends Integer> integerList = new ArrayList<>();
List<String> stringsList = new ArrayList();
print(commonList); //编译通过
print(integerList);//编译通过
print(stringsList);//编译错误
}
public static void print(List<? extends Number> list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
6.泛型的擦除
泛型是 Java 1.5 版本才引进的概念,在这之前是没有泛型的概念的,但显然,泛型代码能够很好地和之前版本的代码很好地兼容。因为,泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如<T>
则会被转译成普通的 Object 类型,如果指定了上限如
不能创建泛型数组的原因:数组中存储的类型是确定的,泛型在运行时,被擦除
7.泛型的应用
1.通用Service使用泛型类,实际实现时类指定业务pojo.
public interface BasicService<T extends BaseEntity,M extends BaseMapper<T>> {
T getModelById(Long id);
List<T> getListByEqualsMap(Map<String,Object> mapEquals);
T getModelByEqualsMap(Map<String,Object> mapEquals);
List<T> selectBySelective(T t);
int insertModel(T t,String userName);
int insertSelective(T t,String userName);
int updateById(T t,Long id,String userName);
}