Java-泛型-01

1,泛型的定义:

泛型(宽泛的数据类型)是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。


2,泛型的优点:

Java引入泛型是一个较大的功能增强,①类型安全:主要目标是提高 Java 程序的类型安全,通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设,将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。②消除强制类型转换:泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。 经常见到的异常(运行时产生ClassCastException)


3,泛型的缺点:声明泛型变量相应的罗嗦,(很多都是一劳永逸,无伤大雅)


4,泛型类

要求:

可以接受不同数据类型,除了借助方法重载,还可以借助自动装箱和向上转型。我们知道,基本数据类型可以自动装箱,被转换成对应的包装类;Object 是所有类的祖先类,任何一个类的实例都可以向上转型为 Object 类型,例如:

  • int --> Integer --> Object
  • double -->Double --> Object
  • String --> Object
但是在获取坐标是,则需要向下转型,而向下转型就存在相当的风险,而且这些风险在编译时期并不会暴露出来,只有在运行是才会报错,抛出 java.lang.ClassCastException 异常。



定义一个泛型类:

public class Model<T1,T2> {
    private T1 X;
    private T2 Y;
    
    public T1 getX() {
        return X;
    }
    public T2 getY() {
        return Y;
    }
    public void setX(T1 x) {
        X = x;
    }
    public void setY(T2 y) {
        Y = y;
    }
}


调用泛型:

public class Demo {
    public static void main(String[] args) {
        Model<String,Integer> model = newModel<String,Integer>();

       model.setX("字符串");

       model.setY(1);

        String x =model.getX();

       int y =model.getY();

    }

}


注意:

#泛型是 Java 1.5 的新增特性,它以C++模板为参照,本质是参数化类型(Parameterized Type)的应用。

#类型参数只能用来表示引用类型,不能用来表示基本类型,如  int、double、char 等。但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。


5,泛型方法


public class Demo<T1,T2> {
    T1 X;
    T2 Y;
    public T1 getX() {
        return X;
    }
    public T2 getY() {
        return Y;
    }
    public void setX(T1 x) {
        X = x;
    }
    public void setY(T2 y) {
        Y = y;
    }
   

    //定义一个泛型方法,注意:V1,V2与T1,T2没有任何必然的关系,都是相对独立的,但是<V1,V2>与(V1 x,V2 y)必须一一对应

    public static <V1,V2> void printDemo(V1 x,V2 y){
        System.out.println("X="+x+"    Y=" + y);
    }
}


调用:

public static void main(String[] args) {
        Demo.printDemo("a", 1);
 }


结果:X=a    Y=1


6,泛型接口(引用案例)

  1. public class Demo {
  2. public static void main(String arsg[]) {
  3. Info<String> obj = new InfoImp<String>("www.weixueyuan.net");
  4. System.out.println("Length Of String: " + obj.getVar().length());
  5. }
  6. }
  7. //定义泛型接口
  8. interface Info<T> {
  9. public T getVar();
  10. }
  11. //实现接口
  12. class InfoImp<T> implements Info<T> {
  13. private T var;
  14. // 定义泛型构造方法
  15. public InfoImp(T var) {
  16. this.setVar(var);
  17. }
  18. public void setVar(T var) {
  19. this.var = var;
  20. }
  21. public T getVar() {
  22. return this.var;
  23. }
  24. }

附加:

通过 extends 关键字可以限制泛型的类型,

例如,<T extends Number> 表示 T 只接受 Number 及其子类,传入其他类型的数据会报错。

这里的限定使用关键字 extends,后面可以是类也可以是接口。

但这里的 extends 已经不是继承的含义了,应该理解为 T 是继承自 Number 类的类型,或者 T 是实现了 XX 接口的类型。

### Java练习题及解析 #### 1. 泛型类的基本使用 考虑以下泛型类的定义: ```java class Holder<T> { T value; public Holder(T value) { this.value = value; } public T getValue() { return value; } } ``` 该类定义了一个泛型类 `Holder`,其中 `T` 是一个类参数。可以使用该类来存储任何类的对象,并通过 `getValue()` 方法获取该对象。例如,以下代码演示了如何创建一个 `Holder` 实例来存储一个字符串: ```java Holder<String> stringHolder = new Holder<>("Hello"); System.out.println(stringHolder.getValue()); // 输出 "Hello" ``` 如果尝试将错误类的对象传递给 `Holder`,编译器会报错。例如,以下代码会导致编译错误: ```java Holder<Integer> intHolder = new Holder<>("Hello"); // 编译错误 ``` 这是因为 `Holder<Integer>` 要求传入的值必须是 `Integer` 类,而 `"Hello"` 是 `String` 类。 #### 2. 原始类的兼容性 Java 允许将泛型类的实例赋值给原始类的变量,但这种做法不推荐,因为它会失去类安全性。例如: ```java Holder rawHolder = new Holder<String>("Hello"); String value = rawHolder.getValue(); // 不推荐,但可以编译通过 ``` 尽管这段代码可以编译通过,但它失去了带来的类检查。如果尝试从 `rawHolder` 获取一个非 `String` 类的对象,可能会在运行时抛出 `ClassCastException`。 #### 3. 类推断的增强 在 Java 23 中,类推断得到了增强,允许在某些情况下省略显式的类参数。例如: ```java List<String> list = Collections.emptyList(); // Java 23 支持空目标类推断 ``` 在旧版本的 Java 中,必须显式指定类参数: ```java List<String> list = Collections.<String>emptyList(); ``` 这种改进使得代码更加简洁,并减少了冗余的类声明。 #### 4. 可变参数与的结合 Java 允许将可变参数与结合使用。例如,可以定义一个方法来接受可变数量的参数: ```java public static <T> void printValues(T... values) { for (T value : values) { System.out.println(value); } } ``` 调用该方法时,可以传入任意数量的参数: ```java printValues("Apple", "Banana", "Cherry"); // 输出三个字符串 printValues(1, 2, 3); // 输出三个整数 ``` 这种方法在处理不确定数量的输入时非常有用,并且保持了类安全性。 #### 5. 方法的使用 不仅可以用于类,还可以用于方法。例如,定义一个方法来交换两个元素的位置: ```java public static <T> void swap(T[] array, int i, int j) { T temp = array[i]; array[i] = array[j]; array[j] = temp; } ``` 调用该方法时,可以传入任意的数索引: ```java String[] names = {"Alice", "Bob"}; swap(names, 0, 1); System.out.println(Arrays.toString(names)); // 输出 "[Bob, Alice]" ``` 这种方法可以应用于任何类的数,并且保证了类安全性。 #### 6. 接口的实现 Java 允许定义接口,并由具体的类实现这些接口。例如,定义一个接口 `Container<T>`: ```java interface Container<T> { void add(T item); T get(int index); } ``` 然后,可以实现该接口的具体类: ```java class StringContainer implements Container<String> { private List<String> items = new ArrayList<>(); @Override public void add(String item) { items.add(item); } @Override public String get(int index) { return items.get(index); } } ``` 这样,`StringContainer` 类只能用于处理 `String` 类的对象,确保了类安全性。 #### 7. 的边界限制 Java 支持通过边界限制来约束类参数的范围。例如,定义一个方法,要求类参数必须是 `Number` 的子类: ```java public static <T extends Number> double sum(T[] numbers) { double total = 0; for (T number : numbers) { total += number.doubleValue(); } return total; } ``` 调用该方法时,只能传入 `Number` 的子类数: ```java Integer[] integers = {1, 2, 3}; Double[] doubles = {1.5, 2.5, 3.5}; System.out.println(sum(integers)); // 输出 6.0 System.out.println(sum(doubles)); // 输出 7.5 ``` 这种方法确保了类的安全性操作的正确性。 #### 8. 多类参数的使用 Java 支持多个类参数的定义。例如,定义一个泛型类 `Pair<K, V>`,用于存储键值对: ```java class Pair<K, V> { K key; V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } ``` 调用该类时,可以传入任意的键值: ```java Pair<String, Integer> pair = new Pair<>("Age", 25); System.out.println(pair.getKey()); // 输出 "Age" System.out.println(pair.getValue()); // 输出 25 ``` 这种方法可以灵活地处理不同类的数据合。 #### 9. 的通配符使用 Java 支持使用通配符 `?` 来表示未知类。例如,定义一个方法来打印任意的列表: ```java public static void printList(List<?> list) { for (Object obj : list) { System.out.println(obj); } } ``` 调用该方法时,可以传入任意的 `List`: ```java List<String> stringList = Arrays.asList("A", "B", "C"); List<Integer> integerList = Arrays.asList(1, 2, 3); printList(stringList); // 输出三个字符串 printList(integerList); // 输出三个整数 ``` 这种方法在处理未知类的数据时非常有用,并且保持了类安全性。 #### 10. 的递归类限制 Java 支持递归类限制,允许类参数继承自身。例如,定义一个接口 `SelfBound<T>`: ```java interface SelfBound<T extends SelfBound<T>> { T self(); } ``` 这种设计模式常用于链式调用构建器模式中,确保返回的类与当前类一致。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值