Java基础 - 泛型机制详解与实例解析

泛型是Java编程语言中的一项强大的特性,它提供了参数化类型的能力,使得代码更加灵活、安全,并提高了代码的重用性。

泛型其实就是为了参数化类型(在不创建新的类型的前提下,通过泛型指定的不同类型来控制形参具体限制的类型)。

1. 泛型的引入背景

在引入泛型之前,Java中的集合(如ArrayList、HashMap等)都是非泛型的,它们可以存储任意类型的对象,但在使用时需要进行强制类型转换,这带来了类型安全性和代码可读性的问题。泛型的引入就是为了解决这些问题,使得集合类能够在编译期检查元素的类型,并提供更加安全和通用的编程方式。

2. 泛型的基本概念

2.1 泛型类

泛型类是具有一个或多个类型参数的类。在类名后面使用尖括号<>定义类型参数,并在类的声明、方法的返回类型以及方法的参数中使用这些类型参数。

public class Box<T> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

上面的例子中,Box类是一个泛型类,使用<T>定义了一个类型参数。这个类可以用来存储任意类型的值。

2.2 泛型方法

泛型方法是在调用时可以接受不同类型的参数的方法。泛型方法的类型参数在方法返回类型之前声明。

public <T> T identity(T element) {
    return element;
}

上述例子中,identity方法是一个泛型方法,接受一个类型为T的参数,并返回一个同样类型的值。

3. 泛型的实际应用

3.1 集合框架中的泛型

泛型广泛应用于Java的集合框架,使得我们能够在编译期间检测到类型错误。

List<String> stringList = new ArrayList<>();
stringList.add("Hello");
stringList.add("World");

// 编译时会报错,不允许添加非String类型的元素
// stringList.add(42);

for (String s : stringList) {
    System.out.println(s);
}

3.2 泛型通配符(重)

泛型通配符用来表示一种不确定的泛型类型,常用的通配符有?T extends SomeClassT super SomeClass

public static double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number num : list) {
        sum += num.doubleValue();
    }
    return sum;
}
// 接收Number的子类,如<? extends Integer> 则 需要接收Number
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);

System.out.println(sumOfList(integers)); // 输出 6.0
System.out.println(sumOfList(doubles));  // 输出 7.5

泛型通配符上下限

<?> 无限制通配符 <? extends E> extends 关键字声明了类型的上限,表示此类型的子类或指定类 <? super E> super 关键字声明了类型的下界,表示此类型的父类或指定类

3.3 类型擦除

Java中的泛型是通过类型擦除来实现的,即在编译期间会将泛型信息擦除,转为原始类型。这导致在运行时无法获取泛型的实际类型参数。

public class GenericClass<T> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

GenericClass<Integer> genericInt = new GenericClass<>();
GenericClass<String> genericString = new GenericClass<>();

System.out.println(genericInt.getClass() == genericString.getClass()); // 输出 true

4. 泛型的局限性和注意事项

4.1 无法创建泛型数组

由于类型擦除,Java不允许直接创建泛型数组。通常使用集合代替数组来存储泛型对象。

// 编译时会报错
// T[] array = new T[10];

List<T> list = new ArrayList<>();

4.2 泛型类型参数不能是基本数据类型

泛型的类型参数只能是类类型,不能是基本数据类型。如果需要使用基本数据类型,可以使用对应的包装类。

// 编译时会报错
// Box<int> intBox = new Box<int>();

Box<Integer> integerBox = new Box<>();

5. 总结

Java泛型机制通过提供参数化类型的能力,使得代码更加通用、安全。在实际应用中,泛型被广泛用于集合框架、泛型方法等方面,提供了更灵活、类型安全的编程方式。然而,泛型也存在一些局限性和注意事项,如类型擦除、无法创建泛型数组等。合理地使用泛型,将有助于提高代码的可读性、可维护性和重用性。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java泛型Java 5引入的新特性,可以提高代码的可读性和安全性,降低代码的耦合度。泛型是将类型参数化,实现代码的通用性。 一、泛型的基本语法 在声明类、接口、方法时可以使用泛型泛型的声明方式为在类名、接口名、方法名后面加上尖括号<>,括号中可以声明一个或多个类型参数,多个类型参数之间用逗号隔开。例如: ```java public class GenericClass<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } } public interface GenericInterface<T> { T getData(); void setData(T data); } public <T> void genericMethod(T data) { System.out.println(data); } ``` 其中,`GenericClass`是一个泛型类,`GenericInterface`是一个泛型接口,`genericMethod`是一个泛型方法。在这些声明中,`<T>`就是类型参数,可以用任何字母代替。 二、泛型使用 1. 泛型类的使用使用泛型类时,需要在类名后面加上尖括号<>,并在括号中指定具体的类型参数。例如: ```java GenericClass<String> gc = new GenericClass<>(); gc.setData("Hello World"); String data = gc.getData(); ``` 在这个例子中,`GenericClass`被声明为一个泛型类,`<String>`指定了具体的类型参数,即`data`字段的类型为`String`,`gc`对象被创建时没有指定类型参数,因为编译器可以根据上下文自动推断出类型参数为`String`。 2. 泛型接口的使用使用泛型接口时,也需要在接口名后面加上尖括号<>,并在括号中指定具体的类型参数。例如: ```java GenericInterface<String> gi = new GenericInterface<String>() { private String data; @Override public String getData() { return data; } @Override public void setData(String data) { this.data = data; } }; gi.setData("Hello World"); String data = gi.getData(); ``` 在这个例子中,`GenericInterface`被声明为一个泛型接口,`<String>`指定了具体的类型参数,匿名内部类实现了该接口,并使用`String`作为类型参数。 3. 泛型方法的使用使用泛型方法时,需要在方法名前面加上尖括号<>,并在括号中指定具体的类型参数。例如: ```java genericMethod("Hello World"); ``` 在这个例子中,`genericMethod`被声明为一个泛型方法,`<T>`指定了类型参数,`T data`表示一个类型为`T`的参数,调用时可以传入任何类型的参数。 三、泛型的通配符 有时候,我们不知道泛型的具体类型,可以使用通配符`?`。通配符可以作为类型参数出现在方法的参数类型或返回类型中,但不能用于声明泛型类或泛型接口。例如: ```java public void printList(List<?> list) { for (Object obj : list) { System.out.print(obj + " "); } } ``` 在这个例子中,`printList`方法的参数类型为`List<?>`,表示可以接受任何类型的`List`,无论是`List<String>`还是`List<Integer>`都可以。在方法内部,使用`Object`类型来遍历`List`中的元素。 四、泛型的继承 泛型类和泛型接口可以继承或实现其他泛型类或泛型接口,可以使用子类或实现类的类型参数来替换父类或接口的类型参数。例如: ```java public class SubGenericClass<T> extends GenericClass<T> {} public class SubGenericInterface<T> implements GenericInterface<T> { private T data; @Override public T getData() { return data; } @Override public void setData(T data) { this.data = data; } } ``` 在这个例子中,`SubGenericClass`继承了`GenericClass`,并使用了相同的类型参数`T`,`SubGenericInterface`实现了`GenericInterface`,也使用了相同的类型参数`T`。 五、泛型的限定 有时候,我们需要对泛型的类型参数进行限定,使其只能是某个类或接口的子类或实现类。可以使用`extends`关键字来限定类型参数的上限,或使用`super`关键字来限定类型参数的下限。例如: ```java public class GenericClass<T extends Number> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } } public interface GenericInterface<T extends Comparable<T>> { T getData(); void setData(T data); } ``` 在这个例子中,`GenericClass`的类型参数`T`被限定为`Number`的子类,`GenericInterface`的类型参数`T`被限定为实现了`Comparable`接口的类。 六、泛型的擦除 在Java中,泛型信息只存在于代码编译阶段,在编译后的字节码中会被擦除。在运行时,无法获取泛型的具体类型。例如: ```java public void genericMethod(List<String> list) { System.out.println(list.getClass()); } ``` 在这个例子中,`list`的类型为`List<String>`,但是在运行时,`getClass`返回的类型为`java.util.ArrayList`,因为泛型信息已经被擦除了。 七、泛型的类型推断 在Java 7中,引入了钻石操作符<>,可以使用它来省略类型参数的声明。例如: ```java List<String> list = new ArrayList<>(); ``` 在这个例子中,`ArrayList`的类型参数可以被编译器自动推断为`String`。 八、总结 Java泛型是一个强大的特性,可以提高代码的可读性和安全性,降低代码的耦合度。在使用泛型时,需要注意它的基本语法、使用方法、通配符、继承、限定、擦除和类型推断等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

--土拨鼠--

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

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

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

打赏作者

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

抵扣说明:

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

余额充值