泛型
1. 泛型案例
package com.qfedu.a;
public class Demo1 {
public static void main(String[] args) {
print(10);
print(10.5);
print(false);
}
/*
* 重载 reload
* 1. 在同一个类内或者接口内
* 2. 要求方法名必须一致
* 3. 要求形式参数列表必须不一致。
* 4. 返回值类型无要求
* JVM 会根据实际参数的数据类型,选择合适的方法执行。
* 【注意】
* 形式参数列表不同,关注的是参数数据类型,非参数名称。
*
* 以下方法
* 1. 功能一致
* 2. 方法名称一致
* 不同点:
* 参数类型不同。
*
* 参数占位符!!!
public static void print(int num) {
System.out.println("int参数方法");
System.out.println(num);
}
public static void print(double num) {
System.out.println("double参数方法");
System.out.println(num);
}
public static void print(boolean ret) {
System.out.println("boolean参数方法");
System.out.println(ret);
}
*/
public static <T> void print(T t) {
System.out.println(t);
}
}
2. 泛型格式
格式:
<自定义无意义单个英文大写字母数据类型占位符>
常用:
<T> Type 类型
<E> Element 元素
<K> Key 键
<V> value 值
<R> Return 返回值
泛型主要功能
1. 增强方法,满足方法支持数据类型多样性,同时保证数据类型一致化。
2. 泛型常用于【集合】
3. 在 Stream 流开发中泛型存在大量使用。
任务:
方法功能一致,有且只有数据类型不同,通过泛型约束,将数据类型的决定权交给用户操作,提升方法的能力,降低开发压力。
泛型主要出现的三个位置:
1. 方法
2. 类
3. 接口
3. 泛型在方法中使用
格式:
权限修饰符 [static] <自定义泛型占位符> 返回类型 方法名(形式参数列表) {
方法体
}
要求:
1. 方法参数中必须有一个参数对应泛型类型,用于在用户调用当前方法时,传入的实际参数告知泛型对应的具体类型是哪一个。
2. 方法的返回类型和方法体内局部变量可以使用自定义泛型。
3. 单一方法使用泛型约束,方法参数必须有一个参数对应泛型类型。
tips:
[static] 表示可有可无1
package com.qfedu.a;
public class Demo2 {
public static void main(String[] args) {
test(10);
test(new Demo2());
Demo2 demo2 = new Demo2();
Double type = demo2.getType(1.5);
String type2 = demo2.getType("你好泛型");
Float type3 = demo2.getType(10.5F);
}
/**
* static 修饰静态成员方法,方法参数为自定义泛型 T
*
* @param <T> 自定义泛型占位符
* @param t 用户传入的实际参数约束泛型对应的具体数据类型
*/
public static <T> void test(T t) {
System.out.println(t);
}
/**
* 非 static 修饰的成员方法 ,方法的参数和返回值类型都是自定义泛型 T,
* 自定义泛型T 对应具体数据类型需要通过该方法调用过程中的实际参数来约束
*
* @param <T> 自定义泛型占位符
* @param t 用于传入的实际参数约束 T 对应的具体数据类型
* @return 用户传入实际参数约束返回值具体数据类型
*/
public <T> T getType(T t) {
return t;
}
}
4. 泛型在类中使用
格式:
class 类<自定义泛型占位符> {
类内成员方法可以使用类名声明的自定义泛型。
静态成员方法是否可以使用类名声明的自定义泛型???
}
package com.qfedu.a;
class TypeA<T> {
/**
* 方法的参数和返回值类型都是类名声明的自定义泛型, 需要通过类对象来约束泛型对应的具体
* 数据类型。
* @param t 自定义泛型
* @return 自定义泛型
*/
public T getType(T t) {
return t;
}
/**
* 方法的参数类型是自定义泛型类型,泛型对应的具体数据类型需要通过类对象约束。
* @param t 自定义泛型
*/
public void test(T t) {
System.out.println(t);
}
/*
* 类内静态成员方法是否可以使用类名声明的泛型
*
* 1. 静态成员方法在类文件加载阶段,已经具备执行能力,所有执行所需的必要内容都已经明确
* 权限修饰符,返回值类型,方法名,形式参数列表,方法体。
*
* 2. 类名声明的泛型需要在创建对象过程中,约束泛型对应的具体数据类型,
*
* 类内静态成员方法使用类名声明的泛型,直接报错。因为静态成员方法如果自定义泛型,可以通过方法
* 参数约束泛型对应的具体数据类型,从而保证方法在加载阶段已经具备执行能力。
* 但是使用类名声明的泛型,需要通过该实例化类对象约束对应数据类型,两者运行周期不同,无法合作,
* 导致冲突。
public static T staticMethod(T t) {
return t;
}*/
}
public class Demo3 {
public static void main(String[] args) {
/*
* 类名带有自定义泛型,泛型对应的具体数据类型,需要通过该创建类对象过程来
* 进行约束
* 格式:
* TypeA<String> t1 = new TypeA<String>();
* 当前 TypeA 对象 t1 其中所有的泛型对应具体数据类型都是 String 类型。
*/
TypeA<String> t1 = new TypeA<String>();
String str = t1.getType("字符串");
t1.test("泛型通过该创建对象明确数据类型为 字符串类型 String");
/*
* Integer 是对应基本数据类型 int 的包装类,在泛型中需要的类型不是基础类型,
* 需要类,这里可以使用 Integer 类等价于 int,而且 Integer 功能更强大
*/
TypeA<Integer> t2 = new TypeA<Integer>();
Integer i = t2.getType(10);
t2.test(200);
/*
* 一个类带有自定义泛型,如果在创建对象过程中,没有明确泛型对应的具体数据类型,
* 所有使用到泛型的位置都是对应 Object 类型,该方式不符合泛型要求,不建议使用。
*/
TypeA t3 = new TypeA();
Object obj = t3.getType(1000);
t3.test("随便任意类型");
}
}
5. 泛型在接口中使用
格式:
interface 接口名<自定义泛型> {
成员变量 缺省属性: public static final
接口中的成员变量不可以使用自定义泛型,因为成员变量使用 final 修饰,需要在定义时必须初始化,如果使
用泛型,无法明确数据类型,初始化任何数据无意义。所以成员变量不可以使用接口自定义泛型。
成员方法 缺省属性: public abstract
default修饰的默认方法有什么特征,必须有方法体
}
5.1 妻管严模式
/*
* 1. 妻管严模式
* 实现类遵从接口的过程中,接口直接明确泛型对应的具体数据类型。接口中所有方法使用到泛型
* 约束的位置都是对应接口明确的数据类型。
* 实现类完成接口中所有缺省属性为 public abstract 修饰方法和重写default默认方法
* 方法对应泛型位置都根据遵从接口过程中,明确泛型约束类型确定!!!
*/
class TypeB implements A<String> {
@Override
public String getType(String t) {
// TODO Auto-generated method stub
return t;
}
@Override
public void test(String t) {
// TODO Auto-generated method stub
System.out.println(t);
}
@Override
public String testDefault(String t) {
return t;
}
}
5.2 媳妇回娘家模式
/*
* 2. 媳妇回娘家模式
* 实现类遵从接口过程中,接口没有明确泛型对应具体数据类型,同时类名声明和接口一致的泛型占位符。
* 泛型对应具体数据类型,通过实例化实现类对象来进行约束,由调用者决定!!!
*/
class TypeC<T> implements A<T> {
@Override
public T getType(T t) {
return t;
}
@Override
public void test(T t) {
System.out.println(t);
}
}
TypeC<Integer> typeC = new TypeC<Integer>();
Integer i = typeC.getType(100);
typeC.test(200);
System.out.println(i);
Integer i2 = typeC.testDefault(500);
System.out.println(i2);
TypeC<Demo4> typeC2 = new TypeC<Demo4>();
typeC2.test(new Demo4());
Demo4 testDefault2 = typeC2.testDefault(new Demo4());
Demo4 type = typeC2.getType(new Demo4());