泛型

22 篇文章 0 订阅

泛型

1. 泛型
1.1 泛型概述
	润物细无声!!!
	泛型其实也是一种归纳总结思想的提升,对于数据处理的范围,参数的类型,方法操作的数据... 进行了二次剥离!!!
	代码中使用泛型之后,可以极大的提高对于代码的复用性,可移植性,可操作性。
1.2 泛型格式
Java中泛型规定:
	<自定义无意义英文大写单字母占位符>
	一般常用:
		<T> Type 
		<E> Element
		<K> Key
		<V> Value
泛型可以约束
	方法
	类
	接口
1.3【 补充知识点包装类】
Java中数据类型其实是分两大类
	1. 基本数据类型
		byte short int long float double char boolean
	2. 引用数据类型
	
Java中有一个概念
	万物皆对象。
	所以Java中对于基本数据类型也做了封装,完成了对于基本数据类型的【包装类】

基本数据类型对应的包装类
	byte    Byte
	short   Short
	int     Integer
	long    Long
	float   Float
	double  Double
	char    Character
	boolean Boolean
	1. 包装类的使用,可以满足Java中万物皆对象的操作规范,让代码操作更加统一化
	2. 包装类中对于数据类型提供了一定的【解析方法】,这些方法是需要我们学习的
	3. 包装类使用不会增加我们开发的压力,因为Java中提供了【自动包装】和【自动拆箱】
	
自动包装和自动拆箱
package com.qfedu.a;

/*
 * 自动包装和自动拆箱演示
 */
public class Demo1 {
	public static void main(String[] args) {
		// 基本数据类型
		int num1 = 10;
		
		// 基本数据类型赋值给包装类型,【自动包装】
		Integer num2 = num1;
		System.out.println(num2);
		
		// 包装类型可以直接赋值对应的基本数据类型,【自动拆箱】
		int num3 = num2;
		System.out.println(num3);
	}
}
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("想啥来啥~~~~");
		
		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;

/*
 * 类声明带有自定义泛型演示 
 * <T> 声明自定义泛型T
 */
class Demo<T> {
	/*
	 * 在带有泛型的类内,成员方法可以直接使用类声明的自定义泛型
	 */
	public void test1(T t) {
		System.out.println(t);
	}
	
	public T test2(T t) {
		return t;
	}
}

public class Demo5 {
	public static void main(String[] args) {
		/*
		 * 约束泛型的具体数据类型是String类型
		 * 
		 * 类内所有的成员方法中使用到泛型的位置都是String类型
		 */
		Demo<String> demo = new Demo<String>();
		
		demo.test1("你好");
		String test2 = demo.test2("大家好");
		
	
		/*
		 * 泛型约束当前 d 对象中所有的泛型都是Demo1类型
		 */
		Demo<Demo1> d = new Demo<Demo1>();
		d.test1(new Demo1());
		Demo1 test22 = d.test2(new Demo1());
		
		
		/*
		 * 未使用具体数据类型来约束对应的泛型
		 * 
		 * 当前d1调用所有类内使用泛型的方法,泛型对应的具体数据类型
		 * 都会变成Object类型,这样就有有悖于泛型的操作要求。
		 */
		Demo d1 = new Demo();	
	}
}
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
		该方法没有方法体

泛型在接口中使用的格式:
	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) {
		// TODO Auto-generated method stub
		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");
	}
}
2. 项目
2.1 任务目标
1. 自定义异常处理
	异常处理过程
2. 剥离排序算法核心内容,提高代码的利用率【重点】
	接口操作,插件式编程!!!
3. 完成数据的字符串处理过程
	数据 ==> 字符串 字符串 ==> 数据
2.2 项目中使用自定义异常
package com.qfedu.student.system.myexception;

/**
 * 自定义异常,用于创建StudentManager对象时
 * 用户传入的初始化容量不合法操作!抛出异常处理!!!
 * 
 * @author Anonymous
 *
 */
public class IllegalCapacityException extends Exception {

	private static final long serialVersionUID = 1L;

	public IllegalCapacityException() {}
	
	public IllegalCapacityException(String message) {
		super(message);
	}
}
package com.qfedu.student.system.myexception;

/**
 * 自定义异常,用于在StudentManager对象底层数组扩容的过程
 * 发现数组的容量超出了最大数组要求
 * @author Anonymous
 *
 */
public class OverflowMaxArraySizeException extends Exception {
	
	private static final long serialVersionUID = 1L;

	public OverflowMaxArraySizeException() {
	}

	public OverflowMaxArraySizeException(String message) {
		super(message);
	}
}
2.3 项目中排序方法核心操作剥离
2.3.1 生活逻辑引入接口操作
期望模型:
	排序算法就是一个红白机,主机
	排序要求就是一个游戏卡,可替换
	
游戏卡,SD卡,SIM
	有没有要求???
	接口有规范,有尺寸,有要求

需要使用Java中的接口格式吗?
	接口中的成员变量是一个常量!!!
	接口中规定了需要实现类完成的方法。

排序算法制定参数的类型为接口类型
	需要传入的数据时接口的实现类对象【多态】
	通过接口的实现类对象调用规定的比较方法,替换排序过程中的排序。
2.3.2 代码演示
比较接口规范
package com.qfedu.student.system.compare;

import com.qfedu.student.system.entity.Student;

public interface StudentCompare {
	/*
	 * 接口要求的方法分析
	 * 		返回值:
	 * 			boolean
	 * 		方法名:
	 * 	 		compare
	 * 		形式参数列表: 
	 * 			需要两个学生对象
	 * 			(Student stu1, Student stu2)
	 * 方法声明:
	 * 		boolean compare(Student stu1, Student stu2)
	 */
	/**
	 * 要求实现类完成的比较两个学生类对象的方法,具体的比较方式由实现类决定
	 * 
	 * @param stu1 Student类型
	 * @param stu2 Student类型
	 * @return 比较结果返回boolean
	 */
	boolean compare(Student stu1, Student stu2);
}

比较方法使用接口作为参数
/**                                                         
 * 按照成绩升序排序的算法                                              
 *                                                          
 * @param com 这里需要的参数类型是StudentCompare接口,要求传入的              
 * 			对象是StudentCompare接口实现类对象                        
 */                                                         
public void sortUsingCompare(StudentCompare com) {          
	/*                                                      
	 * 排序算法操作不能在原数据数组中进行直接操作,需要另外准备                         
	 * 一个用于排序的临时数组,这里就涉及到一个数据拷贝过程。                          
	 */                                                     
	Student[] sortTemp = new Student[size];                 
	                                                        
	for (int i = 0; i < sortTemp.length; i++) {             
		sortTemp[i] = allStus[i];                           
	}                                                       
	                                                        
	for (int i = 0; i < sortTemp.length - 1; i++) {         
		                                                    
		// 找出极值                                             
		int index = i;                                      
		                                                    
		for (int j = i + 1; j < sortTemp.length; j++) {     
			// 按照成绩升序排序                                     
			// 使用接口中规定的方法,替换比较规则!!!                         
			if (com.compare(sortTemp[index], sortTemp[j])) {
				index = j;                                  
			}                                               
		}                                                   
		                                                    
		// 交换位置                                             
		if (index != i) {                                   
			Student stu = sortTemp[index];                  
			sortTemp[index] = sortTemp[i];                  
			sortTemp[i] = stu;                              
		}                                                   
	}                                                       
	                                                        
	for (int i = 0; i < sortTemp.length; i++) {             
		System.out.println(sortTemp[i]);                    
	}                                                       
	                                                        
}                                                           
比较规则实现类
package com.qfedu.student.system.compare.impl;

import com.qfedu.student.system.compare.StudentCompare;
import com.qfedu.student.system.entity.Student;

/**
 * 学生成绩升序排序要求
 * 是StudentCompare接口的实现类对象
 * 
 * @author Anonymous
 *
 */
public class ScoreAscCompare implements StudentCompare {

	@Override
	public boolean compare(Student stu1, Student stu2) {
		return stu1.getScore() > stu2.getScore();
	}

}
package com.qfedu.student.system.compare.impl;

import com.qfedu.student.system.compare.StudentCompare;
import com.qfedu.student.system.entity.Student;

public class ScoreDescCompare implements StudentCompare {

	@Override
	public boolean compare(Student stu1, Student stu2) {
		return stu1.getScore() < stu2.getScore();
	}
}
                                                         
/*   
 * 调用过程,需要在之前代码中准备好需要排序的数据
 * 该方法要求的参数是StudentCompare接口,实际传入的内容是                  
 * StudentCompare接口 实现类 ScoreAscCompare对象                
 * 【多态】                                                  
 */                                                      
studentManager.sortUsingCompare(new ScoreAscCompare());  
System.out.println();                                    
                                                         
studentManager.sortUsingCompare(new ScoreDescCompare()); 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值