泛型和项目
1. 泛型
1.1 泛型体验卡
补充知识点 方法的重载
方法的重载 reload
- 要求在同一个类内, 或者同一个接口内
- 要求方法名必须一致
- 要求方法形式参数类型必须不一致,调用方法的过程中通过实际参数列表数据类型,选择合适的方法
作用:
1. 降低方法冗余
2. 提供方法处理的多样性
package com.qfedu.a_genericity;
public class Demo1 {
public static void main(String[] args) {
print(10);
print(10.5);
}
/*
* 方法的重载 reload
* 1. 要求在同一个类内, 或者同一个接口内
* 2. 要求方法名必须一致
* 3. 要求方法形式参数类型必须不一致,调用方法的过程中通过实际参数列表数据类型,选择合适的方法
*
*
* 作用:
* 1. 降低方法冗余
* 2. 提供方法处理的多样性
*/
public static void print(int num) {
System.out.println("int:" + num);
}
public static void print(double num) {
System.out.println("double:" + num);
}
}
泛型的第一个案例
public class Demo2 {
public static void main(String[] args) {
/*
方法形式参数列表数据类型 T 对应的具体数据类型,是由实际参数来决定的!!!
print(10);
print(false);
print(10.5);
print(10.56F);
}
/**
* 带有泛型约束的方法
* @param <T> 自定义泛型声明
* @param t 泛型对应类型
*/
public static <T> void print(T t) {
System.out.println(t);
}
1.2 泛型语法规则
泛型主要功能是为了增强【方法】
1. 单一增强
2. 批量增强(类和接口)
格式:
<自定义无意义单一大写英文字母泛型占位符> 泛型声明
常用占位符
<T> Type 类型
<E> Element 元素
<K> Key 键
<V> Value 值
<R> Return 返回值
泛型可以利用到的位置:
1. 泛型直接约束方法
2. 泛型约束类,类内的成员方法可以使用类声明泛型
3. 泛型约束接口,接口内成员方法可以使用接口声明泛型
1.3 自定义泛型约束方法
首先必须有泛型声明,告知编译器当前方法使用自定义泛型
格式:
权限修饰符 是否静态 <泛型占位符> 方法名(形式参数列表)
【重点/注意】
形式参数列表中必须有一个参数对应自定义泛型,用于明确泛型对应的具体数据类型。
package com.qfedu.a_genericity;
public class Demo3 {
public static void main(String[] args) {
// 实际参数为 int类型
test(10);
Integer i = getType(20);
// 实际参数为 Demo3 类对选哪个
// 匿名对象直接作为方法的参数
test(new Demo3());
Demo3 ds = getType(new Demo3());
// 实际参数为字符串类型
test("字符串类型");
String str = getType("字符串");
}
/**
* 方法参数使用了自定义泛型,泛型对应得到具体数据类型由实际参数决定
*
* @param <T> 自定义泛型声明
* @param t 泛型参数,利用用户提供的实际参数,约束泛型对应的具体数据类型
*/
public static <T> void test(T t) {
System.out.println(t);
}
/**
* 方法参数和返回值使用了方法声明的自定义泛型,要求方法参数中的泛型参数约束 泛型对应具体数据类型
*
* @param <T> 自定义泛型声明
* @param t 泛型参数,利用用户提供的实际参数,约束泛型对应的具体数据类型
* @return 自定义泛型类型,泛型对应的具体数据类型由实际参数数据类型决定
*/
public static <T> T getType(T t) {
return t;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fiPWcqyV-1667833887157)(D:\AQF\teacher\Day17\img\微信图片_20221107105032.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vyxjTt6M-1667833887160)(D:\AQF\teacher\Day17\img\微信图片_20221107105117.png)]
1.4 自定义泛型约束类 ==> 类中的方法
格式:
class 类名 <自定义泛型占位符> {
成员变量 ==> 目前阶段不建议使用自定义泛型
成员方法 ==> 【重点】 泛型约束内容
构造方法 ==> 目前阶段不建议使用自定义泛型
}
类名声明的自定义泛型用不成员方法使用数据类型约束
package com.qfedu.a_genericity;
/**
* 自定义类型 带有自定义泛型 <T>
* 【注意】
* 一个类带有自定义泛型,泛型对应的具体数据类型,由实例化对象过程约束
*
* 具体格式如下:
* TypeA<String> t1 = new TypeA<String>();
*
* 数据类型和构造方法名,之后都有一个尖括号明确数据类型,
* 明确的数据类型就是用于约束泛型对应的具体数据类型
* 目前 TypeA<String> t1 对象,所有成员方法使用到自定义泛型的位置都是 String
* t1 对象调用的方法
* public void test(String t);
* public String getType(String t);
*
*
* @author lenovo
*
* @param <T>
*/
class TypeA<T> {
/**
* 成员方法,可以直接利用类名声明的自定义泛型,无需再次声明
*
* @param t 自定义泛型
*/
public void test(T t) {
System.out.println(t);
}
/**
* 成员方法,方法参数和返回值类型是类名声明的自定义泛型
*
* @param t 自定义泛型
* @return 自定义泛型
*/
public T getType(T t) {
return t;
}
/*
public static void testStatic(T t) {
System.out.println(t);
}
*/
}
public class Demo4 {
public static void main(String[] args) {
// 实例化对象过程中,约束当前 TypeA t1 对象使用泛型对象具体数据类型为 String
TypeA<String> t1 = new TypeA<String>();
// 所有带有泛型 <T> 占位符对应的位置都是 String 类型
t1.test("字符串");
String str = t1.getType("字符串 String 类型");
System.out.println(str);
// 实例化对象过程中,约束当前 TypeA t2 对象使用泛型对应具体数据类型为 Integer <==> int
TypeA<Integer> t2 = new TypeA<Integer>();
// 目前所有 t2 对象使用的方法泛型位置都是 Integer 类型 <==> int 类型
t2.test(10);
Integer i = t2.getType(20);
System.out.println(i);
// 实例化 TypeA 类型,没有约束泛型对应的具体数据类型, Eclipse 有警告!!!
// t3 对象的泛型对应的是什么类型??? 泛型所有位置都是 Object 类型
TypeA t3 = new TypeA();
/*
* 什么是 Object 类型
* Object 类型是 Java 中所有类型的父类, 是 Java 最大的数据类型
* 万物皆对象,万物皆 Object
*
* 带有自定义泛型约束的类,没有在实例化对象过重,明确泛型对应的具体数据类型,
* 所有泛型 对应位置都是 Object 类型,这只是 Java 编译器的权宜之计
* 咱们开发禁止使用。
* 缺乏了数据类型明确,和数据类型的一致化要求
*
*/
t3.test(1);
t3.test('A');
t3.test("Object");
t3.test(new Demo4());
Object o1 = t3.getType(10);
Object o2 = t3.getType("字符串");
}
}
思考题:
就目前而言,TypeA 类中是否可以定义 static 修饰的静态成员方法,直接使用类名声明的自定义范???
1. 类名声明的自定义泛型什么时候明确约束对应的具体数据类型???
实例化对象过程中约束
2. static 修饰的静态成员方法是在类文件加载阶段语句已经准备就绪,已经具备执行能力。
权限修饰符,静态标记,返回值类型,方法名,形式参数列表,方法体
3. static 如果可以使用类名声明的自定义泛型,存在一个问题
在类加载阶段,泛型对应的具体数据类型不明确,无法使用
静态成员方法自定义声明泛型,自行使用,泛型对应的具体数据类型是由实际参数来约束的
如果静态成员方法使用类名对应的自定义泛型,泛型需要在实例化对象过程中明确约束,和静态成员声明周期不统一
4. 类声明泛型需要实例化对象,但是静态成员方法【没有对象】
1.5 自定义泛型约束接口 ==> 接口中方法
格式:
interface 接口<自定义泛型占位符> {
成员变量 缺省属性:public static final 要求定义时必须初始化
final 关键字要求成员变量定义时必须初始化
泛型在定义阶段没有明确的数据类型,无法进行合理合适的初始化
【接口中成员变量无法使用自定义泛型】
成员方法 缺省属性:public abstract 要求当前方法没有方法体
default 修饰的默认方法: JDK 1.8 以上版本支持,允许方法有方法体
}
语法总结:
1. 接口中的成员变量不能使用自定义泛型
2. 接口中 缺省属性为 public abstract 修饰方法和 default 关键字修饰方法都可以使用接口声明的自定义泛型。
interface A<T> {
// 接口中缺省属性为 public abstract 修饰方法可以使用接口声明自定义泛型
void test(T t);
T getType(T t);
// default 关键字修饰的默认方法也可以使用接口声明自定义泛型
default void testDefault(T t) {
System.out.println(t);
}
}
自由模式
package com.qfedu.a_genericity;
interface A<T> {
// 接口中缺省属性为 public abstract 修饰方法可以使用接口声明自定义泛型
void test(T t);
T getType(T t);
// default 关键字修饰的默认方法也可以使用接口声明自定义泛型
default void testDefault(T t) {
System.out.println(t);
}
}
/*
* 1. 自由模式
* 泛型对应的具体数据类型由实现类自行决定
*
* 2. 卑微模式
* 泛型对应的具体数据类型在实现类遵从接口的过程中直接约束
*/
/**
* 自由模式:
* 实现类声明和接口泛型一致的泛型占位符,由实例化对象过程对泛型数据类型进行约束和明确
* @author lenovo
*
* @param <T> 占位符
*/
class TypeB<T> implements A<T> {
@Override
public void test(T t) {
System.out.println(t);
}
@Override
public T getType(T t) {
return t;
}
}
public class Demo5 {
public static void main(String[] args) {
// 实例化 TypeB 对象,泛型约束为 String 类型
TypeB<String> t1 = new TypeB<String>();
/*
* t1 对象对应方法所有泛型位置都是 String 包括实现接口中的 public abstract 修饰方法
* 以及接口中 default 关键字修饰的默认方法
*/
t1.test("实现类遵从接口要求完成的方法,参数泛型目前对应的为 String 类型");
t1.testDefault("接口 default 修饰的默认方法,方法泛型对应的具体数据类型根据当前实例化 TypeB 对象 t1 明确为 String 类型");
String string = t1.getType("实现类遵从接口要求完成的方法,方法参数和返回值类型对应泛型具体数据类型为 String leiixng ");
System.out.println(string);
/*
* t2 对象泛型约束为 Integer 类型, 类内所有接口缺省属性为 public abstract 方法实现和 default 默认方法
* 泛型对应具体数据类型都是 Integer 类型
*/
TypeB<Integer> t2 = new TypeB<Integer>();
t2.test(10);
t2.testDefault(200);
Integer i = t2.getType(10000);
System.out.println(i);
}
}
卑微模式
package com.qfedu.a_genericity;
/**
* 卑微模式:
* 类遵从带有自定义泛型的接口,遵从过程中,接口直接明确泛型对应的具体数据类型
* 接口实现类所有使用到泛型的位置都是接口明确约束的泛型类型
*
* 当前 TypeC 类泛型对应的具体数据类型为 String
* @author lenovo
*
*/
class TypeC implements A<String> {
@Override
public void test(String t) {
System.out.println(t);
}
@Override
public String getType(String t) {
return t;
}
}
public class Demo6 {
public static void main(String[] args) {
TypeC t1 = new TypeC();
t1.test("接口泛型在遵从过程中明确为 String 类型");
t1.testDefault("接口泛型在遵从过程中明确为 String 类型");
String type = t1.getType("字符串");
System.out.println(type);
}
}
1.6 总结
泛型:
1. 泛型主要目的是增强方法,是满足方法数据类型支持的多样性,都是严格遵从数据类型一致化要求。
一旦约束泛型对应的具体数据类型,数据类型无法修改!!!
2. 泛型在单一约束方法
【明确要求】 方法参数必须要有一个对应自定义泛型类型
3. 泛型在类声明使用
【明确要求】泛型对应的具体数据类型由实例化过程约束,并且【强烈要求】必须约束!!!不可以使用 Object
4. 泛型在接口声明使用
自由模式:实现类实例化对象自由
卑微模式:实现类遵从接口,接口明确要求
程中明确为 String 类型");
t1.testDefault(“接口泛型在遵从过程中明确为 String 类型”);
String type = t1.getType("字符串");
System.out.println(type);
}
}
##### 1.6 总结
泛型:
1. 泛型主要目的是增强方法,是满足方法数据类型支持的多样性,都是严格遵从数据类型一致化要求。
一旦约束泛型对应的具体数据类型,数据类型无法修改!!!
2. 泛型在单一约束方法
【明确要求】 方法参数必须要有一个对应自定义泛型类型
3. 泛型在类声明使用
【明确要求】泛型对应的具体数据类型由实例化过程约束,并且【强烈要求】必须约束!!!不可以使用 Object
4. 泛型在接口声明使用
自由模式:实现类实例化对象自由
卑微模式:实现类遵从接口,接口明确要求