CoreJava 泛型

java泛型的出现避免了强制类型转换,便于代码更好的被阅读

本文的写作参照了张孝祥的泛型介绍:http://www.itcast.cn/news/dbfd20f1/f4b1/412d/9b40/c1a81b8bf1da.shtml

更多疑问请参考:http://www.vaikan.com/java-generics-quick-tutorial/

1.可以接收类型参数的类型在接受类型参数后变为泛型,但是,虽然是不同的泛型但是还是相同的类型

package com.yuki.generic;

import java.util.Vector;

/**
 * 同一个类型的不同的泛型
 * Vector<Integer>和Vector<Boolean>是同一个类型的不同泛型
 *
 * @author yuki
 *
 */
public class Demo1 {

    public static void main(String[] args) {

        Vector<Integer> vi = new Vector<>();
        Vector<Boolean> vb = new Vector<>();

        vi.add(1);
        vb.add(true);

        boolean same = vi.getClass() == vb.getClass();

        System.out.println("same = " + same);

    }

}

执行结果如下:

same = true

2.可以通过反射跳过泛型的类型参数的限制

package com.yuki.generic;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射调用泛型方法
 *
 * ArrayList<E>中的E表示的是一个类型参数或类型变量
 * ArraList<Integer>称为已参数化的类型
 * ArraList<Integer>中的Integer称为类型参数的实例或实际类型参数
 * ArraList<Integer> 读作 ArraList type of Integer
 * ArrayList 称为原始类型
 *
 * @author yuki
 *
 */
public class Demo2 {

    public static void main(String[] args) throws Exception {

        // List<Integer> l = new ArrayList<Integer>();
        // 下面的写法也是可以的
        List<Integer> l = new ArrayList<>();

        // 规定存放整数对象的序列不能存放字符串
        // list.add("i am string"); // error!

        Method m = l.getClass().getMethod("add", Object.class);
        m.invoke(l, "abc");

        System.out.println("l.get(0) = " + l.get(0));

        // 不能创建参数化类型的数组,Cannot create a generic array
        // List<Object>[] l2 = new ArrayList<Object>[10]; // error!
    }

}

执行结果如下:

l.get(0) = abc

3.问号?可以作为泛型的通配符,发可以匹配任意类型, 但是形参上的参数引用失去了泛型的信息

package com.yuki.generic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Demo3 {

    public static void main(String[] args) {

        List<Integer> l = new ArrayList<>();
        l.add(1);
        l.add(2);

        printCollection(l);
    }

    // --- 没有使用泛型 ---
    // public static void printCollection(Collection collection){
    // --- 泛型类型必须为Collection<Object>,不能传递类似Collection<Integer>的参数 ---
    // public static void printCollection(Collection<Object> collection){
    // ? 是通配符,表示可以接受任意类型
    public static void printCollection(Collection<?> c){
        // 不能调用与类型有关的方法
        // c.add(1); // error!
        final int SIZE = c.size();
        int i = 0;
        for(Object o : c){
            System.out.println("c : " + i++ + " in " + SIZE + " -> " + o);
        }
    }

}

运行结果如下:

c : 0 in 2 -> 1
c : 1 in 2 -> 2

4.静态函数Class.forName返回的参数类型是Class<?>,应为传入的类名只是它的参数

package com.yuki.generic;

public class Demo4 {
public static void main(String[] args) throws Exception {

        // 它返回的是Class<?>
        // Class<Number> y = Class.forName("java.lang.String");
        Class<?> y = Class.forName("java.lang.String");

     System.out.println("y = " + y);
    }

}

运行结果如下:

y = class java.lang.String

5.泛型方法的定义,它接受的参数和它的返回值会搜索继承树上最近的一个分支点

比如说,猫和狗它们的最小父类是犬科动物,而不是脊椎动物

package com.yuki.generic;

public class Demo5 {

    @SuppressWarnings("unused")
    public static void main(String[] args) {

        Integer i = add(3, 5);

        // Float n = add(3.5, 5); // error!
        // Float 和 Integer 的父类是 Number
        Number n = add(3.5, 5);

        Object o = add(3, "abc");
    }

    // 在返回方法前,获取方法的类型参数
    private static <T> T add(T x, T y){
        System.out.println("wake up : x = " + x + ", y = " + y);
        return null;
    }

}

运行结果如下:

wake up : x = 3, y = 5
wake up : x = 3.5, y = 5
wake up : x = 3, y = abc

6.定义一个一个泛型的方法,int[]已经是引用类型而不是基本类型,所以不能自动封箱

package com.yuki.generic;

public class Demo6 {

    public static void main(String[] args) {

        String[] a = swap(new String[]{"abc", "xyz", "uvw"}, 1, 2);
        StringBuilder sb = new StringBuilder();
        for(String s : a){
            sb.append(s + ',');
        }
        System.out.println(sb);

        // 泛型必须是引用类型,不能使基本类型
        // int[] 已经是对象了,所以不能自动封箱
        // swap(new int[]{1, 2, 3, 4, 5}, 3, 4); // error!

    }

    /**
     * 定义泛型是可以限定类型
     * 限定它必须实现某接口或实现某类,用and连接
     * <T extends Serializable & Cloneable>
     *
     * 可以抛出泛型的异常
     * <T extends Exception> void methodName() throws T
     *
     * 声明多个泛型之间用,分割
     */
    private static <T> T[] swap(T[] a, int i, int j){
        T temp = a[i];
        a[i] = a[j];
        a[j] = temp;

        return a;
    }

}

运行结果如下:

abc,uvw,xyz,

7.自动类型转换的泛型方法,虽然可以不必这么麻烦的。。。

package com.yuki.generic;

public class Demo7 {

    public static void main(String[] args) {

        Object o = "abc";
        String s = autoConvert(o);

        System.out.println("s = " + s);
    }

    @SuppressWarnings("unchecked")
    private static <T> T autoConvert(Object o){
        return (T)o;
    }

}

运行结果如下:

s = abc

8.当参数中有两个相同的泛型类型引用时,这里, 第一个匹配的参数类型确定方法的泛型类型

package com.yuki.generic;

import java.util.Collection;
import java.util.Date;
import java.util.Vector;

public class Demo8 {

    public static void main(String[] args) {

        // 正确
        copy1(new Vector<String>(), new String[10]);

        // Date和String取共同的最小父类
        copy2(new Date[10], new String[20]);

        // String不是Date的子类
        // copy1(new Vector<Date>(), new String[10]); // error!

    }

    //
    private static <T> void copy1(Collection<T> c, T[] a){

    }

    private static <T> void copy2(T[] c, T[] a){

    }
}

9.定义泛型类,类的实例方法可以使用运行实例化的泛型类,但是,静态方法与类的实例,所以需要定义为泛型方法

程序的入口:Demo9

package com.yuki.generic;

public class Demo9 {

    public static void main(String[] args) {

        GenericSample<String> gs = new GenericSample<>();

        // 参数类型不匹配
        // gs.add(3); // error!

        gs.add("hello, generic");
        String s = gs.look();

        System.out.println("s = " + s);
    }

}

使用到的类:GenericSample

package com.yuki.generic;

// 类级别的泛型
public class GenericSample<E> {

    private E e;

    public void add(E e){
        this.e = e;
    }

    public E look(){
        return e;
    }

    // 静态方法不能使用类的实例才能使用的泛型
    // public static void staticMethod(E e) { }

    // 这里使用的是方法级别的泛型
    public static <E> void staticMethod(E e) { }
}

运行结果如下:

s = hello, generic

10.怎样知道方法的泛型参数中可以容纳的泛型参数类型呢?

程序入口:Demo10

package com.yuki.generic;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Vector;

public class Demo10 {

    public static void main(String[] args) throws Exception {

        GenericParameter<Date> gp = new GenericParameter<>();

        // 怎样知道集合中所装的实例类型
        Class<?> clazz = gp.getClass();
        Method method = clazz.getMethod("applyVector", Vector.class);

        // Type是Class的子类,它的其中一个子接口是ParameterizedType
        Type[] types = method.getGenericParameterTypes();
        ParameterizedType pType = (ParameterizedType) types[0];

        // 得到泛型的类型
        Type t = pType.getRawType();
        // 得到泛型参数的类型
        Type[] ta = pType.getActualTypeArguments();

        System.out.println("t = " + t);
        System.out.println("ta[0] = " + ta[0]);

        Method method2 = clazz.getMethod("applyList", List.class);
        ParameterizedType pType2 = (ParameterizedType) method2.getGenericParameterTypes()[0];
        System.out.println("rawType = " + pType2.getRawType());
        System.out.println("actualTypeArguments[0] = " + pType2.getActualTypeArguments()[0]);
    }

}

使用到的类:GenericParameter<E>

package com.yuki.generic;

import java.util.Date;
import java.util.List;
import java.util.Vector;

public class GenericParameter<E> {

    public void applyVector(Vector<E> v){
        // 我们不知道参数列表中参数的类型,
        // 但是当把变量交给一个方法去使用时
        // 可以知道方法所接受参数的实际类型
    }

    public void applyList(List<Date> v){

    }
}

运行结果如下:

t = class java.util.Vector
ta[0] = E
rawType = interface java.util.List
actualTypeArguments[0] = class java.util.Date

跟多好文请看:http://www.cnblogs.com/kodoyang/

Thanks!

Java核心 --- 泛型的更多相关文章

  1. java核心卷轴之泛型程序设计

    本文根据<Java核心卷轴>第十二章总结而来,更加详细的内容请查看<Java核心卷轴> 1. 泛型类型只能是引用类型,不可以使用基本数据类型. 2. 类型变量含义 E : 集合 ...

  2. Java核心 --- 枚举

    Java核心 --- 枚举 枚举把显示的变量与逻辑的数字绑定在一起在编译的时候,就会发现数据不合法也起到了使程序更加易读,规范代码的作用 一.用普通类的方式实现枚举 新建一个终态类Season,把构造 ...

  3. Java核心编程快速学习

    Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...

  4. Java基础学习笔记二十三 Java核心语法之反射

    类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...

  5. Java核心编程快速入门

    Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...

  6. Java中泛型使用

    Java中泛型使用 泛型作用: 泛型:集合类添加对象不用强转 反射机制:将泛型固定的类的所有方法和成员全部显示出来 核心代码: ArrayList<Ls> ff=new ArrayList ...

  7. Java核心编程快速学习(转载)

    http://www.cnblogs.com/wanliwang01/p/java_core.html Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体 ...

  8. 2018.6.19 Java核心API与高级编程实践复习总结

    Java 核心编程API与高级编程实践 第一章 异常 1.1 异常概述 在程序运行中,经常会出现一些意外情况,这些意外会导致程序出错或者崩溃而影响程序的正常执行,在java语言中,将这些程序意外称为异 ...

  9. 深入Java核心 Java中多态的实现机制(1)

    在疯狂java中,多态是这样解释的: 多态:相同类型的变量,调用同一个方法时,呈现出多中不同的行为特征, 这就是多态. 加上下面的解释:(多态四小类:强制的,重载的,参数的和包含的) 同时, 还用人这 ...

随机推荐

  1. Java:网络编程之IP、URL

    java.net  类 InetAddress 此类表示互联网协议 (IP) 地址. 会抛出异常 UnknownHostException   直接已知子类:         Inet4Address ...

  2. Partitioner

    partitioner 是map中的数据映射到不同的reduce时的根据.一般情况下,partitioner会根据数据的key来把数据平均分配给不同的reduce,同时保证相同的key分发到同一个re ...

  3. SPOJ 416 Divisibility by 15 细节题

    一个结论:一个数,如果它的所有数字之和能被3整除,那么这个数也能被3整除. 最后一位肯定是0或者5,如果没有就impossible. 剩下的就是,如何删除尽量少的数,使所有数字之和为3的倍数. 情况比 ...

  4. SPOJ 274 Johnny and the Watermelon Plantation(TLE)

    O(n^3)的时间复杂度,改了半天交了二三十遍,TLE到死,实在没办法了…… 跪求指点!!! #include <cstdio> #include <cstdlib> #inc ...

  5. 最短JS判断是否为IE6(IE的写法) (转)

    常用的 JavaScript 检测浏览器为 IE 是哪个版本的代码,包括是否是最人极端厌恶的 ie6 识别与检测. 代码如下: var isIE = !!window.ActiveXObject; v ...

  6. php实现新闻页面

    首页 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8& ...

  7. [POJ1050]To the Max(最大子矩阵,DP)

    题目链接:http://poj.org/problem?id=1050 发现这个题没有写过题解,现在补上吧,思路挺经典的. 思路就是枚举所有的连续的连续的行,比如1 2 3 4 12 23 34 45 ...

  8. Webservce、WCF、WebApi的区别

    Web Service It is based on SOAP and return data in XML form. It support only HTTP protocol. It is no ...

  9. URAL1355. Bald Spot Revisited

    1355 其实就是求质因子的个数 这样肯定是最多的 注意一下 除到最后不是1的情况 #include <iostream> #include<cstdio> #include& ...

  10. R语言 rwordseg包的下载

    在CRAN中没有,如果通过R下载经常会出错,使用以下地址下载后加载本地包 http://R-Forge.R-project.org/bin/windows/contrib/3.0/Rwordseg_0 ...