你真的理解了继承和多态吗?

本文通过实例解析Java中多态的实现机制,重点探讨对象字段与方法在继承过程中的表现差异,揭示字段与方法在继承与多态中的不同行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


最近被同事问起一道SCJP的题目,是跟继承和多态有关的。具体的题目我就不重复了,来看一段我自己敲的代码:
 1 package sean.work.test;
 2
 3 public   class  DoYouReallyUnderstandPolymorphism  {
 4    
 5    public static void main(String[] args) {
 6        A a = new A();
 7        B b = new B();
 8        a.s = "[AA]";
 9        b.s = "[BB]";
10        System.out.println(a.s);      // prints "[AA]"
11        System.out.println(b.s);      // prints "[BB]"
12        System.out.println(a.getS()); // prints "[AA]"
13        System.out.println(b.getS()); // prints "[BB]"
14        System.out.println("====================");
15        a = b; // a now refers to object b
16        System.out.println(a.s);      // prints "[A]"  <<--1-- the class A copy
17        System.out.println(b.s);      // prints "[BB]"
18        System.out.println(a.getS()); // prints "[BB]"
19        System.out.println(b.getS()); // prints "[BB]"
20        System.out.println("====================");
21        ((A)b).s = "[AA]"// <<--2-- changes the class A copy in object b 
22        System.out.println(a.s);      // prints "[AA]" <<--3-- class A copy changed
23        System.out.println(b.s);      // prints "[BB]"
24        System.out.println(a.getS()); // prints "[BB]"
25        System.out.println(b.getS()); // prints "[BB]"
26    }

27
28}

29
30 class  A  {
31    String s = "[A]";
32    String getS() {
33        return s;
34    }

35}

36
37 class  B extends A {
38    String s = "[B]";
39    String getS() {
40        return s;
41    }

42}

43

这里我们的B类继承自A类,重写了getS()方法,于是我们可以利用到多态。如果你留意15、16、21、22这几行的话,你也许就会知道我在说什么了。假如你觉得这样的打印结果是理所当然,那么我想你可以完全忽略这篇随笔,因为我要讲的就集中在这几行,而你已经很清楚的理解背后的含义。

下面跟感兴趣的朋友们说说我的理解:

直观的讲,我们很容易轻信当"a = b;"以后,变量a指向的对象是B类的b那个对象,自然a.s就应该等同于b.s,然而事实并非如此。当B继承A时,父类A的字段s并没有被B的字段s取代,而是保留了一份拷贝,所谓重写(Override),那是对方法而言的。于是,当我们new B()时,在实际创建的对象中,包含了两个版本的字段s,一个"[A]"(属于A类)一个"[B]"(属于B类)。而方法getS()只有一个版本。这就是在继承过程中字段和方法的区别。也就是说,重写的概念和字段无关。在第16行,我们通过a.s访问的是b这个对象中保留的A类的字段s;而在21行,我们改变的正是这个A类版本的s字段。

多态的精髓在于动态确定对象的行为,而对象的行为体现在方法而非字段,字段代表的更多的是对象的状态。于是只有方法的多态而没有字段的多态。从上面的代码可以看出,不管你用什么类型的变量存放对象b的引用,最终调用的方法版本都是b的真实类型那个版本,这就是多态的威力。

从编译的角度来看,上面代码中的s字段和getS()方法的不同在于:s字段是在编译期静态链接(你可以改变它的值,但是它在对象中的相对地址已经确定好),而getS()方法是在运行期动态链接的。

说了这么多,真的不知道我表达清楚没有,毕竟没有系统研究过OO和编译原理,说得不当的地方还请多多包涵。最后,请不要学我这里的编码风格,因为很显然应该对main方法中的代码段执行Extract Method重构了,我这里只是为了注释方便。
参考资源链接:[Python面向对象编程:类与对象详解](https://wenku.youkuaiyun.com/doc/6dtngs1mba?utm_source=wenku_answer2doc_content) 在Python中实现面向对象编程的封装、继承多态,首先需要理解这三个概念的基础含义。封装是将数据操作数据的函数绑定在一起形成对象,从而隐藏对象的内部实现细节,只暴露必要的接口。继承是子类继承父类的特性,允许复用扩展功能。多态是指不同对象对同一消息作出不同响应的能力。以下是如何在Python中实现这些特性的示例: 1. 封装: 封装可以通过定义私有属性提供公共方法来实现。私有属性通过在属性名前加上双下划线`__`来创建,例如`__private_attribute`。公共方法则允许外部访问修改这些私有属性,但只能通过方法来间接操作。 ```python class Animal: def __init__(self, kind, voice): self.__kind = kind self.__voice = voice def speak(self): return f'{self.__kind} says {self.__voice}' def get_kind(self): return self.__kind def set_kind(self, kind): self.__kind = kind ``` 在这个例子中,`kind``voice`被封装在`Animal`类内部,外部代码不能直接访问它们,但可以通过`speak`方法来“询问”动物的叫声,或者通过`get_kind``set_kind`方法来获取设置动物的种类。 2. 继承继承通过在类定义时指定父类来实现。子类继承父类的所有属性方法,可以通过重写方法来扩展或修改继承的行为。 ```python class Cat(Animal): def __init__(self, voice): super().__init__('Cat', voice) def speak(self): return 'Meow! ' + super().speak() ``` 在这里,`Cat`类继承了`Animal`类,并重写了`speak`方法,添加了新的行为。使用`super()`可以调用父类的方法。 3. 多态多态是指不同对象对同一消息可以有不同的实现方式。在Python中,由于动态类型系统的特性,多态通常是通过接口(如抽象类方法)来实现的。这里我们使用普通类方法来展示多态的实现。 ```python def animal_sound(animal): print(animal.speak()) dog = Animal('Dog', 'Bark') animal_sound(dog) # 输出: Dog says Bark animal_sound(Cat('Purr')) # 输出: Meow! Cat says Purr ``` 在这个例子中,`animal_sound`函数接受任何继承自`Animal`类的对象作为参数,并调用其`speak`方法。由于`Cat`类重写了`speak`方法,函数能够根据传入对象的不同展示不同的行为,体现了多态的特性。 学习如何在Python中实现面向对象编程的三大特性,推荐参考《Python面向对象编程:类与对象详解》。这份资料详细解释了类的定义、对象的创建以及如何使用面向对象的设计原则来编写清晰、可维护的代码。通过阅读实践,你将能够更加深入地理解封装、继承多态,并能够将这些概念应用到实际的编程工作中。 参考资源链接:[Python面向对象编程:类与对象详解](https://wenku.youkuaiyun.com/doc/6dtngs1mba?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值