沈阳集团网站建设,王烨江婉柔,做网站需要掌握的技术,专业律所网站建设在定义类、接口和方法时#xff0c;泛型使类型(类和接口)成为参数。与方法声明中使用的形参非常相似#xff0c;类型参数为您提供了一种方法#xff0c;可以用不同的输入重用相同的代码。不同之处在于形式参数的输入是值#xff0c;而类型参数的输入是类型。
使用泛型有许…在定义类、接口和方法时泛型使类型(类和接口)成为参数。与方法声明中使用的形参非常相似类型参数为您提供了一种方法可以用不同的输入重用相同的代码。不同之处在于形式参数的输入是值而类型参数的输入是类型。
使用泛型有许多好处
1、在编译时加强类型检测
通过使用泛型可以在编译时捕获和修复类型错误从而避免在运行时出现 ClassCastException 等类型转换异常。这提高了代码的可靠性和稳定性。
2、消除类型转换
使用泛型可以避免一些操作的强制类型转换
3、提高代码重用性
泛型可以使代码更加通用可以编写一次代码来处理多种类型的数据。
4、提高性能
泛型是在编译时进行类型检查的因此可以避免在运行时进行类型转换从而提高了程序的性能。
泛型定义
泛型可以定义在类接口和方法上。泛型使用 来指定泛型类型。
public class AminalT {private T flag;public T getFlag() {return flag;}public Aminal(T x){this.flag x;}public static void main(String[] args) {AminalString a1 new Aminal(a);AminalInteger a2 new Aminal(2);System.out.println(a1.getFlag());System.out.println(a2.getFlag());}
}如上类变量flag在class定义时候指定为泛型在对应使用泛型变量flag的地方都需要使用泛型进行接收和传递。
常见的泛型类型标识
E - Element表示元素常见于JDK的集合框架中
K - Key键
V - Value值
N - Number数字
T - Type 类型
S, U, V等 - 第2个、第3个、第4个类型
上面这些泛型类型标识只是一种约定不会强制进行校验你也完全可以自定义如下
public class FruitXXX {private XXX price;XXX getPrice(){return price;}void setPrice(XXX price){this.price price;}public static void main(String[] args) {FruitDouble f1 new Fruit();f1.setPrice(2.1d);FruitInteger f2 new Fruit();f2.setPrice(5);}
}上面使用XXX来表示类型一样可以正常编译使用。
多个泛型
定义泛型时可以指定多个泛型类型多个之间使用隔开
public class PairK,V {K key;V value;public Pair(K k,V v){this.key k;this.value v;}public static void main(String[] args) {PairInteger,String pair new Pair(666,泛型);System.out.println(pair.value);}
}泛型方法
泛型方法相比于普通方法的声明还会在返回值前使用 来声明使用的泛型参数列表
public static T ListT fromArrayToList(T[] a) {return Arrays.stream(a).collect(Collectors.toList());
}这里需要主要一点类上的泛型在类方法上都可以直接使用注意是非静态方法不用在方法上声明。
泛型类型限定
可以限定泛型为某个类的子类或实现了某个接口使用extends来指定父类。
public static T extends Number float plus(T a ,T b){
return a.floatValue() a.floatValue();
}如果要限定多个条件可以使用 来连接。
T extends Number Comparable通配符限定
在泛型代码中问号?被称为通配符用来表示未知类型。通配符可以在多种情况下使用作为参数、字段或局部变量的类型有时作为返回类型尽管最好的编程实践是更加具体。通配符永远不会被用作泛型方法调用的类型参数泛型类的实例创建或者超类型。
通配符限定只能使用在引用类型上是是对泛型的限定。可以限定泛型的上界和下界。
? extends Foo
? super Foo 上界? extends Foo表示泛型最高类型是Foo只能是Foo及其子类。
下界? super Foo表示泛型最低类型是Foo只能是Foo及其父类。
无界? 表示没有类型限制
例如
public void printFruits(List? extends Fruit fruits) {for (Fruit fruit : fruits) {System.out.println(fruit);}
}这里入参约束成Fruit的上界也就是入参只能是实现了Fruit接口的类这样在方法体中就可以调用Fruit接口统一的方法来完成逻辑操作。这里一定要理解 extends和 T extends的区别。extends是针对引用类型也就是实际参数而T extends是方法或类的定义上。
类型擦除Type Erasure
Java 中的泛型在编译时会进行类型擦除Type Erasure。类型擦除是 Java 泛型实现的一种机制它允许你在编译时使用泛型类型(也就是在编码是进行检测)但在运行时使用的是原始类型。在编译时泛型类型参数被擦除并替换为其边界或 Object 类型。
验证泛型擦除可以使用反射来操作class。
如下定义类
public class ErasureTestT,X extends Number {T t;X x;public void setT(T t){this.t t;}
}通过反射打印类信息
Class c ErasureTest.class;
for (Field field : c.getDeclaredFields()) {System.out.println(field.getName():field.getType());
}
for (Method method : c.getDeclaredMethods()) {System.out.println(method.getName():);Class[] params method.getParameterTypes();for (int i 0; i params.length; i) {System.out.println(参数params[i].getName(),类型params[i].getTypeName());
}
/**
输出内容
t:class java.lang.Object
x:class java.lang.Number
setT:
参数java.lang.Object,类型java.lang.Object
*/这里可以看到X extends Number转换成了其上界NumberT转换成了其原始类型Object。
擦除带来的问题
由于擦除通过反射在对方法进行调用时可以跳过类型约束
ListString list new ArrayList();
list.add(haha);
Method addMethod list.getClass().getDeclaredMethod(add, Object.class);
addMethod.invoke(list,Integer.valueOf(1));
System.out.println(list);如上代码定义了一个String型的list但是我们通过反射成功的往list添加了一个Integer类型的上面的代码可以正常执行。这就可以绕过泛型限定。