泛型 类 接口 方法 通配符

发布于:2025-02-14 ⋅ 阅读:(12) ⋅ 点赞:(0)

泛型

泛型类

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

image-20250206145118086

接口使用

接口后要立马接收参数 类型参数

类后要立马接收参数 类型参数

接口

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;
    }
}