Java的编程之旅48——泛型

Java中的泛型是一种参数化类型的概念,它允许我们使用一个类型参数来代替具体的类型,使得代码可以在编译时期进行类型检查。泛型提供了更加灵活和类型安全的编程方式,可以提高代码的可读性和重用性。

使用泛型的主要好处是可以编写通用的代码,使得该代码可以适用于多种类型的数据。例如,我们可以编写一个通用的集合类,可以存储不同类型的数据。通过使用泛型,我们可以在编译时期就能够发现并防止类型错误的发生。

1.泛型类

泛型类是一种使用了类型参数的类,它可以在实例化的时候指定具体的类型参数,从而使得该类可以适用于多种类型的数据。泛型类通过在类名后面使用尖括号<>来定义类型参数,<>中的内容可以为

E :Element元素

K :Key 键

T :Type属性,类型

V :值,具体的值

public class Generic<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

这段代码定义了一个泛型类Generic,该类有一个类型参数T。

这个泛型类有一个私有成员变量t,类型为T。通过公有的getT()方法可以获取t的值,通过公有的setT()方法可以设置t的值。

public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

定义了一个Student类,它有两个私有成员变量name和age,以及一个构造方法和一个重写的toString()方法 

public class GTest {
    public static void main(String[] args) {
        Generic<String> strG = new Generic<>();
        strG.setT("Hello");
        String str = strG.getT();
        System.out.println(str);

        Generic<Integer> intG = new Generic<>();
        intG.setT(123);
        Integer i = intG.getT();
        System.out.println(i+1);

        Generic<Student> stuG = new Generic<>();
        stuG.setT(new Student("d",2));
        Student stu = stuG.getT();
        System.out.println(stu);

    }
}

在测试中,首先实例化了一个Generic对象strG,并指定其泛型类型参数为String。然后使用setT()方法设置t的值为"Hello",并使用getT()方法获取t的值并赋给str变量。最后输出str的值为"Hello"。

接着实例化了一个Generic对象intG,并指定其泛型类型参数为Integer。通过setT()方法将t的值设置为123,并使用getT()方法获取t的值并赋给i变量。最后输出i+1的值为124。

最后实例化了一个Generic对象stuG,并指定其泛型类型参数为Student。使用setT()方法将t的值设置为一个Student对象,该对象通过Student构造方法传入"name"和2作为参数值。使用getT()方法获取t的值并赋给stu变量。最后输出stu的值为"Student{name='d', age=2}"。

这说明了泛型类可以传入任何类型的参数

2.泛型方法

泛型方法是一种在方法中使用泛型的方式。在方法声明时,在返回类型前面使用尖括号(<>)来定义一个或多个类型参数。这些类型参数可以在方法的参数列表、方法的返回类型以及方法体内使用。

使用泛型方法可以在方法内部灵活地处理不同类型的数据,提高代码的灵活性和重用性。泛型方法可以独立于其所在的类进行类型参数的定义,并且可以在不同类中进行调用。

以下是一个使用泛型方法的示例:

public class GenericMethod {
    
    public <T> void printArray(T[] array) {
        for (T item : array) {
            System.out.println(item);
        }
    }
    
    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = {"Hello", "World"};
        
        GenericMethod gm = new GenericMethod();
        gm.printArray(intArray);
        gm.printArray(strArray);
    }
}

在上述示例中,printArray 方法使用了泛型方法的语法 &lt;T>,表示在方法中使用了一个类型参数 T。这个类型参数可以在方法的参数 T[] array、方法的返回类型以及方法体内使用。这样,printArray 方法就可以接受不同类型的数组作为参数,并打印出数组中的每个元素。通过泛型方法,我们可以在一个方法中处理多种类型的参数,提高代码的灵活性。

3.泛型接口

泛型接口是一个定义了一个或多个类型参数的接口。使用泛型接口可以在接口内部定义一个或多个类型参数,然后在实现该接口时,指定具体的类型参数。

泛型接口的定义与普通接口的定义类似,只是在接口的名称后面使用尖括号(<>)来定义一个或多个类型参数。这些类型参数可以在接口的方法、常量以及内部嵌套的类中使用。

以下是一个使用泛型接口的示例:

public interface Generic<T> {
    void show(T t);
}

上述代码定义了一个泛型接口 Generic,该接口有一个抽象方法 show,该方法接受一个类型为 T 的参数。 

public class GenericImpl<T> implements Generic<T>{
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

 然后,通过实现泛型接口 Generic 的类 GenericImpl,实现了 show 方法,具体实现是打印传入的参数。

public class GenTest {
    public static void main(String[] args) {
        GenericImpl<String> strG = new GenericImpl<>();
        strG.show("haha");
        GenericImpl<Integer> intG = new GenericImpl<>();
        intG.show(123);
        GenericImpl<Student> stuG = new GenericImpl<>();
        stuG.show(new Student("k",5));
    }


}

在 GenTest 类的 main 方法中,创建了三个 GenericImpl 对象,并分别传入不同的类型参数。然后调用 show 方法,传入不同的参数。结果会分别打印出 "haha"、123 和 Student 对象的字符串表示。

这样,在 GenericImpl 类中,通过实现泛型接口 Generic,我们可以将 show 方法的类型参数 T 指定为不同的类型,从而实现对不同类型的对象进行处理的灵活性。

4.泛型通配符

泛型通配符是Java和一些其他支持泛型的语言中的一种特殊类型占位符。它用于表示不确定类型的参数或返回值,允许你在编写方法或类的时候对未知类型进行操作,而无需指定具体的类型。主要有两种泛型通配符:

1. `?` 或者未限定的通配符:表示任意类型的参数,通常用于方法声明或变量声明,例如 List<?> 表示可以存储不同类型元素的列表。

2. `<T>` 或者类型参数通配符:当你知道你正在处理的是某个接口或类的实例,但是不想暴露这个类型时,可以使用 `T` 作为类型参数。比如 `List<T> list;` 中,`T` 可以代表任何实现了 `List` 接口的对象类型。

泛型通配符提高了代码的灵活性和复用性,但在访问通配符的实际元素时,可能会受到类型安全性的限制。

        ArrayList<?> list1 = new ArrayList<String>();
        ArrayList<?> list2 = new ArrayList<Integer>();
        ArrayList<?> list3 = new ArrayList<Float>();
        ArrayList<?> list4 = new ArrayList<Double>();
        ArrayList<?> list5 = new ArrayList<Student>();

        ArrayList<? extends Number> list6 = new ArrayList<Number>();
        ArrayList<? extends Number> list7 = new ArrayList<Integer>();
        ArrayList<? extends Number> list8 = new ArrayList<Float>();

        //ArrayList<? extends Number> list9 = new ArrayList<Object>();错误

在这段代码中,`ArrayList<?>` 表示的是泛型通配符,表示列表可以存储任何类型的对象。然而,在创建`list1`到`list5`时,分别传入了`String`、`Integer`、`Float`、`Double`和`Student`类型,这实际上是不安全的,因为它们并不是泛型中指定的类型。

`ArrayList<? extends Number>` 则是一个更精确的声明,它表示列表可以存储任意类型,这个类型必须是`Number`类或其子类。`list6`、`list7`和`list8`分别用于存储`Number`的子类,如整数`Integer`、浮点数`Float`,所以这些都是合法的。

然而,`ArrayList<? extends Number> list9 = new ArrayList<Object>();` 这行是错误的。因为`Object`不是`Number`类或其子类,所以尝试将`ArrayList<Object>`赋值给一个期望存储`Number`或其子类的变量会违反类型安全性。这种赋值会抛出编译错误,提示你不能将`Object`直接放入需要`Number`类型的地方。正确做法应该是明确指定子类类型,而不是`Object`。例如:

ArrayList<? extends Number> list9 = new ArrayList<Float>();

5.可变长参数

在 Java 中,可变长参数(Varargs)是一种方便的特性,允许方法接受数量不定的同类型参数。

使用格式是在参数类型后面加上三个点 `...` 。例如:`public void methodName(String... args)` ,这里的 `args` 就是一个可变长参数。

优点包括:

1.  提高了方法的灵活性,不必为不同数量的参数定义多个重载方法。
2.  使代码更简洁,减少了方法的数量。

在方法内部,可变长参数被视为一个数组来处理。

public class VariableLengthParameter {
    public static void main(String[] args) {

        System.out.println(mySum(1,2));

        System.out.println(mySum(1,2,3));

        System.out.println(mySum(1,2,3,4));
      
    }

    public static  int mySum(int ...a) {

        int sum = 0;
        for (int i : a) {
            sum += i;
        }
        return sum;
    }
    
}

这段代码定义了一个包含变长参数的方法mySum。在main方法中,分别传入不同个数的参数调用mySum方法,并将结果打印出来。

mySum方法中,使用了可变参数int ...a来接收参数。这意味着mySum方法可以接受任意个数的整型参数。在方法体中,使用for-each循环遍历参数a,并将每个参数累加到sum变量中。

最后,mySum方法返回累加结果sum。

在main方法中,依次调用了mySum方法,并将结果打印出来。输出结果为:

3 6 10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

惊爆点大男主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值