精华内容
下载资源
问答
  • Java多态泛型
    2018-09-27 14:16:37

    一、多态理解
    1、判断是否是同一个函数,通过唯一性标识(方法名+参数(顺序、数量、类型一致))
    2、重载:参数 与 父类 不同
    重写(覆盖):方法名+参数 与 父类 相同
    3、多态分为编译时多态(重载)和运行时多态(重写、覆盖)。因为重载是不同的方法,编译器能编译的时候就确定是否调用该方法;而对于重写,只有在创建出由父类引用指向子类实例时候,才会知道调用的是哪个方法。
    4、多态只是针对方法的多态,属性没有多态。
    5、方法中被private、final、static修饰的方法会被关闭多态。
    6、运行时多态的必要条件就是存在继承关系与向上转型

    二、泛型理解
    1、引入泛型主要作用就是为了安全,在编译时就发现类型转换时的错误,增加编译时类型检查,从而不把错误带到运行阶段;其次,可以实现代码的复用
    2、泛型通过编译器类型擦除实现
    3、泛型指定的类不具有继承关系
    4、泛型典型例子:Collection中的Iterator

    三、多态与泛型关系
    定义的层面不一样:多态是基于继承关系,根据传入参数或者运行时的关系确定行为;而泛型是使用这个泛型类的时候再去确定这个类里面的成员具体是什么类型

    更多相关内容
  • java多态和泛型 从作为Java程序员的早期开始,我们都知道如何实例化使用Collection对象。 实例化为具体类的List接口将如下所示。 List myArrayList = new ArrayList(); 如果myArrayList应该仅保存Integer对象,则...
    java多态和泛型

    java多态和泛型

    从作为Java程序员的早期开始,我们都知道如何实例化和使用Collection对象。 实例化为具体类的List接口将如下所示。

    List myArrayList  =  new ArrayList();

    如果myArrayList应该仅保存Integer对象,则从Java 5编译器开始,按照Java Generics规范,实例化将如下所示:

    List<Integer> myArrayList = new ArrayList<Integer>();

    在同一行中,接受和/或返回字符串列表的方法将从

    public List processStrings(ArrayList myStringList);

    public List<String> processStrings(ArrayList<String> myStringList);

    而且它们是类型安全的,因此我们不必进行强制转换即可检索列表对象的项目

    String aStringFromMyStringList = myStringList.get(0); //No ClassCastException possible.

    如果将aStringFromMyStringList声明为String以外的任何内容,则以上内容将不会编译。

    到这里为止,我们应该对面向对象的Java如何工作感到满意,但是下一项可能会让许多人感到惊讶。

    当我们使用List<Integer> myArrayList = new ArrayList<Integer>(); 意味着我们应该只在ArrayList和NOTHING ELSE中使用“ Integer”。 等一下,泛型不是OOP的一部分,这意味着我们不能在这些对象中应用多态吗? 答案是不。 让我们看看为什么。

    我们已经看到多态性适用于集合的基本类型,这就是为什么List<Integer> myArrayList可以实例化为新的ArrayList<Integer>();

    但是呢:

    class Parent{}
    
    class Child extends Parent{}

    使用以上方法,以下实例将无法正常工作,并最终导致编译错误。

    List<Parent> myList = new ArrayList<Child>() //Compilation Error;

    一个简单的规则是变量声明的类型必须与您传递给实际对象类型的类型相匹配。 如果我们声明List<Parent> myList那么我分配给myList任何myList必须仅是<Parent>类型,而不是Parent类的子类型,而不是Parent类的超类型。

    这意味着正确的代码是:

    List<Parent> myList = new ArrayList<Parent>(); // Compiles fine

    但是以上内容与习惯于使用以下合法的传统Java程序员相矛盾。

    Parent[] myParentArray = new Child[10];

    要详细了解上述差异,让我们有一个如下的继承结构:

    public class Animal{}
    
    public class Cat extends Animal{}
    
    public class Dog extends Animal{}

    我们可以在数组中实现多态,因为不应将数组指定为安全类型。 请参见下面的数组示例,以及为什么我们需要将类型安全列表作为Collection对象。

    public void addAnimals(Animal[] animals ) {
     	animals [0] = new Animal();
    
                 // If passed animal[] is of type Dog[] then we are adding a Cat object to a Dog[] array.
     	animals [1] = new Cat();
    
                 // If passed animal[] is of type Cat[] then we are adding a Dog object to a cat[] array.
                 animals [1] = new Dog(); 
    }

    由于猫或狗是动物的类型,因此可以将猫阵列或狗阵列作为动物阵列进行传递。

    public class callerClass() {
                  Animal[] animalArray = new Animal[10];
                  Cat[] catArray = new Cat[10];
                  Dog[] dogArray = new Dog[10];
    
                 addAnimals(animalArray); //Expected, no questions raised here. 
     addAnimals(catArray); //As Cat[] is a type of Animal[] so we may end up in adding a Cat in Dog Array.                                                
                 addAnimals(dogArray); // As Dog[] is a type of Animal[] so if Cat[] is passed we may end up in adding a Dog in a //Cat array.
    }

    但是看看如果我们使用Collections会发生什么。 我们可以有类似上面的方法:

    public void addAnimals(List<Animal> myAnimalList()) {     //Some code here.  }

    调用上述方法的调用方方法如下所示。

    public class callerClass() {
                  List<Animal> animalList = new ArrayList<Animal>();
                  List<Cat> catList = new ArrayList<Cat>();
                  List<Dog> dogList = new ArrayList<Dog>();
    
                 addAnimals(animalList); 
                 addAnimals(catList);
                 addAnimals(dogList); 
    }

    如果我们尝试编译以上内容会发生什么? 它将在addAnimals(catList);行失败addAnimals(catList);addAnimals(dogList) ,因为List类型与addAnimals(List<Animal> myAnimalList())方法的预期列表类型不匹配。 该方法期望列表仅声明为动物类型。

    尽管上面的方法失败了,但是当列表被声明为超类型列表时,泛型实际上可以保留子类型的实例。 例如,我们可以像下面这样详细实现addAnimals( List<Animal> myAnimalList () myAnimalList List<Animal> myAnimalList () )方法。

    public void addAnimals(List<Animal> myAnimalList ()) {
               aList.add(new Animal()); // Expected code.
               aList.add(new Cat()); //Yes this works.
               aList.add(new Dog()); //Any Animal subtype works.
    }

    这意味着我们可以将子超类的继承概念应用于将对象添加到列表中,而不是将对象作为方法参数分配或传递。

    这就是为什么Java的阻止原因addAnimals(catList)代码进行编译,因为如果被在实施后编制然后addAnimals方法,我们总是可以有aList.add(new Dog())代码,即使ALIST是猫名单的类型,这是错误的! 我们不能将Dog对象添加到Cat列表中,因为该列表仅声明为具有Cat对象(或其子类)。 泛型可以使列表类型安全并且在技术上有意义。 为了接受多态子/超类,我们可以使用通配符来增强方法签名,这可以在另一个会话中进行讨论。

    翻译自: https://www.javacodegeeks.com/2015/03/polymorphism-in-java-generics.html

    java多态和泛型

    展开全文
  • Java多态主要分为三方面: 继承(类、对象) 重写(方法) 向上转型(父类引用指向子类对象) 注:重载多态没有半毛钱关系。 重载:在一个类中,方法名字相同,而参数不同、返回类型可同可不同,调用者根据...

    多态和泛型

    多态

    Java多态主要分为三方面:

    继承(类、对象)

    重写(方法)

    向上转型(父类引用指向子类对象)

    注:重载和多态没有半毛钱关系。

        重载:在一个类中,方法名字相同,而参数不同、返回类型可同可不同,调用者根据参数列表的不同自动调用不同的方法。

    重载方法必须保证参数列表的不同。

    最常见的重载为构造器的重载。

     

    泛型

    重载只能在方法中,要求每个方法的参数列表不同,不同的参数列表实际上调用的是不同的方法体。实际上一个方法还是只能使用一个类型(基本类型或自定义类型)的参数。

    泛型使得同一个类、接口或者方法,在不同的情况下能够接收不同类型的参数,让同一个类和方法能够使用不同类型的参数,至于究竟是什么类型,由用户的传入来决定。

        我的理解,泛型就是在定义类和方法要使用的数据时,使用一个符号来表示具体类型不确定,这个符号可以应用传入的各种类型,从而让这个类和方法适用于多种类型,拥有模板的功能。

        主要有泛型类、泛型接口、泛型方法。

     

    泛型类

    class A<T>{

        T key;//key这个成员变量的类型为T,T的类型由外部指定

        public A(T key) {//泛型构造方法形参key的类型也为T,T的类型由外部指定

            this.key = key;

        }

        public T getKey(){//泛型类中的方法的返回值类型为T,T的类型由外部指定

            return key;

        }

    }

    泛型类和普通类的区别在于,泛型类中成员变量、方法使用的类型不是确定的类型。

    在实例化泛型类(使用泛型类创建对象)时,必须指定T的具体类型。

    泛型指定的类型只能是包装类,不能是基本类型。

     

    泛型接口

    interface A<T>{

        public T next();

    }

    class B implements A<Integer>{

        @Override

        public Integer next() {

        }

    }

    class B<T> implements A<T>{

        @Override

        public T next() {

        }

    }

    泛型接口的定义和泛型类一样。

    在实现泛型接口的时候,可以将泛型指定为具体的类型,也可以继续保留泛型不传入泛型实参。

    如果不传入泛型实参,声明类的时候也必须声明泛型。

     

    泛型通配符

        Integer 是Number的一个子类,但是在使用Number作为形参的方法中,并不能传入Integer的实例。也就是说,有继承关系的类之间,父类作为形参的方法并不能接收子类。

    如果需要一种可以表示同时是父类和子类的引用类型,用泛型通配符来表示。

    public void showA(A<Number> obj){

    }

    A<Integer> a1=new A<>(123);//报错,不兼容

    A<Number> a2=new A<>(123);

     

    public void showA(A<?> obj){ //可以兼容

    }

     

    泛型方法

    class A<T>{

        T key;//key这个成员变量的类型为T,T的类型由外部指定

        public A(T key) {//泛型构造方法形参key的类型也为T,T的类型由外部指定

            this.key = key;

        }

        public T getKey(){//1.这是泛型类中的方法,但不是泛型方法

            return key;

        }

    }

     

    //2.这也不是泛型方法,他使用泛型类A作为参数列表

    public void showA(A<Number> obj){

    }

    public void showA(A<?> obj){

    }

     

    //2.这才是泛型方法,标志是public 之后的<T>

    //T表示的泛型作为返回值类型,A<T>表示以泛型类A作为参数

    public <T> T showA(A<T> a){

    }

     

    泛型方法与可变参数

    public <T> void print( T... args){

        for(T t : args){

            Log.d(t);

        }

    }

        上述方法中,不管传入多少个参数,也不管参数是什么类型,都能打印出来。

    泛型擦除

    Java的泛型是伪泛型,编译过程中,所有的泛型信息都会被擦除,实际运行的代码中并没有泛型。

    ArrayList<String> list1 = new ArrayList<String>();

    list1.add("abc");

     

    ArrayList<Integer> list2 = new ArrayList<Integer>();

    list2.add(123);

     

    System.out.println(list1.getClass() == list2.getClass());

    //true,两个类型都是list

    上述代码表明:List<Integer>和List<String>两个泛型类型,在编译后都是List,JVM只能看到List,看不到泛型附加的类型信息。

     

    ArrayList<Integer> list = new ArrayList<Integer>();

     

    list.add(1);  //直接调用 add方法只能存储整形,因为泛型类型的实例为Integer

     

    //通过反射,可以使得List能够存储String类型,再一次表明JVM看不到附加信息,在编译时,泛型擦除了,只保留了原始类型

    list.getClass().getMethod("add", Object.class).invoke(list, "asd");

     

    for (int i = 0; i < list.size(); i++){

        System.out.println(list.get(i));

    }

     

    泛型擦除后保留原始类型,不限定类型的泛型类编译后,T会被替换成Object;使用T extend XX限定类型的泛型编译后,T会被替换成XX。也就是说,在不限定类型的泛型类中,泛型的原始类型是Object,在限定类型为XX的泛型类中中,原始类型是XX。

    展开全文
  • Java基础之多态和泛型浅析一、前言:楼主看了许多资料后,算是对多态和泛型有了一些浅显的理解,这里做一简单总结二、什么是多态多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口(这里...

    Java基础之多态和泛型浅析

    一、前言:

    楼主看了许多资料后,算是对多态和泛型有了一些浅显的理解,这里做一简单总结

    二、什么是多态?

    多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口(这里所谓的接口是楼主自己发明的,这里不是局限于Java的interface,可以把它看作为广义定义的对象源)的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在Object Pascal和C++中都是通过虚函数实现的。但是在Java中楼主认为基于类之间的继承关系

    多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。C++中的多态性具体体现在运行和编译两个方面。运行时多态是动态多态,其具体引用的对象在运行时才能确定。编译时多态是静态多态,在编译时就可以确定对象使用的形式。

    简单的来说多态就是同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

    把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

    赋值之后,父类型的引用就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。

    举个例子:从一个基类中派生,响应一个虚命令,产生不同的结果。

    比如从某个基类派生出多个子类,其基类有一个虚方法Tdoit,然后其子类也有这个方法,但行为不同,然后这些子类对象中的任何一个可以赋给其基类对象的引用,或者说将子对象地址赋给基类指针,这样其基类的对象就可以执行不同的操作了。实际上你是在通过其基类的引用来访问其子类对象的,你要做的就是一个赋值操作。

    使用继承性的结果就是当创建了一个类的家族,在认识这个类的家族时,就是把子类的对象当作基类的对象,这种认识又叫作upcasting(向上转型)。这样认识的重要性在于:我们可以只针对基类写出一段程序,但它可以适应于这个类的家族,因为编译器会自动找出合适的对象来执行操作。这种现象又称为多态性。而实现多态性的手段又叫称动态绑定(dynamic binding)。

    简单的说,建立一个父类对象的引用,它所指对象可以是这个父类的对象,也可以是它的子类的对象。java中当子类拥有和父类同样的函数,当通过这个父类对象的引用调用这个函数的时候,调用到的是子类中的函数。

    多态,意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。

    多态所展示的特性示例:

    Parent pa = new Child_A();

    pa.simpleCall()则显然是调用Child_A的方法;

    Parent pa = new Child_B();

    pa.simpleCall()则是在调用Child_B的方法。所以,我们对于抽象的父类或者接口给出了我们的具体实现后,pa 可以完全不用管实现的细节,只访问我们定义的方法,就可以了。事实上,这就是多态所起的作用,可以实现控制反转。这在大量的J2EE轻量级框架中被用到,比如Spring的依赖注入机制。

    三、什么是泛型?

    一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类。如果要编写可以应用多种类型的代码,这种刻板的限制对代码的约束就会很大。

    在面向对象编程语言中,上面介绍的多态是一种泛化机制。例如,你可以将方法的参数类型设为基类,那么,该方法就可以接受从这个基类中导出的任何类作为参数。这样的方法更加通用一些。可应用的地方也多一些。在类的内部也是如此,凡是需要说明类型的地方,如果都使用基类,确实能够具备很好的灵活性。但是如果考虑除了final类(不能扩展),其他任何类都可以被扩展,所以这种灵活性大多数也会有一些性能损耗。

    有时候,拘泥于单继承体系,也会使程序受限太多。如果方法的参数是一个接口,而不是一个类,这种限制就放松了许多。因为任何实现了该接口的都能够满足该方法,这也包括暂时还不存在的类

    在Java5之后,引入了泛型这个概念:泛型实现了参数化类型的概念,使代码可以应用于多种类型,泛型这个概念的术语是:“适用于许多许多的类型”。泛型通过解耦类或方法所使用的类型之间的约束。使类或方法具备最广泛的表达能力

    为什么要使用泛型?

    在Java5之前,泛型程序设计是用继承实现的。例如ArrayList类只维护一个Object引用的数组:

    //before generic classes

    public class ArrayList {

    private Object[] elementData;

    ...............

    public Object get(int i) {.......}

    public void add(Object object) {.........}

    }

    这种方法有两个问题,当获取一个值时必须进行强制类型转换

    ArrayList files = new ArrayList();

    .......................

    String fileName = (String)files.get(0);

    此外,这里没有错误检查。可以向数组列表中添加任何类的对象。

    files.add(new File("......"));

    对于这个调用,编译和运行都不会出错。然而在其他地方,如果将get的结果强制类型转换为String类型,就会产生一个错误。泛型提供了一个更好的解决方案:

    Java5以后,ArrayList有一个类型参数来指定元素的类型:

    ArrayList files = new ArrayList();(在Java7及以后的版本中,构造函数中可以省略泛型类型:ArrayList files = new ArrayList<>();)

    这显然使得代码具有更好的可读性。人们一看这个数组列表中包含的是String对象。

    三、多态与泛型的区别:

    其实多态和泛型也没有什么根本的区别,如果非要说说区别,那就说说吧:

    泛型和多态比较容易混淆, 简单来说:泛型就是类型参数化, 好处是编译器会检查参数类型.多态就是多个类由继承(实现接口)得到的一致外观, 好处是简化代码, 隔绝修改实际上泛型和多态没有直接关系, 使用泛型在代码中就能按照指定类型的外观操作对象.

    比较常用的泛型类型就是List和Map, 说个简单的例子吧:

    List list = ....; //具体类型, 就跟多态没什么关系了

    for (String str : list) {

    System.out.println(str.substring(1));

    }

    List list = ...; //地球上但凡讲OO的都拿这个说事儿... 成员就是小猫小狗狮子老虎什么的

    for (Animal animal : list) {

    animal.say(); //喵, 汪....., 多态

    }

    多态可以分为编译时多态和运行时多态,泛型是对类型的抽象,属于编译时多态。

    比如说下面的私有字段x, 它的数据类型在编译的时候是动态决定的,具有多态性。

    class A{ private T x;} A a = new A();

    多态还可以分为:行为多态和属性多态。

    下面的p在给它赋值前是不知道它的性别的,在给它赋不同的值的时候就表现出属性多态了。

    与此同时,也具有了行为的多态, Walk().男人和女人走路的方式是不一样的,所以是多态了。

    基类: Class Person, public virtual method Walk() {}

    子类: Man, Woman

    Person p = new Man();

    Person p = new Woman();

    转载请注明出处,谢谢!

    展开全文
  • 一、接口二、多态多态是同一个行为具有多个不同表现形式或形态的能力。2.1 类型转换转换方式隐式 向上转型对于基本数据类型,存储容量低的可自动向存储容量高的类型转换对于引用变量,子类可被转换为超类,可被赋给...
  • 在面向对象的Collection中处处体现泛型和多态的思想,且慢,由于泛型和多态两者之间本身就有一定的相似性,让我们先认清楚泛型和多态之后再进入话题。多态是面向对象最基本的概念之一,即要模糊父类和之类之间的区别...
  • (一)多态 1.概念 简单理解就是,一个对象可以表现出多种状态。可以看做是对抽象对象的逆过程,具体化抽象对象的行为。而它是如何实现这种表现出多种状态功能的呢。 从Java语法上来讲有如下两种方式: 1.1 使用继承...
  • Java多态泛型

    2020-02-17 12:09:22
    Java泛型的理解: Class<? extends Object>是什么意思? <T>是定义一个泛型 T是让方法返回的类型是之前定义的泛型的类型 Class<? extends T> 这个是定义参数的类型为Class, 但是这个Class...
  • 多态 & java泛型

    2021-12-10 00:21:43
    统一与差异)2)接口抽象类的比较(同: 抽象方法、继承,异: 多态实现)2、泛型的本质 & 作用1)泛型的本质 - 类型参数化2)泛型的作用3、泛型的使用1)jdk中常见的泛型2)自定义泛型方法(利用反射调用共有...
  • java 多态泛型实现

    2010-10-30 16:30:38
    RTRTRTRTRT 多态泛型实现 急需积分...
  • JAVA 多态 异常 泛型

    2021-05-24 00:25:06
    JAVA 多态 异常 泛型多态 多态 多态性是指同一个操作作用于某一类对象,可以有不同的解释,产生不同的执行结果
  • 多态泛型

    千次阅读 2016-04-01 15:52:10
    1.多态的理解使用: 多态自我理解就是同种调用的不同结果表现 1) 方法的多态性:包括重载重写(其实重写就是为了下面类之间继承的多态) 2)类之间继承的多态 重载重写已经在之前的文章中学习过了,下面是类的...
  • Java多态遇到泛型类型

    2017-12-05 09:23:20
    1.数组参数的多态化 class Animal { void eat() { System.out.println("animal is sleeping"); } } class Dog extends Animal { void bark() { System.out.println("dog is barking"); } } class Cat ...
  • 其实问题归根结底还是因为泛型和多态绕在一起后形成的复杂度。我们先来考虑一下,什么样的重写才是正确且不会出现类型问题的: 1.函数标识符应该完全。 1.函数参数应该是完全相同的,不能允许任何的协变或逆变...
  • 多态 面向对象三大特性: 继承, 封装, 多态 定义 多态: 是指同一行为,对于不同的对象具有多个不同表现形式。 程序中多态: 是指同一方法,对于不同的对象具有不同的实现 ...多态的好处弊端 好处 提

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,471
精华内容 12,588
关键字:

java多态和泛型

java 订阅