首页 > 其他分享 >泛型

泛型

时间:2022-11-22 10:33:29浏览次数:39  
标签:hutao 类型 参数 泛型 new public

在定义时不指定具体的类型,在使用时才指定具体的类型。

一.泛型类

1-1基本使用

在类上使用类型参数时,用尖括号括住,放在类名后面,如果有多个类型参数,则使用逗号隔开。然后在使用这个类时,再用实际的类型替换此类型参数。

package com.hutao.page.chapter15.page354;

class Automobile {
}

public class Holder3<T> {
    private T a;

    public Holder3(T a) {
        this.a = a;
    }

    public void setA(T a) {
        this.a = a;
    }

    public T getA() {
        return a;
    }

    public static void main(String[] args) {
        Holder3<Automobile> automobileHolder = new Holder3<Automobile>(new Automobile());
        Automobile a = automobileHolder.getA();
        //automobileHolder.setA("Not a automobile");//Error
        //automobileHolder.setA(1);//Error
    }
}

1-2继承泛型类

在继承泛型类时需注意类型参数的指定。

举例说明:

1.TwoTuple类具有两个类型参数A,B:

package com.hutao.page.chapter15.page355;

public class TwoTuple<A, B> {
    public final A first;
    public final B second;

    public TwoTuple(A first, B second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ")";
    }
}

2.继承泛型类TwoTuple

①在继承时不指定泛型父类的类型参数

package com.hutao.page.chapter15.page355;

public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
    public C third;

    public ThreeTuple(A first, B second, C third) {
        super(first, second);
        this.third = third;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ", " + third + ")";
    }
}

②在继承时指定泛型父类的全部类型参数

package com.hutao.page.chapter15.page355;

public class ThreeTuple1<C> extends TwoTuple<Integer, String> {
    public C third;

    public ThreeTuple1(Integer first, String second, C third) {
        super(first, second);
        this.third = third;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ", " + third + ")";
    }
}

③在继承时指定泛型父类的部分类型参数

package com.hutao.page.chapter15.page355;

public class ThreeTuple2<B, C> extends TwoTuple<Integer, B>{
    public C third;

    public ThreeTuple2(Integer first, B second, C third) {
        super(first, second);
        this.third = third;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ", " + third + ")";
    }
}

测试:

package com.hutao.page.chapter15.page355;

class Bike {
}

class Moto {
}

class Car {
}

public class Test {
    public static void main(String[] args) {
        //在继承时不指定泛型父类的类型参数的ThreeTuple<A,B,C>
        ThreeTuple<Bike, Moto, Car> threeTuple = new ThreeTuple<Bike, Moto, Car>(new Bike(), new Moto(), new Car());
        System.out.println(threeTuple);

        //在继承时指定泛型父类的全部类型参数的ThreeTuple1<C>
        ThreeTuple1<Car> threeTuple1 = new ThreeTuple1<Car>(1,"en",new Car());
        System.out.println(threeTuple1);

        //在继承时指定泛型父类的部分类型参数的ThreeTuple2<B, C>
        ThreeTuple2<Moto, Car> threeTuple2 = new ThreeTuple2<Moto, Car>(2,new Moto(), new Car());
        System.out.println(threeTuple2);
    }
}

运行结果为:

(com.hutao.page.chapter15.page355.Bike@4554617c, com.hutao.page.chapter15.page355.Moto@74a14482, com.hutao.page.chapter15.page355.Car@1540e19d)
(1, en, com.hutao.page.chapter15.page355.Car@677327b6)
(2, com.hutao.page.chapter15.page355.Moto@14ae5a5, com.hutao.page.chapter15.page355.Car@7f31245a)

Process finished with exit code 0

总结:

  1. 在继承泛型类时,可在extends关键字后指定泛型父类的全部或者部分类型参数;如:
  2. 如果没有全部指定,则需在子类的泛型参数列表(<>中)添加未指定的类型参数,以确保在使用时,父类的所有类型参数都有有效的值。

1-3其他

  1. 普通内部类可以访问其外围类的类型参数,但静态内部类不可以,因为静态内部类不能直接访问其外围类的非静态成员;
  2. 泛型接口和泛型类的使用一致。

 

二.泛型方法

  1. 方法能否为泛型方法与其所在类是否是泛型类没有关系;
  2. 对于一个static方法而言,无法访问泛型类的类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。

2-1基本使用

要定义泛型方法,只需将泛型参数列表置于方法返回值之前。

package com.hutao.page.chapter15.page361;

public class GenericMethods {
    public <T> void f(T x) {
        System.out.println(x.getClass().getName());
    }

    public static void main(String[] args) {
        GenericMethods genericMethods = new GenericMethods();
        genericMethods.f("");
        genericMethods.f(1);
        genericMethods.f(1.0);
        genericMethods.f(1.0f);
        genericMethods.f('c');
        genericMethods.f(genericMethods);
    }
}

运行结果为:

java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.Character
com.hutao.page.chapter15.page361.GenericMethods

Process finished with exit code 0

2-2类型参数推断

在使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明类型参数的值,因为编译器会自动找出具体的类型。这称为类型参数推断

如,在2-1中调用public <T> void f(T x)方法时,并未显式指定类型参数。

泛型方法可通过①传入的实参②接受方法返回值的引用来进行类型参数推断。

1.根据传入的实参进行类型参数推断

实参和形参是对应的,如果形参是泛型,那么可通过实参的类型推断出类型参数。

package com.hutao.page.chapter15.page361;

public class GenericMethods {
    public <T> void f(T x) {
        System.out.println(x.getClass().getName());
    }

    public static void main(String[] args) {
        GenericMethods genericMethods = new GenericMethods();
        genericMethods.f(""); //形参为(T x),传入的实参类型为String,所以推断出类型参数T为String
        genericMethods.f(1);  //形参为(T x),传入的实参类型为Integer,所以推断出类型参数T为Integer
        genericMethods.f(1.0);
        genericMethods.f(1.0f);
        genericMethods.f('c');
        genericMethods.f(genericMethods);
    }
}

2.根据接受方法返回值的引用进行类型参数推断

方法的返回值和接受方法返回值的引用是对应的,如果方法的返回值是有泛型的,那么可以通过接受方法返回值的引用的具体类型推断出类型参数。

package com.hutao.page.chapter15.page362;

import java.util.*;

public class New {
    public static <K, V> Map<K, V> map() {
        return new HashMap<K, V>();
    }

    public static <T> List<T> list() {
        return new ArrayList<T>();
    }

    public static <T> LinkedList<T> linkedList() {
        return new LinkedList<T>();
    }

    public static <T> Set<T> set() {
        return new HashSet<T>();
    }

    public static <T> Queue<T> queue() {
        return new LinkedList<T>();
    }

    public static void main(String[] args) {
        Map<String, List<String>> map = New.map();
        List<String> list = New.list();
        LinkedList<String> linkedList = New.linkedList();
        Set<String> set = New.set();
        Queue<String> queue = New.queue();
    }
}

拿List<String> list = New.list();来说,list方法定义的返回值是List<T>,而接受list方法返回值的引用为List<String>,所以推断出类型参数T为String。

但是,这种根据接受方法返回值的引用进行类型参数推断的方式只适用于普通的赋值语句(即需用赋值运算符=连接的语句)。如果将一个泛型方法的调用结果(例如New.map())作为参数传递给另一个方法,这时编译器不会进行类型参数推断。

2-3显示指定泛型方法的类型参数

  1. 在点操作符与方法名之间插入尖括号,然后把类型置于尖括号内;
  2. 如果是在定义该方法的类的内部,必须在点操作符前使用this关键字(不然点操作符前没东西);
  3. 如果使用的是静态方法,必须在点操作符之前加上类名。

2-2 2中的问题(非赋值语句不能根据接受方法返回值的引用进行类型参数推断),就可使用这种显示指定类型参数的方法来解决。

import com.hutao.page.chapter15.page362.New;

import java.util.List;

public class LimitsOfInference {
    static void f(List<String> list){
    }

    public static void main(String[] args) {
        f(New.<String>list());
    }
}

2-4根据类型参数创建对象

一个泛型方法,可推断出类型参数T的具体值,并根据推断出的类型参数创建该类型的对象。

不能使用new关键字直接创建类型参数对应类的对象(Type parameter 'T' cannot be instantiated directly.):

可为方法传入要创建对象的Class类型实参,通过2-2.1中的方式推断出类型参数,然后通过反射创建新的对象。

package com.hutao.test.chapter15.page364;

class Dog {
}

public class Test {
    public static <T> T createObject(Class<T> type) {
        try {
            return type.newInstance();
        } catch (Exception e) {
            return null;
        }
    }

    public static void main(String[] args) {
        Dog dog = createObject(Dog.class);
        System.out.println(dog);
    }
}

运行结果为:

com.hutao.test.chapter15.page364.Dog@4554617c

Process finished with exit code 0

 

三.擦除

在泛型代码内部,无法获取任何有关泛型参数类型的信息。即,如果是泛型类,则无法在类内部获取类型参数的具体值;如果是泛型方法,则无法在方法内部获取类型参数的具体值

 

标签:hutao,类型,参数,泛型,new,public
From: https://www.cnblogs.com/certainTao/p/15000790.html

相关文章

  • go1.18泛型初体检
    在Gov1.18中,Go语言新增三个功能,分别是“泛型”、“模糊测试”和“工作区”。本文我们介绍Go社区呼声最高的“泛型”的使用方式。02 引言读者朋友们应该了解......
  • Java 泛型 ? extends 与 ? super
    我们经常在集合的泛型中用到extends、super关键字。先看下List集合中获取和放入接口的定义:通过类定义可以看到,泛型的具体类型在创建集合实例时指定,用于限定该实例的......
  • 《ASP.NET Core技术内幕与项目实战》精简集-EFCore2.9:泛型仓储实现IRepository
    本节内容,部分为补充内容,部分涉及到5.2(P131-133)。主要NuGet包:如前章节所述 仓储模式,将数据访问层抽象出来,隐藏了底层对数据源的CRUD操作,这样在应用层或控制器中,我们直接......
  • C#ORM(反射+泛型)参考范例
    使用控制台:1.数据库字符串<?xmlversion="1.0"encoding="utf-8"?><configuration><startup><supportedRuntimeversion="v4.0"sku=".NETFramework,V......
  • Java中的泛型详解
    ......
  • Java泛型与数组
    Java泛型与数组1.*泛型与数组Java5的泛型有一个很重要的设计原则,如果一段代码在编译时没有提出[unchecked]未经检查的转换警告,则程序在运行时不会引发ClassCastExcepti......
  • Java泛型擦除与转换
    Java泛型擦除与转换1.*擦除与转换在严格的泛型代码里,带泛型声明的类总应该带着类型参数。但为了与老的Java代码保持一致,也允许在使用带泛型声明的类时不指定实际的类型......
  • Java——集合——泛型——泛型通配符
                                  泛型通配符当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通......
  • Java——集合——泛型——定义和使用含有泛型的方法
                                                         ......
  • Java——集合——泛型——定义和使用含有泛型的接口
    定义和使用含有泛型的接口定义格式:修饰符interface接口名<代表泛型的变量>{}1.定义一个含有泛型的类packagecom.itheima.demo03.Generic;/*定义含有泛......