目录
1. 泛型
1.1 泛型概述
润物细无声!!!
泛型其实也是一种归纳总结思想的提升,对于数据处理的范围,参数的类型,方法操作的数据... 进行了二次剥离!!!
代码中使用泛型之后,可以极大的提高对于代码的复用性,可移植性,可操作性。
1.2 泛型格式
Java中泛型规定:
<自定义无意义英文大写单字母占位符>
一般常用:
<T> Type
<E> Element
<K> Key
<V> Value
泛型可以约束
方法
类
接口
1.4 泛型在方法中使用【重点】
1.4.1 格式概述
格式:
权限修饰符 [static] <自定义泛型> 返回值类型 方法名(形式参数列表) {
}
【重点】
1. 要求形式参数列表中必须有一个参数是当前自定义泛型,因为需要通过参数来约束当前方法运行过程中泛型对应的具体数据类型是哪一个。
2. 返回值类型可以使用自定义泛型,而且是被形式参数列表中传入的泛型对应具体数类型控制。(也可以没有返回值或者是其他类型的返回值)
3. 方法体内也可以使用自定义泛型,同时也是被参数当中泛型对应具体数据类型约束监控
1.4.2 代码演示
package com.qfedu.a;
/*
* 自定义泛型在方法中使用【重点】
*/
public class Demo2 {
public static void main(String[] args) {
// <Integer> Integer com.qfedu.a.Demo2.getType(Integer t)
Integer type = getType(1);
Float type2 = getType(3.14F);
Demo2 type3 = getType(new Demo2());
String type4 = getType("这方法有点东西哦~~~~");
}
/**
* 带有自定义泛型 T 对应的方法
*
* @param <T> 自定义泛型无意义英文单个大写字母占位符
* @param t T类型
* @return T类型
*/
public static <T> T getType(T t) {
return t;
}
}
1.4.3 自定义泛型使用案例
package com.qfedu.a;
/*
* 自定义泛型在方法中使用案例
*/
public class Demo3 {
public static void main(String[] args) {
printEverything(1);
printEverything(3.14);
printEverything(3.14F);
printEverything("想啥来啥~~~~");
// 这里的数组需要是包装类
// printAnyType(new int [10]); 这句话会报错
printAnyType(new Integer[10]);
printAnyTypeArray(new Integer[10]);
printAnyTypeArray(new String[10]);
printAnyTypeArray(new Demo3[10]);
}
/*
* 需求
* 完成一个可以满足任意类型展示的方法
*/
public static <T> void printEverything(T t) {
System.out.println(t);
}
/*
* 需求
* 完成一个方法可以满足展示任意类型数组
*/
public static <T> void printAnyTypeArray(T[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
/*
public static void printIntArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void printDoubleArray(double[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
*/
/*
* 一下方法操作过程是一致的,处理方式是一致的,只有参数类型不一样
* 封装 升华参数类型,使用泛型替代
public static void printInt(int i) {
System.out.println(i);
}
public static void printDouble(double d) {
System.out.println(d);
}
public static void printFloat(float f) {
System.out.println(f);
}
*/
}
1.4.4 Object和泛型的对比
package com.qfedu.a;
/*
* Object和泛型的对比
*
*/
public class Demo4 {
public static void main(String[] args) {
/*
* Object参数操作
* 代码中所有的返回值都是Object类型,然后需要操作对应的真实类型
* 要求完成强制类型转换,操作对于数据没有影响,但是有点繁琐
*/
Object type = getType(1);
Object type2 = getType("你好");
Object type3 = getType(new Demo1());
/*
* 泛型参数操作
* 泛型约束之后,返回值类型就是对应的具体数据类型,不需要强制类型
* 转换操作,提高了开发效率
*/
Integer type22 = getType2(1);
String type23 = getType2("你好");
Demo1 type24 = getType2(new Demo1());
}
public static Object getType(Object obj) {
return obj;
}
public static <T> T getType2(T t) {
return t;
}
}
1.5 泛型在类中使用【重点】
1.5.1 格式概述
有那么一大堆方法都要使用泛型,而且这些方法还有一定的关联性。使用类【封装】这些方法,将泛型的声明用于类名上,做到一个统一的约束过程。
【始终强调的是方法!!!】
格式:
class 类名<自定义泛型无意义英文大写单个字母占位符> {
// 成员变量不推荐使用泛型,存在一定的隐患,操作不方便
// 成员方法可以使用类名声明的自定义泛型
// 静态成员方法是个坑!!!
}
类名使用泛型约束具体数据类型的格式【重点】
案例:
class Demo<T> {
}
Eclipse:
类名<具体数据类型> 类对象 = new 构造方法<具体数据类型>();
例:
Demo<String> demo = new Demo<String>(); √标准格式
Demo<String> demo = new Demo<Integer>(); 类型不一致报错 ×
Demo<Object> demo = new Demo<String>(); 类型不一致报错 ×
IDEA:
类名<具体数据类型> 类对象 = new 构造方法<>();
例如:
Demo<String> demo = new Demo<>(); √标准格式
1.5.2 代码案例
package com.qfedu.a;
/**
* 带有【自定义泛型】的类:统一一堆【方法】需要使用泛型,可用类将其封装起来
* 【强调的是方法】
*
* class 类名<自定义泛型无意义英文大写单个字母占位符> {
* 成员变量不推荐使用泛型,存在一定的隐患,操作不方便
* 成员方法可以直接使用类名声明的自定义泛型(生成对象时)
* 静态成员方法自己玩自己的,是个坑
* }
* @author GGGXXC
*
*/
public class Demo5 {
public static void main(String[] args) {
/*
* 泛型创建对象语法:
* 泛型的约束类型为:String类型
* 对象内的所有成员方法中使用到的泛型都是String内容
*/
Demo<String> demo = new Demo<String>();
demo.test1("你好");
String test2 = demo.test2("大家好");
/*
* 未使用泛型约束将会转成object类型
*/
Demo a = new Demo();
a.test1(test2);
}
}
/*
* 类声明带有自定义泛型
* <声明自定义泛型>
*/
class Demo<T> {
/*
* 带有泛型的类,成员方法可以直接使用类声明的自定义泛型
*/
public void test1(T t) {
System.out.println(t);
}
public T test2(T t) {
return t;
}
}
1.5.3 泛型在类内使用的小总结
1. 类内的成员方法可以直接使用对应的类名声明泛型
2. 类内成员方法使用的泛型具体数据类型是在创建当前类对象是约束。
3. 在创建当前类对象时没有约束泛型对应的具体数据类型,那么所有使用到泛型的位置都是Object类型,有悖于泛型使用原则
4. 类中使用泛型,是在满足代码普适性的情况下,有可以兼顾数据类型一致化要求。有的放矢
1.5.4 静态成员方法能不能使用类名声明的自定义泛型
类名声明的自定义泛型是什么时候确定对应具体数据类型?
这里是在调用构造方法时,创建当前对象过程中,对于当前泛型约束具体数据类型进行操作。
Demo<String> d = new Demo<String>();
静态成员方法是什么时候加载的?加载有什么要求?
当前程序运行过程中对于当前类有需求,需要加载当前类文件,同时会加载当前类文件中的所有静态资源
静态成员方法在加载的过程需要明确所有运行所需的必要条件。已经是可以直接运行的状态。
类名声明的自定义泛型是在对象创建过程中明确数据类型的,但是静态成员方法是在类文件加载阶段就需要明确所有内容。生存周期不合理!!!
【没有对象】
【注意】
在带有自定义泛型的类内,静态成员方法需要使用泛型,自娱自乐,自己定义泛型,自己使用。参考【泛型在方法中使用】
1.6 泛型在接口中使用【重点】
1.6.1 格式概述
接口:
成员变量:
缺省属性: public static final
定义时必须初始化
成员方法:
缺省属性: public abstract
该方法没有方法体
有方法体如何使用:
default修饰默认方法,非强制实现方法
泛型在接口中使用的格式:
interface 接口名<自定义泛型无意义英文单个字母大写占位符> {
自定义泛型有且只能给方法使用!!!
}
【接口中的成员变量不能使用自定义泛型】
1. 成员变量缺省属性public static final 定义时必须初始化,但是泛型初始化没有具体的数据类型,无法进行初始化操作
2. 成员变量static修饰,当前成员变量需要在加载阶段,明确所有内容,但是当前情况下,数据类型不明确的。
有悖于语法的!!!
1.6.2 带有泛型的接口怎么用
接口没有自己的类对象
1. 接口不是类
2. 接口中存在未完成的方法,就算是有对象,也得报错的。
带有泛型的接口使用需要依赖于实现类完成。这里有两种方式
1. 自由
2. 乖巧
1.6.3 代码演示
package com.qfedu.a;
/**
* 带有自定义泛型的接口
*
* @author Anonymous
*
* @param <T> 自定义泛型
*/
interface A<T> {
/**
* 当前成员方法缺省属性为public abstract 没有方法体
* @param t T类型
* @return T类型
*/
T test(T t);
}
/**
* 自由方式
* 实现类使用和接口相同的泛型,泛型对应具体数据类型在创建
* 当前类对象时明确
*
* @author Anonymous
*
* @param <T>
*/
class TypeA<T> implements A<T> {
@Override
public T test(T t) {
System.out.println("未明确泛型具体数据类型操作方式,自由");
return t;
}
}
/**
* 乖巧模式
* 实现类在遵从带有自定义泛型的接口时,接口中泛型的具体数据类型已经确认
* 实现类完成的对应方法就OK
*
* @author Anonymous
*
*/
class TypeB implements A<String> {
@Override
public String test(String t) {
return "你好";
}
}
public class Demo7 {
public static void main(String[] args) {
// 在创建对象的过程过程中约束泛型的具体数据类型。
TypeA<Integer> t1 = new TypeA<Integer>();
t1.test(1);
TypeA<Demo1> t2 = new TypeA<Demo1>();
t2.test(new Demo1());
// typeB完成的方法test,要求的参数已经被接口约束
TypeB typeB = new TypeB();
typeB.test("123123");
}
}