1、定义:在程序中定义的某个引用变量具体所指向的类型和调用的方法在编码时并不能确定,而只有在运行的时候才能确定。
2、简单理解:你定义的引用变量是父类型,而你创建的对象是子类型,用这个父类型的引用变量指向这个子类型的对象,然后当你调用这个对象的方法的时候,具体是调用的父类的还是子类的方法只有在运行的时候才能确定,可能调用的是父类的方法也有可能调用的子类的方法,这样不用修改代码,就可以让成徐选择多个运行的状态,这就是多态。
3、要点:
1)多态的三大必要条件:继承、覆写、父类引用指向子类对象。
2)父类的实例方法可以被覆盖,属性不能被覆盖。
3)父类的引用可以访问父类的所有属性和方法,可以访问子类覆盖的方法(引用指向子类对象的话),但不能访问子类的属性(属性不能被覆盖),及子类新添加的方法。
4)父类引用会调用子类覆盖的方法即动态绑定,指定是程序在执行时(非编译期间)会判断引用对象的实际类型,并调用其相应的方法。
4、关于在集合中使用泛型及多态的问题
先看下以下代码能否通过编译?
实例一:
package com.linwei; import java.util.ArrayList; import java.util.List; abstract class Animal { public void eat(){ System.out.println("animal eating"); } } class Dog extends Animal{ public void bark(){ System.out.println("dog barking"); } } class Cat extends Animal{ public void meow(){ System.out.println("cat meowing"); } } public class TestDuotai { public void showAnimals(List<Animal> animals ){ //animals.add(new Cat()); for(Animal a : animals){ a.eat(); } } public static void main(String[] args) { ArrayList<Dog> dogs=new ArrayList<Dog>(); dogs.add(new Dog()); dogs.add(new Dog()); dogs.add(new Dog()); new TestDuotai().showAnimals(dogs); } }
答:不能编译通过。
问题出在该方法:showAnimals(List<Animal> animals )。该方法接受的是Animal类型的集合,按照多态的概念来说,Dog类是Animal类的子类,传入Dog类型的集合应该是没问题的,但为什么不能编译通过呢?
原因(反证法验证):
1)假设能够编译通过,则说明在一个需要List<Animal> 的地方可以传入ArrayList<Dog>对象,不过如果继续往方法的内部思考,就会存在问题。
2)见showAnimals(List<Animal> animals )方法内部的注释行://animals.add(new Cat()),假设把注释去掉,则由于Cat类也是Animal类的子类,所以该行代码也是完全没有问题的。
3)但回到方法的调用处:new TestDuotai().showAnimals(dogs),我们就会发现实际上我们传入showAnimals(List<Animal> animals )方法的是Dog类型的集合,但如果在方法中执行到animals.add(new Cat())代码时,意思是要往ArrayList<Dog>中传入一个Cat类型的对象,如此一来就涉及到了泛型安全性的问题,此时就不能通过编译器的编译(集合泛型类型的检查发生在编译期,而数组类型的检查则在运行期)。
4)结论:你不能向一个参数类型为ArrayList<Animal>的方法中传递ArrayList<Dog>类型的对象。
5) 关于以上第4)点的补充实例,代码如下所示。
package com.linwei; import java.util.ArrayList; import java.util.List; abstract class Animal { public void eat(){ System.out.println("animal eating"); } } class Dog extends Animal{ public void bark(){ System.out.println("dog barking"); } } class Cat extends Animal{ public void meow(){ System.out.println("cat meowing"); } } public class TestDuotai { public void showAnimals(List<Animal> animals ){ for(Animal a : animals){ a.eat(); } } public static void main(String[] args) { ArrayList<Dog> dogs1=new ArrayList<Animal>(); //不能编译通过 ArrayList<Animal> animals1=new ArrayList<Dog>(); //不能编译通过 List<Animal> list=new ArrayList<Animal>(); ArrayList<Dog> dogs=new ArrayList<Dog>(); ArrayList<Animal> animals = dogs; //不能编译通过 List<Dog> dogList=dogs; ArrayList<Object> objects=new ArrayList<Object>(); List<Object> objectList=objects; ArrayList<Object> objs=new ArrayList<Dog>(); //不能编译通过 } }
相关推荐
在面向对象编程中,“父类引用指向子类对象”是一个重要的概念,尤其在Java等支持继承的语言中应用广泛。这一机制允许使用父类类型的引用变量来引用子类的对象,从而实现多态性。 #### 基本原理 在面向对象编程...
多态操作允许我们在编程中使用父类类型的引用来指向子类类型的对象,这种机制使得我们可以编写更加灵活和通用的代码。 在 Java 中,每个子类对象都是父类对象的实例,因此可以将子类对象赋值给父类变量。但是,反之...
4. **类型转换**:虽然父类引用可以指向子类对象,但反过来不行,即子类引用不能直接指向父类对象。若要从父类引用转回子类引用,需要进行类型转换(downcasting),如`Dog dog = (Dog) animal;`,但需要注意,只有...
- **运行时类型判断**:多态性是在运行时决定的,即父类引用变量实际指向的是哪个子类的对象。 ### 二、对象上下转型 1. **向上转型**:子类对象被赋值给父类引用,这是安全的,因为所有子类都具备父类的属性和...
在Java编程中,"父类引用指向子类对象"是一种常见的多态性表现形式,它体现了面向对象设计的核心原则之一。这种技术允许我们通过父类的引用或接口来调用子类的方法,从而实现了代码的灵活性和可扩展性。下面我们将...
这意味着,我们可以使用父类的引用来指向子类的对象,从而实现多态。例如,在上面的示例代码中,我们使用了父类`Animal`的引用来指向子类`Cat`、`Dog`和`Pig`的对象。 二、多态的前提 多态的前提是类与类之间的...
多态性是指父类引用指向子类对象,例如父类Animal,子类Cat和Dog。其中Animal可以是类也可以是接口,Cat和Dog是继承或实现Animal的子类。Animal animal = new Cat();即声明的是父类,实际指向的是子类的一个对象。 ...
在Java中,我们可以通过父类的引用变量来指向子类的对象,这种现象被称为“向上转型”(Upcasting)。例如: ```java class Animal {} // 父类 class Cat extends Animal {} // 子类 public class Test { public ...
Java多态是面向对象编程中的一个核心概念,它允许我们使用父类的引用指向子类的对象,从而实现更灵活的代码编写。在这个“java多态实验”中,我们可以看到一系列小代码实例,这些实例旨在帮助理解和应用多态特性。...
这意味着即使父类引用指向子类对象,调用的方法也是子类重写后的版本,这就是多态的核心机制。 总结起来,多态在Java中起着至关重要的作用,它允许我们编写更加通用和灵活的代码,使得程序能够适应不断变化的需求和...
Java多态是面向对象编程中的一个核心特性,它允许我们以一种统一的方式处理不同类型的对象。在Java中,多态性主要通过继承、接口和方法重写(Override)来实现。这里我们将深入探讨从虚拟机(JVM)的角度来看,Java...
父类引用指向子类对象时,没法调用子类特有的方法; 父类引用指向子类对象: java中子类强转父类,实际上依然是子类; 该引用只能调用父类中定义的方法和变量; 如果子类中重写了父类中的一个方法,那么在...
这主要通过继承、重写以及父类引用指向子类对象的方式来实现。 1. **继承**: 在Java中,多态的基础是继承。子类继承父类,从而获取了父类的属性和方法。这样,子类不仅拥有自己的特性,还能共享父类的功能,增加...
在Java中,当一个父类引用指向子类对象时,调用的方法会根据实际对象的类型进行动态绑定,也就是所谓的晚期绑定(Late Binding)或动态分派。 - 实现多态的关键在于继承和方法重写。子类继承父类后,可以重写父类中...
运行时多态则基于方法的重写(Overriding),子类可以重写父类的方法,当使用父类引用指向子类对象时,如果调用了被重写的方法,那么在运行时会根据实际的对象类型来执行子类的方法,这就是动态绑定。 理解多态的...
多态的发生前提是:必须有继承或实现关系、有方法的重写、父类引用指向子类的对象。在 Java 中,我们可以使用 final 关键字来修饰方法、类和变量,final 修饰的方法不能被子类重写,final 修饰的类不能被继承。 在 ...
在Java中,多态的实现基于继承、方法重写以及父类引用指向子类对象。 1.1 多态的概述 多态(Polymorphism)是指同一个对象在不同的情况下表现出不同的行为特性。在Java中,多态的实现有以下前提条件: - 继承关系...
通过父类引用指向子类对象,我们可以看到多态的效果。具体的实现细节可以通过查看这个文件来学习。 总之,多态是Java编程中不可或缺的一部分,它使得代码更具有灵活性和可扩展性。理解和掌握多态的原理与应用,对于...
在Java面向对象编程中,多态性是核心概念之一,它允许我们使用父类引用指向子类对象,从而实现更灵活的设计。在这个“Java面向对象程序设计-父类作为返回值实现多态”的主题中,我们将深入探讨如何利用这一特性来...
文章围绕子类继承父类成员的过程、成员变量及方法的赋值、重写、覆盖等问题展开讨论,旨在帮助读者更好地理解Java继承中的重点与难点。 #### 关键词 - 继承机制 - 父类 - 子类 #### 一、超类的属性或方法在继承...