泛型
1. 泛型
1.1 为什么要使用泛型
1. 泛型能够让代码更加具有普适性!!!
例如昨天的排序算法,目前支持的有且只有Worker数据类型
后期开发中,一定会涉及到很多种数据类型的排序,排序算法是一致的,不同的是排序规则,和排序处理的数据类型
可以使用泛型来对数据类型进行更高层级的处理
2. 泛型可以减少没有必要的强制类型转换!!!
3. 泛型可以在满足数据类型多样化的情况下,通过一定的条件约束,能够做到足够的数据类型一致化要求。
1.2 泛型的基本格式
格式:
<T> <E> <K> <V>
<自定义无意义单个大写英文字母泛型占位符>
可以使用的地方
1. 方法
2. 类
3. 接口
1.3 泛型在方法中使用
方法内使用自定义声明泛型
【强制要求】
方法使用的泛型,一定需要在参数中存在,用于约束当前方法使用的泛型占位符具
体数据类型是哪一个
package com.qfedu.a;
public class Demo1 {
public static void main(String[] args) {
String str = testType("字符串");
Integer i = testType(1);
Demo1 d1 = testType(new Demo1());
}
/**
* 带有自定义泛型<T>的方法,需要的参数和返回值类型都是泛型T
* 【重点】 泛型的具体数据类型是需要通过实际参数来约束的
*
* @param <T> 自定义泛型单个大写英文字母无意义占位符
* @param t 用户指定的数据类型,第一个是一个参数,第二用于约束T对应的具体数据类型
* @return 自定义泛型T 被约束之后的具体数据类型
*/
public static <T> T testType(T t) {
System.out.println(t.getClass());
return t;
}
}
package com.qfedu.a;
public class Demo2 {
public static void main(String[] args) {
/*
* int 和 Integer 之间的关系
* Integer 这是一个类 是 int 数据类型的包装类
*
* int 和 Integer可以无缝衔接,但是有一些不同之处。
*/
Integer[] arr = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
printArray(arr);
String[] strArr = {"七一建党", "八一建军", "十一国庆", "五一劳动", "六一儿童"};
printArray(strArr);
}
public static <T> void printArray(T[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
1.3 泛型在类内的使用
格式:
class 类名<自定义无意义单个大写字母占位符> {
类内的非静态成员方法可以使用自定义泛型
}
package com.qfedu.a;
/**
* 当前类带有自定义泛型
* 当前自定义泛型可以在类内的方法使用
* @author Anonymous
*
* @param <T>
*/
class TypeR<T> {
public void test(T t) {
System.out.println(t);
}
public T getType(T t) {
return t;
}
/*
* 静态方法是否可以使用类名声明的泛型
*
* 静态成员方法在类文件的加载阶段需要明确所有的内容。
*
* 类名声明的自定义泛型占位符是在创建类对象时,明确当前泛型
* 对应的具体数据类型是什么。
* 静态成员方法在类文件加载之后,已经可以通过类名直接调用。
*
* 生命周期存在一定的时间差!!!
*
*/
// public static T testStatic(T t) {
// }
/*
* 自娱自乐
*
* 通常情况下,静态方法自定义泛型会考虑和类名声明泛型不冲突!!!
*/
public static <E> E testStatic(E e) {
return e;
}
}
public class Demo3 {
public static void main(String[] args) {
/*
* 创建一个带有自定义泛型的类对象,格式如下
* Eclipse中:
* TypeR<String> typeR = new TypeR<String>();
* IDEA
* TypeR<String> typeR = new TypeR<>();
*
* 明确告知编译器,当前类对象typeR 自定义泛型对应的具体数据类型为String类型
*/
TypeR<String> typeR = new TypeR<String>();
// 类内所有使用到自定义泛型的位置都是String
typeR.test("测试");
String str = typeR.getType("大家注意身体");
// 当前约束之后,方法内所有使用到泛型的位置,都是Integer类型
TypeR<Integer> typeR2 = new TypeR<Integer>();
typeR2.test(10);
Integer type = typeR2.getType(10);
TypeR typeR3 = new TypeR();
/*
* 数据类型一致化!!!
*
* 一个类带有自定义泛型,在创建对象的过程中,没有约束泛型的具体数据类型,泛型 * 对应的所有类型都是Object类型
* 这样做有悖于泛型的使用要求,泛型使用是为了 提供代码的普适性,可变通性,但
* 是不能违背数据类型一致化要求。
*/
typeR3.test('六');
typeR3.test("就是这么牛");
typeR3.test(new Demo1());
}
}
1.4 泛型在接口中使用
格式:
interface 接口名<自定义泛型占位符> {
成员变量不得使用自定义泛型数据类型
接口中成员变量缺省属性为public static final
final修饰的成员变量,定义时必须初始化,在泛型没有明确数据类型之前,
无法针对当前数据类型进行合理的初始化操作。【不能使用】
接口中的方法可以使用自定义泛型
缺省属性方法
default默认方法
}
package com.qfedu.a;
interface A<T> {
/**
* 类内的缺省属性为public abstract方法,当前方法的返回值和参数类型
* 都使用了自定义泛型
*
* @param t 接口自定义的泛型数据类型
* @return 接口自定义的泛型数据类型
*/
T testA(T t);
/**
* 默认方法,default修饰方法,当前方法可以拥有方法体,该方法的返回值
* 和参数类型都是接口自定义泛型。
*
* @param t 接口自定义的泛型数据类型
* @return 接口自定义的泛型数据类型
*/
default public T testDefault(T t) {
return t;
}
}
/*
* 自由 Freedom
*
* 类名声明和实现接口一致的泛型使用,泛型对应的具体数据类型是依赖于
* 创建当前类对象时进行数据约束的。
*/
class TypeFreeDom<T> implements A<T> {
@Override
public T testA(T t) {
System.out.println(t.getClass());
return t;
}
}
/*
* 妻管严模式
*
* 遵从接口的过程中,已经明确当前泛型对应的具体数据类型是什么'
* 接下来所有接口中使用到泛型的方法,都是有接口之后的数据类型进行
* 约束。
*/
class QFY implements A<String> {
@Override
public String testA(String t) {
// TODO Auto-generated method stub
return null;
}
}
public class Demo4 {
public static void main(String[] args) {
TypeFreeDom<String> tf = new TypeFreeDom<String>();
String testA = tf.testA("测试呢");
String testDefault = tf.testDefault("测试默认方法");
TypeFreeDom<Character> tf2 = new TypeFreeDom<Character>();
tf2.testA('A');
tf2.testDefault('A');
new QFY().testA("围城");
new QFY().testDefault("城堡");
}
}
网友评论