• 牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现


       不多说,直接上干货!

       先来看个泛型概念提出的背景的例子。

     GenericDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    public class GenericDemo {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            ArrayList al = new ArrayList();
            
            al.add("abc");//public boolean add(Object obj)
            al.add("hahah");
            al.add(4);//al.add(new Integer(4));
            
            Iterator it = al.iterator();
            while(it.hasNext()){    
                String str = (String)it.next();//1处
                System.out.println(str);
            }
        }
    }

       

      输出

    Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        at zhouls.bigdata.DataFeatureSelection.GenericDemo.main(GenericDemo.java:20)
    abc
    hahah

       以上是运行时期出现问题了。

      定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。因为编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。

       在如上的编码过程中,我们发现主要存在两个问题:

      1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。

      2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。

      那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢?答案就是使用泛型。

        再次修改,GenericDemo.java

       这就是,将运行时期的问题ClassCastException转到了编译时期。

       

      再次修改,GenericDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    public class GenericDemo {
        /**
         * @param args
         */
        public static void main(String[] args) {
    
            ArrayList<String> al = new ArrayList<String>();
            
            al.add("abc");//public boolean add(Object obj)
            al.add("hahah");
    //      al.add(4);//al.add(new Integer(4));//1处
            
            Iterator<String> it = al.iterator();
            while(it.hasNext()){
                String str = it.next();//2处
                System.out.println(str);
            }
        }
    }

      采用泛型写法后,在//1处想加入一个Integer类型的对象时会出现编译错误,通过List<String>,直接限定了list集合中只能含有String类型的元素,从而在//2处无须进行强制类型转换,因为此时,集合能够记住元素的类型信息,编译器已经能够确认它是String类型了。

      结合上面的泛型定义,我们知道在List<String>中,String是类型实参,也就是说,相应的List接口中肯定含有类型形参。且get()方法的返回结果也直接是此形参类型(也就是对应的传入的类型实参)。

    什么是泛型?

      泛型:jdk1.5出现的安全机制。

      我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int型数据,另一个是处理String类型数据,或者其它自定义类型数据,但是我们没有办法,只能分别写多个方法处理每种数据类型,因为方法的参数类型不同。有没有一种办法,在方法中传入通用的数据类型,这样不就可以合并代码了吗?泛型的出现就是专门解决这个问题的。

    使用泛型的好处:
      好处:
      1、将运行时期的问题ClassCastException转到了编译时期。
      2、避免了强制转换的麻烦。



    <>什么时候用?

      当操作的引用数据类型不确定的时候。就使用<>。将要操作的引用数据类型传入即可.
      其实<>就是一个用于接收具体引用数据类型的参数范围。

      里面是引用类型,要么放类名,要么放接口名,要么放数组名。

      在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型 。泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。

    运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。

      为什么擦除呢?因为为了兼容运行的类加载器。

      泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者在强制转换了。

    泛型在集合中的应用

      我这里仅仅以集合中的TreeSet为例,

      更多集合,请见

    牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection、集合框架中的Map集合

     GenericDemo.java

     

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    import zhouls.bigdata.DataFeatureSelection.Person;
    import zhouls.bigdata.DataFeatureSelection.ComparatorByName;
    
    public class GenericDemo {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
    
        TreeSet<Person> ts = new TreeSet<Person>(new ComparatorByName());
            ts.add(new Person("lisi8",21));
            ts.add(new Person("lisi3",23));
            ts.add(new Person("lisi",21));
            ts.add(new Person("lis0",20));
            
            Iterator<Person> it = ts.iterator();
            
            while(it.hasNext()){
                Person p = it.next();
                System.out.println(p.getName()+":"+p.getAge());
            }
        }
    
    }

      因为TreeSet是需要是二叉树,需要进行比较排序。

    Person.java

    package zhouls.bigdata.DataFeatureSelection;
    
    public class Person implements Comparable<Person> {
    
        private String name;
        private int age;
        
        public Person() {
            super();    
        }
        
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        public int compareTo(Person p){    
    //        Person p = (Person)obj;
            int temp = this.age - p.age;
            return temp==0?this.name.compareTo(p.name):temp;
        }
        
    
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + age;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        } 
    
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Person other = (Person) obj;
            if (age != other.age)
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }
    
    
    
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    
    
    
    
        @Override
        public String toString() {
            
            return "Person:"+getName()+":"+getAge();
        }
    }

     ComparatorByName.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.Comparator;
    
    import zhouls.bigdata.DataFeatureSelection.Person;
    
    public class ComparatorByName implements Comparator<Person> {
        public int compare(Person o1, Person o2) {
            int temp = o1.getName().compareTo(o2.getName());
            return temp==0? o1.getAge()-o2.getAge(): temp;
        }
    }

     什么是泛型类?什么时候用泛型类?泛型类?

      在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。
      泛型类。什么时候用?当类中的操作的引用数据类型不确定的时候,就使用泛型来表示

     Tool.java

    package zhouls.bigdata.DataFeatureSelection;
    
    /*
    public class Tool {
    
        private Object object;
    
        public Object getObject() {
            return object;
        }
    
        public void setObject(Object object) {
            this.object = object;
        }
        
    }
    
    
    */
    //在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。
    //泛型类。什么时候用?当类中的操作的引用数据类型不确定的时候,就使用泛型来表示。 
    public class Tool<QQ>{
        private QQ q;
    
        public QQ getObject(){
            return q;
        }
    
        public void setObject(QQ object){
            this.q = object;
        }
        
        
        /**
         * 将泛型定义在方法上。
         * @param str
         */
        public <W> void show(W str){
            System.out.println("show : "+str.toString());
        }
        public void print(QQ str){
            System.out.println("print : "+str);
        }
        
        /**
         * 当方法静态时,不能访问类上定义的泛型。如果静态方法使用泛型,只能将泛型定义在方法上。 
         * @param obj
         */
        public static <Y> void method(Y obj){
            System.out.println("method:"+obj);
        }
    }

       GenericDefineDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import zhouls.bigdata.DataFeatureSelection.Student;
    import zhouls.bigdata.DataFeatureSelection.Worker;
    
    public class GenericDefineDemo{
        /**
         * @param args
         */
        public static void main(String[] args){
            Tool<String> tool = new Tool<String>();
            tool.show(new Integer(4));//show : 4
            tool.show("abc");//show : abc
            tool.print("hahah");//print : hahah
    //        tool.print(new Integer(8));//不能
            Tool.method("haha");//method:haha
            Tool.method(new Integer(9));//method:9
        }
        
    }

     Student.java

    package zhouls.bigdata.DataFeatureSelection;
    
    public class Student extends Person{
    
        public Student(){
            super();
            
        }
    
        public Student(String name, int age){
            super(name, age);
            
        }
    
        @Override
        public String toString(){
            return "Student:"+getName()+":"+getAge();
        }
    }

     Worker.java

    package zhouls.bigdata.DataFeatureSelection;
    
    public class Worker extends Person{
    
        public Worker(){
            super();
        }
    
        public Worker(String name, int age){
            super(name, age);
        }
    
        @Override
        public String toString(){
            return "Worker:"+getName()+":"+getAge();
        }
    }

    Person.java

    package zhouls.bigdata.DataFeatureSelection;
    
    public class Person implements Comparable<Person> {
        private String name;
        private int age;
        
        public Person() {
            super();
            
        }
        
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        public int compareTo(Person p){
    //        Person p = (Person)obj;
            int temp = this.age - p.age;
            return temp==0?this.name.compareTo(p.name):temp;
        }
        
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + age;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Person other = (Person) obj;
            if (age != other.age)
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            
            return "Person:"+getName()+":"+getAge();
        }
    }

    泛型接口

     

     GenericDefineDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    public class GenericDefineDemo {
        /**
         * @param args
         */
        public static void main(String[] args) {
            InterImpl in = new InterImpl();
            in.show("abc");
            
            InterImpl2<Integer> in2 = new InterImpl2<Integer>();
            in2.show(5);
        }
    }
    
    //泛型接口,将泛型定义在接口上。 
        interface Inter<T>{
            public void show(T t);
        }
    
        class InterImpl2<Q> implements Inter<Q>{
            public void show(Q q){
                System.out.println("show :"+q);
            }
        }
    
        class InterImpl implements Inter<String>{
            public void show(String str){
                System.out.println("show :"+str);
            }
        }    

    泛型限定上限

     GenericAdvanceDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Iterator;
    
    public class GenericAdvanceDemo {
        /**
         * @param args
         */
        public static void main(String[] args) {
            ArrayList<String> al = new ArrayList<String>();
            al.add("abc");
            al.add("hehe");
            
            ArrayList<Integer> al2 = new ArrayList<Integer>();
            al2.add(5);
            al2.add(67);
            printCollection(al);
            printCollection(al2);
        }
    
        /**
         * 迭代并打印集合中元素。
         * @param al
         */
        public static void printCollection(Collection<?> al) {    
            Iterator<?> it = al.iterator();
            while(it.hasNext()){
                System.out.println(it.next().toString()); 
            }
        }
    }

    泛型限定下限

    GenericAdvanceDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    
    import zhouls.bigdata.DataFeatureSelection.Person;
    import zhouls.bigdata.DataFeatureSelection.Student;
    import zhouls.bigdata.DataFeatureSelection.Worker;
    
    public class GenericAdvanceDemo {
        /**
         * @param args
         */
        public static void main(String[] args) {
            ArrayList<Person> al = new ArrayList<Person>();
            al.add(new Person("abc",30));
            al.add(new Person("abc4",34));
            
            ArrayList<Student> al2 = new ArrayList<Student>();
            al2.add(new Student("stu1",11));
            al2.add(new Student("stu2",22));
            ArrayList<String> al3 = new ArrayList<String>();
            
            al3.add("stu3331");
            al3.add("stu33332");
            
            printCollection(al2);
            printCollection(al);
        }
    
        /**
         * 迭代并打印集合中元素。
         * 
         * 可以对类型进行限定:
         * ? extends E:接收E类型或者E的子类型对象。上限!
         * 
         * ? super E :接收E类型或者E的父类型。下限!
         * @param al
         */
        /*public static void printCollection(Collection<? extends Person> al) {//Collection<Dog> al = new ArrayList<Dog>()
            Iterator<? extends Person> it = al.iterator();
            
            while(it.hasNext()){
    //            T str = it.next();
    //            System.out.println(str);
    //            System.out.println(it.next().toString());
                Person p = it.next();
                
                System.out.println(p.getName()+":"+p.getAge());
            }
            
        }*/
        
        public static void printCollection(Collection<? super Student> al){
            Iterator<? super Student> it = al.iterator();
            while(it.hasNext()){
                
                System.out.println(it.next());
            }
        }
    }

     什么时候使用上限?

     GenericAdvanceDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.ArrayList;
    import zhouls.bigdata.DataFeatureSelection.Person;
    import zhouls.bigdata.DataFeatureSelection.Student;
    import zhouls.bigdata.DataFeatureSelection.Worker;
    
    public class GenericAdvanceDemo{
        /**
         * @param args
         */
        public static void main(String[] args) {
            ArrayList<Person> al1 = new ArrayList<Person>();
            al1.add(new Person("abc",30));
            al1.add(new Person("abc4",34));
        
            ArrayList<Student> al2 = new ArrayList<Student>();
            al2.add(new Student("stu1",11));
            al2.add(new Student("stu2",22));
            
            ArrayList<Worker> al3 = new ArrayList<Worker>();
            al3.add(new Worker("stu1",11));
            al3.add(new Worker("stu2",22));
            
            ArrayList<String> al4 = new ArrayList<String>();
            al4.add("abcdeef");
    //        al1.addAll(al4);//错误,类型不匹配。
            
            al1.addAll(al2);
            al1.addAll(al3);
            System.out.println(al1.size());
        }
    }
    
    
    /*
     * 一般在存储元素的时候都是用上限,因为这样取出都是按照上限类型来运算的。不会出现类型安全隐患。 
     */
    class MyCollection<E>{
        public void add(E e){
        
        }
        public void addAll(MyCollection<? extends E> e){
        }
    }

    什么时候使用下限?

     

     GenericAdvanceDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.Comparator;
    import java.util.Iterator;
    import java.util.TreeSet;
    
    import zhouls.bigdata.DataFeatureSelection.Person;
    import zhouls.bigdata.DataFeatureSelection.Student;
    import zhouls.bigdata.DataFeatureSelection.Worker;
    
    public class GenericAdvanceDemo {
        /**
         * @param args
         */
        public static void main(String[] args) {
            TreeSet<Person> al1 = new TreeSet<Person>(new CompByName());
            al1.add(new Person("abc4",34));
            al1.add(new Person("abc1",30));
            al1.add(new Person("abc2",38));
            
            TreeSet<Student> al2 = new TreeSet<Student>(new CompByName());
            al2.add(new Student("stu1",11));
            al2.add(new Student("stu7",20));
            al2.add(new Student("stu2",22));
            
            
            TreeSet<Worker> al3 = new TreeSet<Worker>();
            al3.add(new Worker("stu1",11));
            al3.add(new Worker("stu2",22));
            
            TreeSet<String> al4 = new TreeSet<String>();
            al4.add("abcdeef");
    //        al1.addAll(al4);//错误,类型不匹配。
    //        al1.addAll(al2);
    //        al1.addAll(al3);
    //        System.out.println(al1.size());
            Iterator<Student> it = al2.iterator();
            while(it.hasNext()){
                System.out.println(it.next());
            }
        }
    }
    
    
    /*
     * class TreeSet<Worker>
     * {
     *         Tree(Comparator<? super Worker> comp);
     * }
     * 什么时候用下限呢?通常对集合中的元素进行取出操作时,可以是用下限。
     */
    
    class CompByName implements Comparator<Person>{
        public int compare(Person o1, Person o2) {
            int temp = o1.getName().compareTo(o2.getName());
            return temp==0? o1.getAge()-o2.getAge():temp;
        }
    }
    
    class CompByStuName implements Comparator<Student>{
        public int compare(Student o1, Student o2) {
            int temp = o1.getName().compareTo(o2.getName());
            return temp==0? o1.getAge()-o2.getAge():temp;
        }
    }
    
    class CompByWorkerName implements Comparator<Worker>{
        public int compare(Worker o1, Worker o2) {
            int temp = o1.getName().compareTo(o2.getName());
            return temp==0? o1.getAge()-o2.getAge():temp;
        }
    }

    泛型限定通配符的体现

     GenericAdvanceDemo.java

    package zhouls.bigdata.DataFeatureSelection;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Comparator;
    import java.util.Iterator;
    import java.util.TreeSet;
    
    import zhouls.bigdata.DataFeatureSelection.Person;
    import zhouls.bigdata.DataFeatureSelection.Student;
    import zhouls.bigdata.DataFeatureSelection.Worker;
    
    public class GenericAdvanceDemo {
        /**
         * @param args
         */
        public static void main(String[] args) {
            ArrayList<Person> al1 = new ArrayList<Person>();
            al1.add(new Person("abc",30));
            al1.add(new Person("abc4",34));
            
            ArrayList<Person> al2 = new ArrayList<Person>();
            al2.add(new Person("abc22222",30));
            al2.add(new Person("abc42222222",34));
    
            ArrayList<String> al4 = new ArrayList<String>();
            al4.add("abcdeef");
            al4.add("abc");
            al1.containsAll(al4);
    //        "abc".equals(new Person("ahahah",20));
        }
        public static void printCollection(Collection<?> al){
            Iterator<?> it = al.iterator();
            while(it.hasNext()){
                System.out.println(it.next().toString());
            }
        }
    }
    
        class MyCollection2<E>{
        public boolean containsAll(Collection<?> coll){
            return true;
        }
    }

    泛型的通配符

      ? 未知类型。

    泛型的限定
      ? extends E: 接收E类型或者E的子类型对象。上限
      一般存储对象的时候用。比如 添加元素 addAll.

      ? super E: 接收E类型或者E的父类型对象。 下限。
      一般取出对象的时候用。比如比较器。

    欢迎大家,加入我的微信公众号:大数据躺过的坑     免费给分享
     
     
     

    同时,大家可以关注我的个人博客

       http://www.cnblogs.com/zlslch/   和     http://www.cnblogs.com/lchzls/ 

       详情请见:http://www.cnblogs.com/zlslch/p/7473861.html

      人生苦短,我愿分享。本公众号将秉持活到老学到老学习无休止的交流分享开源精神,汇聚于互联网和个人学习工作的精华干货知识,一切来于互联网,反馈回互联网。
      目前研究领域:大数据、机器学习、深度学习、人工智能、数据挖掘、数据分析。 语言涉及:Java、Scala、Python、Shell、Linux等 。同时还涉及平常所使用的手机、电脑和互联网上的使用技巧、问题和实用软件。 只要你一直关注和呆在群里,每天必须有收获

           以及对应本平台的QQ群:161156071(大数据躺过的坑)

     

     

  • 相关阅读:
    Redis主从复制
    Redis发布订阅
    Redis持久化
    初探redis.config
    java连接Linux服务器问题
    Redis常见类型及API
    Redis安装
    Nosql
    JMM
    SpringSecurity
  • 原文地址:https://www.cnblogs.com/zlslch/p/7574951.html
Copyright © 2020-2023  润新知