泛型
泛型类
what:
类型参数化
why use:
1. 输出时候是object类型 而不是真正类型转化麻烦
import java.util.ArrayList;
import java.util.List;
public class ObjectExample {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
list.add("Hello");
list.add(123); // 可以添加任何类型的对象
// 运行时可能会出现 ClassCastException
String str = (String) list.get(1);
System.out.println(str);
}
}
一个盒子 什么类型都可以装
而不是 橘子 苹果 火龙果盒子
分别对应一个类
fault example:
package box;
import fruit.*;
public class box {
}
public class appleBox{
private apple apple;
private double length;
private double width;
private double heigth;
private double count;
private double weigth;
appleBox(){
}
appleBox(apple apple,double length,double width,double heigth,double count,double weigth){
this.apple = apple;
this.length = length;
this.width = width;
this.heigth = heigth;
this.count = count;
this.weigth = weigth;
}
public class orangeBox{
private orange orange;
private double length;
private double width;
private double heigth;
private double count;
private double weigth;
orangeBox(){
}
orangeBox(orange orange, double length, double width, double heigth, double count, double weigth){
this.orange = orange;
this.length = length;
this.width = width;
this.heigth = heigth;
this.count = count;
this.weigth = weigth;
}
public class pitayaBox{
private pitaya pitaya;
private double length;
private double width;
private double heigth;
private double count;
private double weigth;
pitayaBox(){
}
pitayaBox(pitaya pitaya,double length,double width,double heigth,double count,double weigth){
this.pitaya = pitaya;
this.length = length;
this.width = width;
this.heigth = heigth;
this.count = count;
this.weigth = weigth;
}
}
- 代码冗余:每个盒子类的逻辑几乎相同,只是类型不同,但需要重复编写。
- 扩展性差:如果需要支持更多类型的水果,就需要继续添加更多的盒子类。
- 维护困难:如果需要修改盒子的功能(如增加新的方法),需要在每个盒子类中逐一修改。
example:
bug1:构造函数不公开化 外部无法构造
/*
构造函数公开化
*/
public boxGeneric(T fruit, double length, double width, double heigth, double count, double weigth) {
this.fruit = fruit;
this.length = length;
this.width = width;
this.heigth = heigth;
this.count = count;
this.weigth = weigth;
}
泛型实例:
package box;
/*
what:
generic 类型参数化
*/
public class boxGeneric<T> {
/*
what:
不同部分只是水果类型 给他类型参数化
但是我接收时候只能接收一种水果类型 然后对应对象确定了 是 苹果盒子/橘子盒子 然后就当苹果盒子正常使用
*/
private T fruit;
private double length;
private double width;
private double heigth;
private double count;
private double weigth;
/*
构造函数公开化
*/
public boxGeneric(T fruit, double length, double width, double heigth, double count, double weigth) {
this.fruit = fruit;
this.length = length;
this.width = width;
this.heigth = heigth;
this.count = count;
this.weigth = weigth;
}
public T getFruit() {
return fruit;
}
public void setFruit(T fruit) {
this.fruit = fruit;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeigth() {
return heigth;
}
public void setHeigth(double heigth) {
this.heigth = heigth;
}
public double getCount() {
return count;
}
public void setCount(double count) {
this.count = count;
}
public double getWeigth() {
return weigth;
}
public void setWeigth(double weigth) {
this.weigth = weigth;
}
}
调用:
import box.boxGeneric;
import fruit.apple;
public class Main {
public static void main(String[] args) {
/*
使用泛型水果盒子
*/
apple apple = new apple();
boxGeneric<fruit.apple> appleboxGeneric = new boxGeneric<>(apple, 1, 1, 1, 1, 1);
System.out.println(appleboxGeneric.getFruit().getName());
}
}
apple类型
package fruit;
public class apple {
private final String name = "apple";
public String getName() {
return name;
}
}
语法
创建 参数化类
class boxGeneric<T>(T fruit){
T fruit;
}
创建泛型对象
new boxGeneric<>()
alt + enter
接口使用
接口后要立马接收参数 类型参数
类后要立马接收参数 类型参数
接口
package interfaceModle;
/*
what:
接口使用泛型 参数要紧紧跟着类呀
*/
public interface keyInterface<T> {
/*
接口函数返回类型为泛型
*/
T getKey();
}
使用1:实现泛型接口的类 不是泛型类 实现类不用接收参数类型 接口还要由实现类给出参数 那么 我们自己指定接口的类型参数
这时实现类使用接口时候 要给出接口的类型参数 因为外部无法给出参数类型 只能我自己给,如果实现类 不给接口参数 默认给接口Object类型
package imple;
import interfaceModle.keyInterface;
/*
非泛型类 要给接口类型参数
*/
public class keyImple implements keyInterface<String> {
@Override
public String getKey() {
return "This is a key ------ 并非generic 是由实现类直接指定类型";
}
}
main:
/*
what:
实现类直接指定类型 的 实现类返回信息
*/
public static void test2(){
keyImple keyImple = new keyImple();
System.out.println(keyImple.getKey());
}
使用2:实现类接收外部的类型参数 接口泛型参数由实现类给出 则接口的类型参数 可以与实现类参数一致 ,也可以直接由实现类给出
package imple;
import interfaceModle.keyInterface;
/*
what:
实现类接收类型参数 赋值给接口参数
*/
public class keyGenericImple<T,E> implements keyInterface<T> {
private T key;
private E value;
public keyGenericImple(T key, E value) {
this.key = key;
this.value = value;
}
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
@Override
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
}
main
/*
what:
实现类接收类型参数 发给接口的类型参数
确定类型参数 设置普通参数值 返回信息
*/
public static void test3(){
keyGenericImple<String, Integer> si = new keyGenericImple<>("你好", 114514);
String key = si.getKey();
Integer value = si.getValue();
System.out.println(key + " = " + value);
}
方法使用
在调用方法时候指明泛型的具体类型
泛型类 作用在 返回值 参数上 但 方法内部无法使用泛型
即 泛型类只在类内部使用 方法内部使用泛型需要泛型方法
how use:
- 泛型类后面紧接所需要的参数
- 泛型方法后面无需紧跟参数 但是 泛型方法需要被修饰所以泛型标志在函数名前面
- 能用泛型方法里的泛型E,类的泛型T也可以用
how set parameter:
类的传递参数写在类的后面
getProduct<Integer> gp = new getProduct<>();
接口的类型参数写作接口后面
方法的类型参数写在 修饰符那里
泛型方法的类型参数 只能通过接收参数时候设置 方法泛型类型 其他没地方接收类型参数呀。。。。
example:
类管类的内部 方法管方法的内部及 方法返回值 方法参数
方法和类 同一个类型参数T 时候 设置一个T = 方法和类全部设置
泛型类 + 泛型方法设置参数
泛型方法
package methodGeneric;
import java.util.ArrayList;
import java.util.Random;
/*
what:
给出任意类型列表 返回一个奖品
*/
public class getProduct<E> {
/*
what:
方法接收任意类型集合 返回一个奖品
how use:
方法类型参数 修饰作用 所以在最前面 声明后 该方法返回值 形式参数都可以使用该类型
接收任意类型奖品列表
how set type parameter:
1.接收参数时候设置参数中的类型参数时 设置方法类型的参数
*/
Random rand = new Random();
public <T> T getProductMethod(ArrayList<T> list) {
return list.get(rand.nextInt(list.size()));
}
}
传入泛型类 类型参数(类后面直接给出) 、泛型方法类型参数(方法参数设置参数)
/*
what:
给出字符串类型奖品列表 返回奖品
*/
public static void test4(){
ArrayList<String> list = new ArrayList<>();
list.add("笔记本电脑");
list.add("苹果手机");
list.add("安卓手机");
/*
what:
传给方法 抽出奖品
*/
getProduct<Integer> gP = new getProduct<>();
String product = gP.getProductMethod(list);
System.out.println("取出奖品为:" + product);
}
/*
what:
给出数字类型列表 抽出奖金
*/
public static void test5(){
ArrayList<Integer> products = new ArrayList<>();
products.add(1000);
products.add(20000);
products.add(300000);
getProduct<Integer> gP = new getProduct<>();
Integer product = gP.getProductMethod(products);
System.out.println("你的奖金为:" + product);
}
careout:
- 设置类泛型参数后 不一定设置方法的类型参数
- 类和方法类型参数名字就算一样 也是相互独立的
- 类的类型参数在实例化对象时设置
- 方法类型参数在接收 形式参数时设置
泛型类设置类型参数–成员方法 仅泛型类类型参数接收
泛型方法 任意类型参数接收
泛型类的成员方法 无法静态
泛型方法 可以静态 泛型方法不是泛型类的成员方法
泛型成员方法:
{
getProduct<Integer> gP = new getProduct<>();
/*
what;
数组
*/
int[] arr = {1000,20000,3000000};
ArrayList<Integer> products = new ArrayList<>();
for(int i = 0;i<arr.length;i++){
products.add(arr[i]);
}
/*
what:
泛型实例化 给成员方法得到奖品
*/
getProduct<Integer> gp = new getProduct<>();
Integer product0 = gp.getProduct0(products);
System.out.println(product0 + " " + product0.getClass().getName());
}
public class getProduct<E> {
Random rand = new Random();
/*
what:
泛型类的成员方法 成员方法全部依赖泛型类 比如 泛型类的类型参数
返回奖品
*/
public E getProduct0(ArrayList<E> list) {
return list.get(rand.nextInt(list.size()));
}
}
泛型方法;
public <T, E, K, V> void getMessage(T t,E e,K k,V v){
System.out.println(t + "\t" + t.getClass().getName());
System.out.println(e + " \t" + t.getClass().getName());
System.out.println(k + " \t" + k.getClass().getName());
System.out.println(v + " \t" + v.getClass().getName());
}
public static void test7(){
getProduct<Integer> gp = new getProduct<>();
gp.getMessage("aaa","bbb",false,true);
System.out.println("------------");
gp.getMessage(true,false,1,22.66);
}
泛型可变参数
泛型方法上E… e 泛型方法前设置修饰符
public static <E> void constantParameterPrint(E... e){
for(int i = 0;i<e.length;i++){
System.out.println(e[i]);
}
}
public static void test7(){
getProduct<Integer> gp = new getProduct<>();
gp.getMessage("aaa","bbb",false,true);
System.out.println("------------");
gp.getMessage(true,false,1,22.66);
System.out.println("------------");
gp.constantParameterPrint(1,2,3,4,5);
System.out.println("------------");
gp.constantParameterPrint('a','b','c','d','e');
}
类型通配符
difficult:
1.Box box 这是一个Box对象 指明Box对象形式参数 创建Box实例对象 而不是一个列表 ArrayLIst arrayList 创建一个ArrayList对象 指明 Number参数 创建arrayList 实例对象
why use:
在用泛型对象作为参数时候 相当于实例化对象 这时候要给对象泛型类型发参数,说明函数有泛型类 实例化对象时 我们已经给该泛型 实例化对象设置了 泛型的类型 这时候 多种类型传入函数(泛型类 实例化对象已经指定) 这时候就会报错
interge 与 Number 在泛型类型参数里不能当作 父亲接收子 多态来理解
solve:
- 方法重载?
- 同名 不能形式参数 尽管泛型的接收类型参数不一样 但是他们都是泛型类 所以相同的参数 无法重载
- Object 泛型类类型参数
- 那么不利于上层接收调用 以为是Object类型
在函数形式参数 泛型类实例化对象 用问号代替类型参数 该泛型类接收所有类型的类型参数 然后实例化形式参数
example:
package typeWildcard;
public class test {
/*
what:
模拟多次 不同类型的泛型对象传入含有通配符函数
返回Object类型 但是上一层强转类型即可
*/
public static void main(String[] args) {
Box<Number> box1 = new Box<>();
box1.setFirst(1);
Number o = (Number)showBox(box1);
System.out.println(o);
System.out.println("-------------");
Box<String> box2 = new Box<>();
box2.setFirst("函数的形式参数 实例化 接收全部类型");
String s = (String)showBox(box2);
System.out.println(s);
}
/*
what;
函数的形式参数 实例化也需要指定泛型类的类型参数 这样无法多态
public static void showBox(Box<Number> box){
Number first = box.getFirst();
}
what effect:
衬托无法多态 因为 形式参数 的类型都是泛型类 所以无法多态
public static void showBox(Box<Integer> box){
Number first = box.getFirst();
}
*/
/*
what:
1.对于函数形式参数为泛型类需要指明类型参数情况 使用问号 代表实例化时接收各种类型参数
2.咱们使用Object接收 但是直接返回上一层因为上一层知道这个object是声明类型呀!!!
*/
public static Object showBox(Box<?> box){
return box.getFirst();
}
}
~~~java
package typeWildcard;
/*
what:
泛型类 当个函数形式参数实例化参数时候 必须要指定泛型类型参数
*/
public class Box<T> {
T first;
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
}