Java泛型学习

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java泛型学习相关的知识,希望对你有一定的参考价值。


package com.fish.genrictiry;
import java.util.ArrayList;
/*
 泛型是jdk1.5使用的新特性。
 
 
  泛型的好处:
  1. 将运行时的异常提前至了编译时。
  2. 避免了无谓的强制类型转换 。
  
  
泛型在集合中的常见应用:
  
  ArrayList<String>  list = new ArrayList<String>();  true     推荐使用。
  
  ArrayList<Object>  list = new ArrayList<String>();  false
  ArrayList<String>  list = new ArrayList<Object>();  false
  
  //以下两种写法主要是为了兼顾新老系统的兼用性问题。
   * 
    ArrayList<String>  list = new ArrayList();           true   
  
    ArrayList    list = new ArrayList<String>();   true   
 
注意: 泛型没有多态的概念,左右两边的数据 类型必须 要一致,或者只是写一边的泛型类型。
推荐使用: 两边都写泛型。
 
 
需求: 把一个集合中元素全部转成大写。 
 
*/
 
public class Demo1 {
    public static void main(String[] args) {
        ArrayList<String>  list = new ArrayList<String>();  //<String> 表示该容器只能存储字符串类型 的数据。
        list.add("aa");
        list.add("bb");
        list.add("cc");
        
        
        for(int i = 0 ; i < list.size() ; i++){
            String str =  list.get(i);
            System.out.println("大写:"+ str.toUpperCase());
        }
        
        MyUtil.print(list);
        ArrayList<String> list2 = MyUtil.getList();
    
    }
}


package com.fish.genrictiry;
import java.util.ArrayList;
//是老程序员写 的。  jdk1.4的时候写的。
public class MyUtil {
    public static ArrayList getList(){
        return new ArrayList();
    }
    public static void print(ArrayList list){
        for (int i = 0; i < list.size() ; i++) {
            System.out.println(list.get(i));
        }
     }
}


package com.fish.genrictiry;
/*
 需求: 定义一个方法可以接收任意类型的参数,而且返回值类型必须 要与实参的类型一致。
 
 自定义泛型:  自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。
 
 方法上自定义泛型:
 
 修饰符  <声明自定义的泛型>返回值类型    函数名(使用自定义泛型 ...){
 
 }
 
在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。
 byte----> Byte
 short---> Short 
 int----> Integer
 long----> Long 
 
 double ----> Double 
 float -----> Float
 
 boolean-----Boolean
 
 char-------》 Character 
 
 
 方法泛型注意的事项:
 1. 在方法上自定义泛型,这个自定义泛型的具体数据类型是在调用该 方法的时候传入实参时确定具体的数据类型的。
 2. 自定义泛型只要符合标识符 的命名规则即可, 但是自定义泛型我们一般都习惯使用一个大写字母表示。  T Type  E Element
 
 */
public class Demo2 {
    public static void main(String[] args) {
            String str = getData("abc");
            Integer i = getData(123);
        }
    public static <abc>abc getData(abc o){
        return o;
    }
}
package com.fish.genrictiry;
import java.util.ArrayList;
/*
 需求: 编写一个数组 的工具类
 
 泛型类:
 
泛型类的定义格式:
class 类名<声明自定义泛型>{
}
 
泛型类要注意的事项:
 1. 在类上自定义泛型的具体数据类型是在使用该类的时候创建对象时候确定的。
 2. 如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象 的时候没有指定 泛型的具体数据类型,那么默认为Object类型
 3.在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用。
 
 
 
 */
class MyArrays<T>{
    //元素翻转
    public void reverse(T[] arr){
        for(int startIndex = 0, endIndex = arr.length-1 ; startIndex<endIndex ; startIndex++,endIndex--){
            T temp  = arr[startIndex];
            arr[startIndex] = arr[endIndex];
            arr[endIndex] = temp;
        }
    }
    //
    public String toString(T[] arr){
        StringBuilder sb = new StringBuilder();
        for(int i = 0 ; i < arr.length ; i++){
            if(i==0){
                sb.append("["+arr[i]+",");
            }else if(i==arr.length-1){
                sb.append(arr[i]+"]");
            }else{
                sb.append(arr[i]+",");
            }
        }
        return sb.toString();
    }
    public static <T>void print(T[] t){
    }

    
}
public class Demo3 {
    public static void main(String[] args) {
        Integer[] arr = {10,12,14,19};
        MyArrays<Integer> tool = new MyArrays<Integer>();
        tool.reverse(arr);
        System.out.println("数组的元素:"+tool.toString(arr));
        
        MyArrays<String> tool2 = new MyArrays<String>();
        String[] arr2 = {"aaa","bbb","ccc"};
        tool2.reverse(arr2);
        
        ArrayList<String> list = new ArrayList<String>();
    }
}


package com.fish.genrictiry;
/*
 泛型接口
 
泛型接口的定义格式: 
interface 接口名<声明自定义泛型>{
}
泛型接口要注意的事项:
1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定 的。
2. 在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型。
需求: 目前我实现一个接口的时候,我还不明确我目前要操作的数据类型,我要等待创建接口实现类 对象的时候我才能指定泛型的具体数据类型。
如果要延长接口自定义泛型 的具体数据类型,那么格式如下:
格式:  
public class Demo4<T> implements Dao<T>{
}
*/

interface Dao<T>{
    public void add(T t);
 }
public class Demo4<T> implements Dao<T> {

    public static void main(String[] args) {
        Demo4<String> d = new Demo4<String>();
    }
    public void add(T t){
    
    }
}


package com.fish.genrictiry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

/*
 泛型的上下限:
 
需求1: 定义一个函数可以接收接收任意类型的集合对象, 要求接收的集合对象只能存储Integer或者是Integer的父类类型数据。
需求2: 定义一个函数可以接收接收任意类型的集合对象, 要求接收的集合对象只能存储Number或者是Number的子类类型数据。
泛型中通配符: ? 
? super Integer : 只能存储Integer或者是Integer父类元素。  泛型 的下限
 
 ? extends Number : 只能存储Number或者是Number类型的子类数据。 泛型上限
 
*/
public class Demo5 {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<Integer>();
        ArrayList<Number> list2 = new ArrayList<Number>();
        HashSet<String> set = new HashSet<String>();
        //getData(set);
    }
    
    //泛型的上限
    public static void getData(Collection<? extends Number> c){
    }
    
    //泛型的下限
    public static void print(Collection<? super Integer> c){
    
    }
}




总结:


单例集合 的体系:

---------| Collection 单例集合的根接口

------------| List  如果是实现了List接口的集合类, 具备的特点:有序,重复。

---------------| ArraryList  底层 是使用了Object数组实现的,特点: 查询速度快,增删慢。

---------------| LinkedList 底层是使用了链表数据结构实现 的, 特点: 查询速度慢,增删快。

---------------| Vector Vector的实现与ArrayList是一致,但是是线程安全 的,操作效率低。 jdk1.0的时候出现的

------------| Set  如果是实现了Set接口的集合类,具备的特点:无序,不可重复。

----------------| HashSet  底层是使用了一个哈希表支持的, 特点:存取速度快。

HashSet添加元素的原理:

往HashSet添加元素的时候,首先HashSet会调用元素的hashCOde方法得到元素的哈希码值,然后会经过一系列运算

就可以算出该元素在哈希表中的存储位置/

情况1:如果算出该元素的位置目前没有任何元素存储,那么该元素可以直接存储 

情况2: 如果算出该元素的位置目前已经存有其他的元素,那么还会调用元素的equals方法与该位置的元素再比较一次。

如果equals方法返回的是false,那么该元素允许存储,如果euqlas方法返回的是true,那么该元素被视为重复元素,不允许存储。

------------------| TreeSet  底层是使用了红黑树(二叉树)数据结构实现的, 特点:会对元素进行排序存储。


TreeSet要注意的事项:

1. 往TreeSet添加元素的时候,如果元素本身具备自然顺序的特性,那么会根据元素自然顺序的特性进行排序存储。

2. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么元素所属的类必须要实现Comparable接口,把元素的比较规则定义

在CompareTo方法上。

3. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而且元素所属的类没有实现COmparable接口,那么必须要在创建

TreeSet对象的时候传入比较器。

4. 如果比较的方法(CompareTo 或者Compare )返回的是0的时候,那么该元素就被视为重复元素,不允许添加。

比较器的定义格式:  自定义一个类实现COmparator接口即可。

class 类名  implements Comparator{

}


泛型:泛型是jdk1.5出现的新特性。


泛型的好处:

1. 将运行时出现 的问题提前至了编译时。

2. 避免了无谓强制类型转换。

自定义泛型: 自定义泛型就是一个数据类型的占位符或者理解为一个数据类型的变量。

泛型方法:

修饰符  <声明自定义的泛型>返回值类型  函数名(自定义的泛型  变量名..)

泛型方法要注意的事项: 

1. 泛型方法中 的自定义泛型的具体数据类型是在调用该函数的时候传入实参时确定的。

2. 自定义泛型所用 的标识符只要符合标识符 的命名规则即可。但是我们一般都习惯使用一个大写字母表示。


泛型类:


泛型类的定义格式

class 类名<声明自定义的泛型>{

}


泛型类要注意的事项:

1. 泛型类上的自定义泛型是在使用该类创建对象的时候指定具体的数据类型的。

2. 如果一个类已经自定义了泛型,使用该类创建对象的时候如果没有指定泛型的具体数据类型,那么默认为Object类型。

3. 静态的函数不能使用类上自定义的泛型,如果静态函数需要使用,必须要在函数上自定义泛型。


泛型接口:


泛型接口的定义格式:

interface 接口名<声明自定义的泛型>{

}

泛型接口要注意事项:

1. 泛型接口上的自定义泛型是在实现该接口的时候指定具体数据类型的。

2. 如果实现接口的时候没有指定接口上 的自定义泛型的具体数据类型,那么默认为Object数据类型。

3. 如果需要在创建接口实现类对象的时候才指定接口上自定义泛型,那么需要以下格式: class<T> 类名  implements  接口<T>


泛型上下限:

? super Integer   允许是Integer数据类型或者是Integer父类类型       泛型的下限

?  extedns Number  允许是Number数据类型或者是Number子类的数据类型   泛型的上限。




本文出自 “小鱼的博客” 博客,谢绝转载!

以上是关于Java泛型学习的主要内容,如果未能解决你的问题,请参考以下文章

操作 Java 泛型:泛型在继承方面体现与通配符使用

Java泛型:类型擦除

201621123054《Java程序设计》第九周学习总结

Java泛型学习笔记 - 泛型的继承

201621123048《Java程序设计》第九周学习总结

201671010135 2016--2017--《java程序设计:泛型数组设计学习总结》