`

自定义泛型方法及其应用和类型参数的类型推断

阅读更多

自定义泛型方法用其应用

1. 定义泛型方法

a. java的泛型方法没有C++函数功能强大,java中的如下代码无法通过编译:

<T> T add(T x, T y) {

return (T) (x + y);

}

2. 交换数组中的两个元素的位置 //下面的方法很通用,这样做还是有意义的

private static <T> void swap(T[] a,int i, int j) {

T tmp = a[i];

a[i] = a[j];

a[j] = tmp;

}

3. 用于放置泛型的类型参数的尖括号应出现在方法的其它所有修饰符之后和在方法的返回类型之前,也就是紧邻返回之前。按照惯例,类型参数通常用单个大写字母表示。

例:private static <T> void swap(T[] a,int i, int j){};

4. 除了在应用泛型时可以使用extends 限定符,在定义泛型时也可以使用extends限定符,例如,Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,
<V extends Serializable & cloneable> void method(){};

5. 普通方法、构造方法和静态方法中都可以泛型。

6 也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch子句中。 //貌似有点问题,报错

private static <T extends Exception> sayHello() throws T {

try {

 

}catch (Exception e) {

thorw (T)e;

}

}

7. 在泛型中可以同时有多个类型参数,在定义它们的类括号中用逗号分开,例如:

public static <K,V> V getValue(K key) {return map.get(key);}

编写一个泛型方法,自动将Object类型的对象转换成其它类型

private static <T> T autoConvert(Object obj) {

return (T) obj;

}

定义一个方法,可以将任意类型的数组中的所有元素填充为想方相应类型的某个对象

private static <T> void fillArray(T[] a, T obj) {

for (int i = 0; i < a.length; i++) {

a[i] = obj;

}

}

采用自定泛型方法的方式打印出任意参数化类型的集合中的所有内容。

在这种情况下,前面的通配符方案要比泛型方法更有效,当一个类型变量用来表达两个参数之间或者参数和值之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体中也被使用而不是仅在签名的时候使用,才需要使用泛型方法。

public static void printCollection(Collection<?> collection) {

System.out.println(collection.size());

for(Object obj: collection) {

System.out.println(obj);

}

}

 

public static <T> void printCollection2(Collection<T> collection, T obj2) {

System.out.println(collection.size());

for(Object obj: collection) {

System.out.println(obj);

}

collection.add(obj2);

}

定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的集合中

定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的别一个数组中

类型参数的类型推断

1. 编译器判断泛型的实际类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种子选手非常复杂的过程。

2. 根据调用泛型方法时实际传递的参数类型或值的类型来推断,具体规则如下:
a.
当草棚个类变量只在整个参数列表中的所有和返回值中的一处被应用了,那么根据调用 方法时该处的实际应用类型来确定,这很容易凭着感觉推断来来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。例如:

swap(new String[3],3,4)->static <E> void Swap(E[] a, int i, int j);

b. 当某个类型变更在整个参数列表中所胡参数和返回值的多处被应用了,如果调用方法时这多处的实际应用类型都对就同各种类型来确定,这很容易凭感觉推断出来,例如:
add(3,5)->static <T> add(T a, T b);

c. 当某个类型变量在整个参数列表中的所有值和返回值中的多处被应用了,如果说调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题:
fill(new Integer[3], 3,5f) -> static <T> void fill(T[] a, T v);

d. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,并且使用返回值,这时候优先考虑返回值的类型,例如,下面的语句实际对应的类型就是Integer了,编译器将报告错误,将变量X的类型改为float,对比Eclipse报告错误提示,接着再将变量X类型改为Number,则没有了错误:

int x = (3.35f) -> sttic <T> add(T a, T b);

 

分享到:
评论

相关推荐

    C#5.0本质论第四版(因文件较大传的是百度网盘地址)

    11.4.1 泛型方法类型推断 328 11.4.2 约束的指定 328 11.5 协变性和逆变性 330 11.5.1 在C# 4.0中使用out类型参数修饰符允许协变性 331 11.5.2 在C# 4.0中使用in类型参数修饰符允许逆变性 332 ...

    Swift语言开发常见问题总结.docx

    利用Swift的类型推断能力减少显式类型声明。 选项集(OptSet)和可选(Optional) 使用if let、guard let解包可选值。 利用.none、.some构造可选类型。 运算符重载 自定义运算符以符合业务逻辑需求。 扩展...

    ADO.NET本质论.pdf

    深入探索了类、接口、属性和方法。讲解了数据结构,演示了如何用ado.net来解决具体的数据访问问题。重点讨论了ado.net如何有效地平衡"功能的泛化"和"执行效率",以及它如何解决对扩展性、并发性和可靠性的要求。针对...

    C++ Primer中文版(第5版)李普曼 等著 pdf 1/3

     16.2.1 类型转换与模板类型参数 601  16.2.2 函数模板显式实参 603  16.2.3 尾置返回类型与类型转换 604  16.2.4 函数指针和实参推断 607  16.2.5 模板实参推断和引用 608  16.2.6 理解std::move 610  16.2....

    C++Primer(第5版 )中文版(美)李普曼等著.part2.rar

     16.2.1 类型转换与模板类型参数 601  16.2.2 函数模板显式实参 603  16.2.3 尾置返回类型与类型转换 604  16.2.4 函数指针和实参推断 607  16.2.5 模板实参推断和引用 608  16.2.6 理解std::move 610  16.2....

    ASP.NET 控件的使用

    16.2.1 使用不同的参数类型 509 16.2.2 作为参数传递对象 511 16.3 使用ObjectDataSource控件分页、排序和过滤数据 515 16.3.1 用户界面分页 515 16.3.2 数据源分页 517 16.3.3 用户界面排序 522 16.3.4 数据源排序 ...

    ASP.NET.4揭秘

    20.1.3 理解类型推断723 20.1.4 理解匿名类型724 20.1.5 理解泛型724 20.1.6 理解lambda表达式726 20.1.7 理解扩展方法729 20.1.8 理解linq730 20.2 创建linq to sql实体732 20.2.1 手工创建实体732 20.2.2 使用linq...

Global site tag (gtag.js) - Google Analytics