自定义泛型类

如何自定义泛型结构:泛型类,泛型接口,泛型方法
泛型类和泛型接口的区别主要是类和接口的区别,所以就不去举泛型接口的例子
自定义泛型类:
以前我们定义的类的元素是非常确定的,但我们可能会涉及到这个类有一个属性,这个属性类型不太确定,可以给类加上泛型,泛型用大写字符表示:通常用T,E,K,V(K,V更多的运用在键值对的泛型中)
类的内部结构就可以使用类的泛型,下面的程序中把T称为类的泛型
接口中不能有构造器

//在实例化的时候指明T到底是什么类型
public class Order<T>{
    String orderName;
    int orderId;

    T orderT;
    public Order(){

    }
    public Order(String orderName,int orderId,T orderT){
        this.orderName=orderName;
        this.orderId=orderId;
        this.orderT=orderT;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }

    public T getOrderT() {
        return orderT;
    }

    public void setOrderT(T orderT) {
        this.orderT = orderT;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }
}

集合当中在List声明了泛型,ArrayList实现了它,这个泛型也保留了
Order是一个自定义的泛型类,在实际开发中如果需要提供Order的子类SubOrder,继承于Order
如果像这样进行了指明,造SubOrder的对象的时候,就不用加尖括号了(不用写成SubOrder<>了)

 class SubOrder extends Order<Integer>{
}

可以直接这么写
由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不再需要指明泛型
这里注意Order是泛型类,subOrder不是泛型类,就是一个普通的类

class subOrder extends Order<Integer>{


}
public class SubOrder {

    public static void main(String[] args) {
        subOrder sub=new subOrder();
        sub.setOrderT(1233);//调用父类的方法,因为指明了Integer,所以此时要求传入的是Integer类型
    }
}

还有一种情况,继承Order但不去指明,此时SubOrder1是泛型类,实例化的时候可以指明类型

public class test01 {

    public static void main(String[] args) {
        SubOrder1<String> sub2=new SubOrder1<>();
        sub2.setOrderT("order2");//此时就要传入String类型
    }
}
class SubOrder1<T> extends Order<T>{


}

注意点:

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如: <E1,E2,E3>,有几个就放几个

  2. 泛型类的空参构造器如下:public GenericClass(){}。
    而下面是错误的:public GenericClass< E>(){},实例化的时候需要补上,此时new之后的尖括号里面可以为空,new SubOrder1<>();写成这样也可以:new SubOrder1< String>();

  3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。

  4. 泛型不同的引用不能相互赋值。 尽管在编译时ArrayList< String>和ArrayList< Integer>是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中

  5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。这里只是认为是Object但不等于是Object,因为在继承方面还是有区别。经验:泛型要使用就一直都用。要不用,就一直都不要用。

  6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。

  7. jdk1.7,泛型的简化操作:ArrayList< String> list = new ArrayList<>();

  8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。

  9. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型

public class Order<T>{
    String orderName;
    int orderId;

    T orderT;
    
    public static void show(){
        System.out.println(orderT);//会报错
    }
}

这么写也报错

    public static void show(T orderT){
        System.out.println(orderT);
    }

因为类的泛型是造对象的时候指定的,静态结构的加载早于对象的创建,所以是错误的
10. 异常类不能是泛型的,异常类不能声明为泛型类
不能这么写,编译不通过

    try{
        
    }catch(T t){
        
    }
public class MyException extends Exception{
//不报错
}
public class MyException<T> extends Exception{
//报错
}
  1. 不能使用new E[]。否则编译不通过,但是可以:E[] elements = (E[])new Object[capacity];
    public Order(){
        T[] arr=new T[10];
    }//编译不通过

可以这么写

    public Order(){
        T[] arr=(T[])new Object[10];
    }

new的其实还是Object类型的数组,但具体放数据的时候必须放T和其子类的对象,不要放Object对象,否则出类型转换异常,这样才能保证实际执行的时候不会出问题
12. 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。
13. 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
子类不保留父类的泛型:按需实现
没有类型 擦除
具体类型
子类保留父类的泛型:泛型子类
全部保留
部分保留
结论:子类除了指定或保留父类的泛型,还可以增加自己的泛型

class Father<T1, T2> {

        }
        // 子类不保留父类的泛型
        // 1)没有类型 擦除
         class Son1 extends Father {// 等价于class Son extends Father<Object,Object>{ }

         }
         // 2)具体类型
         class Son2 extends Father<Integer, String> {

         }
         // 子类保留父类的泛型
        // 1)全部保留
         class Son3<T1, T2> extends Father<T1, T2> {

         }
         // 2)部分保留,Integer是确定的,另一个是不确定的
        class Son4<T2> extends Father<Integer, T2> {

        }
        class Father<T1, T2> {

        }
        // 子类不保留父类的泛型
        // 1)没有类型 擦除
         class Son<A, B> extends Father{//等价于class Son extends Father<Object,Object>{ }
				//这里是子类自己提供了两个泛型参数A,B,是额外的
         }
         // 2)具体类型
         class Son2<A, B> extends Father<Integer, String> {
				//如果父类中的方法用到了泛型,就是Integer和String,这里是自己额外又定义了两个泛型参数,在自己的东西中还可以用自己的A和B
         }
         // 子类保留父类的泛型
        // 1)全部保留
         class Son3<T1, T2, A, B> extends Father<T1, T2> {
				//在保留T1,T2的基础之上,又额外定义了两个
         }
         // 2)部分保留
        class Son4<T2, A, B> extends Father<Integer, T2> {
            //保留T2的同时自己又额外定义了两个
        }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于C#编程语言的问题,下面是答案: 我们可以创建一个名为Calculator的自定义泛型类,并在其中定义一个Add泛型方法。这个方法可以接受任意类型的参,并计算两个的和。以下是代码实现: ``` public class Calculator<T> { public T Add(T num1, T num2) { dynamic dynamicNum1 = num1; dynamic dynamicNum2 = num2; return dynamicNum1 + dynamicNum2; } } ``` 在上面的代码中,我们使用了C# 4.0中引入的dynamic类型。这个类型可以在运行时决定变量的类型,从而允许我们对任意类型的参进行加法操作。在Add方法中,我们首先将num1和num2转换为dynamic类型,并将它们相加。最后,我们将结果返回。 现在,我们可以使用这个自定义泛型类Calculator来计算任意类型的两个的和。以下是使用示例: ``` Calculator<int> intCalculator = new Calculator<int>(); int sum1 = intCalculator.Add(5, 10); // sum1 = 15 Calculator<double> doubleCalculator = new Calculator<double>(); double sum2 = doubleCalculator.Add(3.14, 2.71); // sum2 = 5.85 Calculator<string> stringCalculator = new Calculator<string>(); string sum3 = stringCalculator.Add("Hello", " World"); // sum3 = "Hello World" ``` 在上面的代码中,我们分别使用了int、double和string类型来创建三个不同的Calculator对象,并调用了它们的Add方法来计算两个的和。可以看到,这个自定义泛型类可以非常方便地处理任意类型的参,从而使我们的代码更加灵活和可重用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值