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. C++:构造函数默认的参数声明

    C++函数的默认参数指的是在函数声明或者定义时给形式参数指定默认值,从而在调用参数时可以少写参数,少掉的参数用默认值代替.LZ的Display()函数的代码看起来似乎是可以有s2和s3两个默认参数,那 ...

  2. wordcount数据流过程解析

    (1)执行hadoopFile()操作,其中有生成HadoopRDD的new 方法.然后执行map方法.pair => pair._2.toString,只对Value值进行操作.在textFi ...

  3. js webstorm用法

    js  webstorm用法 一.什么是webstorm?       WebStorm 是jetbrains公司旗下一款JavaScript 开发工具.被广大中国JS开发者誉为“Web前端开发神器” ...

  4. C# 文件递归

    C#   文件递归 Directory.GetDirectories: 获取指定目录下的文件夹,不包括子目录: Directory.GetFiles:获取指定文件夹下的文件,不包括子目录: 1.获取所 ...

  5. Android 如何处理崩溃的异常

    Android中处理崩溃异常    大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试 ...

  6. POJ-3669 Meteor Shower(bfs)

    http://poj.org/problem?id=3669 注意理解题意:有m颗行星将会落在方格中(第一象限),第i颗行星在ti时间会摧毁(xi,yi)这个点和四周相邻的点,一个人开始在原点,然后只 ...

  7. JS function的定义方法,及function对象的理解。

    废话篇: 今天看到了Function的内容,各种晕,各种混淆有木有.简直是挑战个人脑经急转弯的极限啊.不过,最终这一难题还是被我攻克了,哇咔咔.现在就把这东西记下来,免得到时候又忘了就悲催了.... ...

  8. Python3 学习第十弹: 模块学习三之数字处理

    math模块 提供基础的数学函数, cos(3.14) = -0.999..(弧度制) acos(1) = 0.0 sqrt(9) = 3.0 degrees(3.14) = 179.9999..(弧 ...

  9. bzoj4127

    肯定是树链剖分+线段树,关键是怎么维护 绝对值和这个东西显然不能简单的合并标记 因为对于负数,加之后绝对值和是变小的 那我们考虑对负数和非负数数分别维护 下面的问题就是经过操作如果负数变成了正数怎么办 ...

  10. HDU 1058 Humble Numbers【DP】

    题意:给出丑数的定义,只含有2,3,5,7这四个素数因子的数称为素数.求第n个丑数. 可以先观察几个丑数得出规律 1:dp[1] 2:min(1*2,1*3,1*5,1*7) 3:min(2*2,1* ...