java夯实基础系列:泛型

一.概念

1.为什么需要泛型?

不使用泛型时:

public class Test01 {

    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("m1", "sssss");
        String str = (String)map.get("m1");

    }
}

使用泛型后:

public class Test01 {

    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("m1", "sssss");
        String str = map.get("m1");
    }
}

jdk1.5出现的泛型,通过<数据类型>来接收一种引用数据类型,作用是编译程序时,使用检查集合中添加的对象是否是该类型的,从而把运行时期的问题转移到了编译时期,提高了程序的安全性。否则很容易出现“java.lang.ClassCastException”异常。使用泛型就可以解决此类问题。

这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

泛型擦除:编译时存在泛型,编译完成后字节码文件中是没有泛型的.

2.泛型的优缺点

在泛型出现之前,当我们想增加程序的扩展性时,常用Object,但是泛型出现之后,我们更多的时候使用泛型。

使用Object

public class Tool {
    private Object obj;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }
}

使用泛型

public class Tool1<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

一个实体类

public class Worker {
}

使用对比

public class Test01 {

    public static void main(String[] args) {
//        HashMap<String, String> map = new HashMap<>();
//        map.put("m1", "sssss");
//        String str = map.get("m1");

        // 使用object
        Tool tool = new Tool();
        tool.setObj(new Worker());
        Worker worker = (Worker) tool.getObj();

        // 使用泛型
        Tool1<Worker> tool1 = new Tool1<>();
        tool1.setT(new Worker());
        Worker worker1 = tool1.getT();
    }
}

3.什么是泛型?

所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。泛型的出现避免了强转,并且把错误转移到了编译时期。

泛型格式:通过<>来定义要操作的引用数据类型

其实Java的泛型就是创建一个用类型作为参数的类。就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1、str2的值是可变的。而泛型也是一样的,这样写class Java_Generics<K,V>,这里边的K和V就象方法中的参数str1和str2,也是可变。

泛型参数的命名风格为:推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。使用T代表类型,无论何时都没有比这更具体的类型来区分它。这经常见于泛型方法。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。如果一个泛型函数在一个泛型类里面出现,最好避免在方法的类型参数和类的类型参数中使用同样的名字来避免混淆。对内部类也是同样。

编写泛型类要注意:

1) 在定义一个泛型类的时候,在 “<>”之间定义形式类型参数,例如:“class TestGen<K,V>”,其中“K” , “V”不代表值,而是表示类型。

2) 实例化泛型对象的时候,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。例如:

TestGen<String,String> t=new TestGen<String,String>();

3) 泛型中<K extends Object>,extends并不代表继承,它是类型范围限制。

4.什么时候使用泛型?

1.当类中要操作的引用数据类型不确定的时候

2.早期定义object来完成扩展,现在定义泛型来完成扩展。一般的应用开发中泛型使用较少,多用在框架或者库的设计中,为增加扩展性。

二.泛型的使用

1.泛型类

直接看代码:

public class Demo1 {
    public void show(String s) {
        System.out.println("show:" + s);
    }

    public void show(Integer i) {
        System.out.println("show:" + i);
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        demo1.show(3);
        demo1.show("111111");
    }
}

public class Demo<T> {
    public void show(T t) {
        System.out.println("show:" + t);
    }

    public static void main(String[] args) {
        Demo<String> demo = new Demo<>();
        demo.show("hello");

        Demo<Integer> demo1 = new Demo<>();
        demo1.show(2);

    }
}

以上对使用泛型和不使用泛型做了对比,我们之前需要写两个方法,现在一个就搞定了,泛型的优势不言自明。

说明:

泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型之后,所有要操作的类型就固定了,即方法操作的类型就固定了。一个方法的参数的类型只有在该类上的泛型确定了才能确定。

为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。

2.泛型方法

为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。

泛型定义在方法上时,放在返回类型的前面,修饰符的后面。

    public <E> void fun(E e) {
        System.out.println("show:" + e);
    }
        Demo<Integer> demo1 = new Demo<>();
        demo1.fun("fdfdfdf");
        demo1.fun(122);

全部代码:

public class Demo<T> {
    public void show(T t) {
        System.out.println("show:" + t);
    }

    // 这个E与类的泛型类型是无关的
    public <E> void fun(E e) {
        System.out.println("show:" + e);
    }

    public static void main(String[] args) {
        Demo<String> demo = new Demo<>();
        demo.show("hello");

        Demo<Integer> demo1 = new Demo<>();
        demo1.show(2);

        demo1.fun("fdfdfdf");
        demo1.fun(122);

    }
}

说明:

静态方法泛型有一个需要注意:

静态方法不可以访问类上定义的泛型,只能将泛型定义到方法上。原因是因为:类加载的时候,类还没有泛型类型呢,之后创建了类的对象,才知道类的泛型。

    public static <W> void method (W w) {
        System.out.println("show:" + w);
    }

3.泛型接口

直接看代码

public interface Inter<T> {
    void show (T t);
}

public class InterImpl implements Inter<String> {
    @Override
    public void show(String s) {

    }
}

假设类在实现接口的时候,并不知道泛型的类型,怎么办呢?

public interface Inter<T> {
    void show (T t);
}

public class InterImpl1<T> implements Inter<T> {
    @Override
    public void show(T t) {

    }
}

4.通配符(?)

任意类型,这样可以提高他的通用性

public class Demo4 {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("111");
        list.add("2222");
        list.add("333");
        dieDai(list);
    }

    private static void dieDai(ArrayList list) {
        for (int i = 0; i < list.size(); i++) {
            Object o = list.get(i);
            System.out.println(o);
        }
    }

    private static void dieDai1(ArrayList<?> list) {
        for (int i = 0; i < list.size(); i++) {
            Object o = list.get(i);
            System.out.println(o);
        }
    }

    private static <Q> void dieDai2(ArrayList<Q> q) {
        for (int i = 0; i < q.size(); i++) {
            Q q1 = q.get(i);
            System.out.println(q1);
        }
    }
}

5.泛型限定(extends ,super )

受限泛型是指在泛型的操作过程中,可以指定一个泛型对象的范围上限和范围下限

格式:

上限:
      声明对象:  类名称<? extends Person>对象名称
      声明类:访问权限 类名称<泛型标识 extends 类>

      这个尖括号里必须是person或者person的子类.就是你传过来的集合元素类型可以是person或者person的子类

 下限:
      声明对象:  类名称<? super Person>对象名称
      这个尖括号里必须是person或者person的父类.就是你传过来的集合元素类型可以是person或者person的父类
class Info<T>{
      private T var;

      public T getVar() {
           return var ;
     }

      public void setVar(T var) {
           this .var = var;
     }

}

public class TypeTest {

      public static void main(String[] args) {
          Info< Integer>i= new Info< Integer>();
          i.setVar(20);
           fun(i);
     }

      public static void fun(Info<? extends Number> temp){
          System. out .println("内容" +temp.getVar());
     }
}

6.泛型数组

public class TypeTest {

           public static void main(String[] args) {
               //Integer i[]={1,2,3,4,5};//静态初始化数组
              Integer i[]= fun1(1,2,3,4,5);
               fun2(i);
          }

           public static <T> T[] fun1(T...arg){ //可变参数和泛型数组
               return arg;
          }

           public static <T> void fun2(T param[]){
               for (T t: param){
                   System. out .print(t+"," );
              }
          }

}

三.参考资料

https://yq.aliyun.com/articles/3311

http://www.weixueyuan.net/view/6321.html

http://blog.csdn.net/u012152619/article/details/47253811

时间: 2024-11-08 08:21:59

java夯实基础系列:泛型的相关文章

Java【基础系列】-文件编码与格式

本章主题: 简要的回顾java的基础知识 读文件: BufferedReader 从字符输入流中读取文本,缓冲各个字符,从而提供字符.数组和行的高效读取. 可以指定缓冲区的大小,或者可使用默认的大小.大多数情况下,默认值就足够大了. 通常,Reader 所作的每个读取请求都会导致对基础字符或字节流进行相应的读取请求.因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader).例如, B

夯实基础系列一:Java 基础总结

前言 大学期间接触 Java 的时间也不短了,不论学习还是实习,都让我发觉基础的重要性.互联网发展太快了,各种框架各种技术更新迭代的速度非常快,可能你刚好掌握了一门技术的应用,它却已经走在淘汰的边缘了. 而学习新技术总要付出一定的时间成本,那么怎么降低时间成本呢?那就是打好基础,技术再怎么革新,底层的东西也很少会变动,牢固的基础会帮助你在各种新技术的学习中游刃有余,快速上手. 因为我选择的方向是后台开发,所以谈谈我认为的基础有哪些.其他方向肯定也有自己的体系,从低层到高层,可以自己摸索.后台的话

Java(C#)基础差异-泛型

1.限制泛型可用类型 Java 语法如下: class 类名称<T extends anyClass> 其中,anyClass指摸个接口或类. 使用泛型限制后,泛型类的类型必须实现或继承了anyClass这个接口或类.无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字. 举例如下: import java.util.*; public class LimitClass<T extends List> { public static void main(

Java Se 基础系列(笔记) -- BasicDataType

java.lang.String类代表不可变的字符序列 String类常用方法:1.public char charAt(int index); -- 返回下标为index的字符 2.public int length(); 3.public int indexOf(String str); -- 返回字符串中第一次出现字符串str的下标   4.public int indexOf(String str, int fromIndex); 5.public boolean equalsIgnor

Java Se 基础系列(笔记) -- Exception

Exception 1.java 异常是java提供的用于处理程序中错误(指在程序运行的过程中发生的一些异常事件)的一种机制 2.java程序的执行过程中如果发生异常事件则自动生产一个异常类对象,该对象封装了异常事件的信息并被提交给java运行时系统,这过程称为throw异常: 当java运行时系统接收到异常对象时会寻找能处理这一异常的代码并交其处理,这过程称为catch异常 1 public class TestEx1 { 2 public static void main(String[]

Java零基础系列005——条件控制

public class Control { public static void main(String[] args) { //java里常用的条件控制语句有if-esle,switch语句. boolean tr = true; boolean fa = false; //if语句后面的括号里装的是逻辑,其结果是boolean类型,当括号中结果为true时,程序运行大括号里的语句,否者运行else里面的. System.out.println("*******************if-

Java零基础系列002——命名、变量类型、类型转换、JDK中二进制整数和数字分隔符新特性

public class BasicDataType { public static void main(String[] args) { /* * 标示符:用于给变量.方法.类命名,必须以字母.下划线.$符号开头.以字母.下划线.数字.$符号组合,且不能为关键字 * * * */ System.out.println("--------------标示符------------"); int $,_,a;//正确的命名 int 彭驰=12;//由于Java内部采用Unicode编码方

JavaScript夯实基础系列(四):原型

??在JavaScript中有六种数据类型:number.string.boolean.null.undefined以及对象,ES6加入了一种新的数据类型symbol.其中对象称为引用类型,其他数据类型称为基础类型.在面向对象编程的语言中,对象一般是由类实例化出来的,但是在JavaScript中并没有类,对象是以与类完全不同的设计模式产生的. 一.创建对象 ??最常用来创建的方式是通过对象字面量的方式,简单便捷.但是该方式为单例模式,如果创建类似的对象会产生过多重复的代码,如下代码所示: var

夯实基础系列二:网络知识总结

前言 无论是 C/S 开发还是 B/S 开发,无论是前端开发还是后台开发,网络总是无法避免的,数据如何传输,如何保证正确性和可靠性,如何提高传输效率,如何解决会话管理问题,如何在网络拥堵环境下采取措施.这些都是需要了解的. 今天总结下与网络相关的知识,不是那么详细,但是包含了我认为重要的所有点.如果想深入了解的可以参考<图解HTTP[上野 宣]>.<图解TCP/IP(第5版)[竹下隆史]>以及计算机网络相关教材. 概要 网络知识我做了 8 个方面的总结,包括DNS协议,HTTP协议