java中的泛型(基础篇)
java中的泛型--基础篇
什么是泛型
泛型即参数化类型,是JDK1.5中引入的一个新特性。 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型。换句话说,"泛型"这个术语的意思是:“适用于许多的类型”。
(出自 java编程思想)
1:泛型的使用
在我们平时开发或者查看源码的时候,我们会发现很多的代码都会用到泛型,比如我们常用到的ArratList,为什么它能够同时创建 String,Double等等很多的类型的集合那?如果我们点进源码就会发现,在源码中使用了泛型。接下来我们就来看看泛型到底有哪些吧!
1.1: 字母规范
在定义泛型类时,我们已经提到用于指定泛型的变量是一个大写字母,当然不是的!!!!任意一个大写字母都可以。他们的意义是完全相同的,但为了提高可读性,大家还是用有意义的字母比较好,一般来讲,在不同的情境下使用的字母意义如下:
- E — Element,常用在java Collection里,如:
- List,Iterator,Set
- K,V — Key,Value,代表Map的键值对
- N — Number,数字
- T — Type,类型,如String,Integer等等
1.2:泛型接口
// 接口上定义泛型,此处可以随便写标识符号
public interface Things<T> {
T getThing();
// 作为返回值
void setThing(T t);
//作为参数
}
泛型接口的使用
非泛型类
public class Coding implements Things<String> {
private String str;
public Coding(String str) {
this.str = str;
}
@Override
public String getThing() {
return this.str;
}
@Override
public void setThing(String s) {
}
public static void main(String[] args) {
Coding coding = new Coding("写代码!");
System.out.println(coding.getThing());
}
泛型类
public class Work<T> implements Things<T> {
private T var;
public Work(T var) {
this.setThing(var);
}
@Override
public T getThing() {
return this.var;
}
@Override
public void setThing(T var) {
this.var = var ;
}
public static void main(String[] args) {
Work<String> work=new Work<>("工作中!");
System.out.println(work.getThing());
}
}
1.3:泛型类
public class DoSome<T> {
private T x;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
public static void main(String[] args) {
DoSome<String> doSome =new DoSome();
doSome.setX("123");
System.out.println(doSome.getX());
DoSome<Integer> doSome1 =new DoSome();
doSome1.setX(new Integer(100));
System.out.println(doSome1.getX());
}
}
尖括号中,你传进去的是什么,T就代表什么类型。这就是泛型的最大作用,我们只需要考虑逻辑实现,就能拿给各种类来用。
1.4:泛型方法
public class FanxingMethodTest {
public <T> void normalMethod(T t){
System.out.println("normalMethod: "+t.toString());
}
public void method(String str){
System.out.println("method:"+str.toString());
}
public static void main(String[] args) {
FanxingMethodTest fanxingMethodTest=new FanxingMethodTest();
fanxingMethodTest.normalMethod(123);
fanxingMethodTest.normalMethod("字符串");
fanxingMethodTest.method("123");
}
}
2: 通配符
2.1: 通配符
非限定通配符
形如<?>,表示通配符泛型值接受所有类型。
限定通配符上限
<? extends T>表示该通配符所代表的类型是T类型及T类型的子类。
限定通配符下限
形如<? super T>,表示通配符所代表的类型是T类型的父类,只能接收T及其三层父类类型。
2.2: ?和 T 的区别
T 代表一种类型 (具体的java类型)
?是通配符,泛指所有类型,一般用于定义一个引用变量,这么做的好处是,如定义一个引用变量,就可以指向多个对象。表示不确定的java类型
T和?运用的地方有点不同,?是定义在引用变量上,T是类上或方法上
- ArrayList al=new ArrayList();指定集合元素只能是T类型
- ArrayList<?> al=new ArrayList<?>();集合元素可以是任意类型,这种没有意义,一般是方法中,只是为了说明用法
- ArrayList<? extends E> al=new ArrayList<? extends E>();
泛型的限定:
? extends E:接收E类型或者E的子类型。
?super E:接收E类型或者E的父类型。
2.3: Object跟泛型类区别
Object是所有类的根类,是具体的一个类,使用的时候可能是需要类型强制转换的,但是用T ?等这些的话,在实际用之前类型就已经确定了,不需要强制转换。
追问:
也就是说,这个方法能知道返回的是哪种类型(父类),就用T行了?如果完全不知道的就用?用T的得到的对象就不需要类型转换了,而用?的就必需用强转了!
追答:
第一种是固定的一种泛型,第二种是只要是Object类的子类都可以,换言之,任何类都可以,因为Object是所有类的根基类
固定的泛型指类型是固定的,比如:Interge,String. 就是
<? extends Collection> 这里?代表一个未知的类型,
但是,这个未知的类型实际上是Collection的一个子类,Collection是这个通配符的上限.
举个例子: class Test { }
其中,限定了构造此类实例的时候T是一个确定类型(具体类型),这个类型实现了Collection接口,但是实现 Collection接口的类很多很多,如果针对每一种都要写出具体的子类类型,那也太麻烦了,干脆还不如用Object通用一下。<? extends Collection>其中,?是一个未知类型,是一个通配符泛型,这个类型是实现Collection接口即可。
3: 泛型使用的注意事项
泛型类型参数不能使用基本数据类型指定,基本数据类型要写成其包装类型。
例如使用new ArrayList()是不合法的。因为类型擦除后会替换成Object(如果通过extends设置了上限,则替换成上限类型),int显然无法替换成Object,所以泛型参数必须是引用类型。泛型类型参数是使用new对象时确定。若不指定泛型类型,则默认使用Object类型。在JDK1.7以后,指定泛型可以省略最后"<>"中的类型。
4: 使用泛型的优势
- 减少了强制类型转换的操作
- 在编译时期进行类型检查,避免了很多运行时期才能发现的错误
本文地址:https://blog.csdn.net/qq_42843770/article/details/107343288