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

Python学习之-继承多态 什么是继承?什么是多态?面向对象的三大特性:封装:根据 职责 将属性方法封装到一个抽象类中继承: 实现代码的重用,相同的代码不需要重复的编写多态: 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度继承继承是一种机制,它使得一个类(称为子类或派生类)能够继承另一个类(称为父类或基类)的属性行为(方法)。子类除了可以继承父类的功能外,还可以添加新的功能或重写某些功能。单继承: 当一个类仅继承自一个父类时。多继承: 当一个类继承自多个父类时。 阅读详情
最近被同事问起一道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重构了,我这里只是为了注释方便。

// BTW,时不时抽空想想这样的问题感觉真不错。

Feedback

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2005-06-07 16:26 by 小毅
谢谢您,学到很容易忽略的东西,觉得很重要
再谢谢你...

# 原来字段和方法有这样的区别哦  回复  更多评论   

2005-06-08 09:02 by emu
>>只有方法的多态而没有字段的多态

以前都没有想过这个问题哦。

前两天遇到一个内嵌类的方法重载时候的古怪问题,不知是否与此有关,正好回头去研究一下。

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2005-06-08 12:16 by FS
Java的对象模型偶不太清楚,不过通过对Delphi的对象模型的了解,我感觉应该和Java没有太大的区别。

按照楼主所说的,当执行了语句“a=b”后,变量a和b的内容应该是不变的,所变的是a指向的对象实体中的指向类的指针的内容,在Delphi中,这个指针叫做vptr,CPP中也是如此叫法。vptr直接指到类的VMT(不知道Java中如何叫法);因此,再次使用a.s访问实例变量,则要进入b指向的对象实体中进行字段的查找,但由于b里面存在两个s字段,并且以类型信息为区分方式,所以找到的是类型A的字段s。至于编译处理方面,我想应该是把类型信息作为字段的前缀或者后缀。

同样,当执行了“((A)b).s=“[AA]””后,由于已经把b的类型转化为A类型,而且b指针的未改变,所以在b的对象实体中,实际改变的是属于类型A的字段s的内容。个人感觉,其实楼主已经说出了,对b中不同类型的同名字段的访问方式。

最后留下一个问题:这种对象模型中的字段处理方式如果在继承字段访问量小的情况下是很浪费空间的。那么,这样处理的优点又是什么?

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2005-06-08 12:18 by FS
按照OO这种东西在语言设计上的考虑,对象所涉及到的所有内容就是三块:对象指针,对象实体和对象所属类型的内存布局。而对象实体中只存放状态信息,即对象所属类型的实例字段的内容,因此,从这个角度考虑,多态和实例字段的信息是没有任何关系的。但对于类字段,即申明为static的字段就未必了。

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2005-07-20 23:24 by 丑男
System.out.println(a.s); // prints "[A]"
这句确实我没想到!看来真被难倒了

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2006-05-15 17:30 by songxu
非常感谢

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2006-07-15 17:22 by tcpipok
我是想到了,不过就像楼主所说的,这种编码风格不好,子类尽量不要用父类用过的变量名,真的是容易搞混,这种代码用来考试可以,但用来编程不好.

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2006-08-17 20:34 by 小小
请问:
java中字符串的连接是不是一种多态的表现?

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2007-03-05 22:52 by 谷钰
@tcpipok
我不知道你是否理解OO真正的精髓,以上用法展示了面向对象设计的核心思想,通过虚方法调用,实现不同子类对同一行为(方法)的不同实现。希望以下例子可以给大家一些启发:

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2007-03-05 23:05 by 谷钰
public class Employee {

protected String name = "张三";

private double salary = 1000;

public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}

public Employee() {
this("王老五", 1);
}

public String getDetails() {
return "姓名:" + this.name + ", 工资: " + this.salary;
}

public double getSalary() {
return this.salary;
}

public void setSalary(double salary) {
this.salary = salary;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public boolean equals(Object o) {
if (this == o) {
return true;
}

if (o instanceof Employee) {
Employee te = (Employee) o;

return this.salary == te.getSalary() && this.name.equals(te.getName());
}

return false;
}

public int hashCode() {
if (this.name == null) {
return 0;
}
return this.name.hashCode();
}

public String toString() {
return "$$" + this.getDetails();
// return super.toString();
}

public static void printAll(Employee[] all) {
System.out.println("所有员工:");
for (int i = 0; i < all.length; ++i) {
System.out.println(all[i].getDetails());
}
}

public static void main(String[] args) {
Employee e = new Employee("张三", 2500);
System.out.println(e.getDetails());

Manager m = new Manager("李四", 4500, "软件开发部");
System.out.println(m.getDetails());

Employee ee = new Manager("王五", 4500, "软件销售部");
System.out.println(ee.getDetails());

if (ee instanceof Manager) {
Manager mmm = (Manager) ee;
System.out.println(mmm.getDepartment());
}

Employee e2 = new Employee("张三", 2500);
System.out.println(e.equals(e2));

System.out.println(e);
System.out.println("##" + e);

Employee[] eAll = {
e, m, ee
};
printAll(eAll);
}
}

class Manager extends Employee {
private String department = "44";

public Manager() {
super();
this.department = "计算机";
}

public Manager(String name, double salary, String department) {
super(name, salary);

this.department = department;
}

public String getDetails() {
return super.getDetails() + ", 管理部门: " + this.department;
}

public String getDepartment() {
return this.department;
}
}

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2007-03-05 23:11 by 谷钰
核心在
public static void printAll(Employee[] all) {
System.out.println("所有员工:");
for (int i = 0; i < all.length; ++i) {
System.out.println(all[i].getDetails());
}
}
函数的设计上,通过Employee隐藏所有雇员子类的细节,通过getDetails()方法来隐藏不同雇员(Manger,Engineer等)对详细信息的函数细节。

只有这样的函数才能最大程度上复用,既当设计有新的Employee子类定义也不许要对此函数做任何的修改,个人认为面向对象的最大好处是提高程序的复用性,降低维护成本。这些需要多态,继承才能作到。:)

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2007-03-06 09:38 by 大胃
谢谢 谷钰 的回复!

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2008-05-21 17:06 by tonytang
to 谷钰,你的代码也没有回答tcpipok的疑问啊。子类和父类定义相同的属性有意义吗?

# re: 你真的理解了继承和多态吗?  回复  更多评论   

2008-06-25 11:00 by shell
写的太好了。
学习了很多。


from:http://www.blogjava.net/sean/archive/2005/06/07/5666.html
1.30 Cubemx_STM32H743 SD_Card纳入文件管理系统 Cubemx_STM32H743 SD_Card纳入文件管理系统1、简介2、CubeMX配置 1、简介 前面文章原理其实一样的。 1.29 Cubemx_STM32F429\H743 nandflash、spifalsh纳入文件管理系统 现在一并将SD卡、NandFlash、SPIFlash一并作为文件管理。 下面直接介绍SDcard,其他参考前面文章。 2、CubeMX配置 ... 阅读详情

相关推荐

静态代码审计插件 snyk 使用教程

静态代码审计插件 snyk 使用教程

SHELLCODE_8BIT的博客 1946

继承多态

一.概述 面向对象程序设计的三大原则是封装性,继承多态性。继承性是子类自动共享父类的数据方法的机制,它是由类的派生功能体现的。继承具有传递性,使得一个类可以继承另一个类的属性方法,这样通过抽象出共同的属性方法组件新的类,便于代码的重用。而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消息主要是对类成员函数的调用,而不同的行为是指类成员函数的不同实现。当对象接收到发送给它的消息时,根据该对象所属的类,动态选用在该类中定义的实现算法。 二.继承 2.1 继承的概述 ...

Lucky_mzc的博客 1万+

nerfstudio nerfacto 默认数据集poster

利用nerfstudio 构建自己的nerf模型,数据集poster

继承多态

继承的引出 “IS-A”关系【表示了一种继承关系】 相当于,苹果是一种水果,梨是一种梨;苹果是一种水果:苹果具有水果共同有的特点,同时兼有苹果所特有的特点。 “HAS-A”关系:【描述了一种聚集关系(组成关系)】 继承的基本概念 作为基础的类(已知的类)-- 基类,又称父类(Base class) 由基类经扩充修改形成的新类-- 派生类,又称为子类(Derived class) C++的继承形式 C++继承形式主要有单重继承、多重继承等两种 单继承的定义方法 单继...

Galaxy_Su的博客 977

孙Cloud的Java学习博客-10.5-final关键字与内部类

- final概念及四种用法 final关键字有四种用法,即可以修饰一个类,一个方法,一个局部变量,一个成员变量 1.当他用于修饰一个类时,public final 类名称{//......} 含义为:这个类不能有任何子类(太监类) 注意:一个类如果是final的,那么其中所有成员方法都无法覆盖重写 2.用于修饰成员方法,那么这个方法就是最终方法,也就是不能覆盖重写 注意:对于类,方法来说abstract关键字与final关键字不能同时使用,因为矛盾 3.用于修饰局部变量,一旦赋值,终生不变(唯一一次

weixin_44719191的博客 310

真的理解继承多态

[code="java"] public class DoYouReallyUnderstandPolymorphism { public static void main(String[] args) { A a = new A(); B b = new B(); a.s = "[AA]"; b...

douhaouag的专栏 204

如何理解封装、继承多态

封装:  封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。被封装的对象通常被称为抽象数据类型。   封装的意义:   封装的意义在于保护或者防止代码(数据)被我们无意中破坏。在面向对象程序设计中数据被看作是一个中心的元素并且使用它的函数结合的很密切,从而保护它不被其它的函数意外的修改。   封装提供了一个有效的途径来保护数据

c_w_d的博客 7万+

C++继承多态

继承我们可以理解为是一种手段,我们是不是可以从其他的地方继承一些东西来供自己使用,继承是面向对象程序设计使代码可以复用的一个很重要的手段。我们可以再保持原有类特性的基础上进行扩展,增添一些其他的功能,而这种新产生的类,就叫做派生类。class Person //基类public:protected:private:class Student : public Person //派生类protected:int main()Student s;

2402_84602321的博客 1983

Java 封装、继承多态理解

更好的阅读体验:Java封装、继承多态理解 1.封装 封装:就是隐藏对象的属性实现细节,仅对外提供公共访问方式。让使用者知道的才暴露出来,不需要让使用者知道的全部隐藏起来 封装的好处:避免使用者直接操作属性值,隐藏类的实现细节;让使用者只能通过程序员规定的方法来访问数据;可以方便的加入存取控制语句,限制不合理操作,提高程序安全性。 1.1.封装的实现 Java是使用“访问控制符”来控制哪些细节需要封装的,哪些细节需要暴露的。 Java中有4种访问控制符,分别为private,defaul.

持 开源思想,撰 必胜所学,望 勤学者,无难处 5945

C++之对封装、继承多态理解

对封装、继承多态的简单认识理解

爱喝橙汁儿的博客 3793

Java继承多态

面向对象程序三大特性:封装、继承多态。在前的一章我们已经了解了什么是封装,而今天我们就要开始了解后面的两个————继承多态。在Java中如果要表示类之间的继承关系,需要借助extends关键字那么让我们来举个例子,我们知道猫狗都可以拥有名字年龄,吃饭的行为,对于这些共性的行为属性,我们可以将它放入一个类当中,让这个类作为父类,而我们的猫类狗类作为子类,同时着不相同的行为属性,而这些我们会将他们放入自己的类当中,而共同拥有的这些行为属性我们可以通过继承来获得他们 。(1)子类中访问父类的成员

zm3rttqs9f的博客 2267

C++封装继承多态理解

面向对象的三个基本特征: 封装 、继承多态 简单概括三大特性作用: 封装是为了代码模块化增加安全性 继承是为了重用扩展现有的代码模块 多态是为了接口复用 封装: 保护数据成员,不让类以外的程序直接访问或者修改类的成员,只能通过其成员对应方法访问(即数据封装) 隐藏方法实现的具体细节,仅仅提供接口, 内容修改不影响外部调用(即方法封装) 继承: 三种继承方式:public、protected、private。 继承的...

奋斗Andy的博客 3491

c#实例简单理解多态继承接口

通过实际案例讲解c#中多态继承以及接口的理解及使用

qq_40770527的博客 1万+

深度剖析—继承多态

之前提到OOP语言的基本三大特性:继承、封装、多态 本篇重点讨论:继承多态 继承 什么是继承? 先举一个例子: class Animal{ public String nama; public void eat(){ System.out.println("Animal::eat()"); } public void sleep(){ System.out.println("Animal::sleep()"); } } class C

一朵花花 1492

Java继承多态:深入理解继承、组合多态的精髓!

欢迎来到这篇关于Java继承多态的博客!在Java编程中,继承多态是两个非常重要的概念,它们为我们构建灵活而高效的代码提供了强大的支持。本文将深入探讨Java继承多态的原理、语法实践,帮助读者更好地理解应用这两个概念。

qq_60104186的博客 1053

封装 继承多态

封装继承多态 封装 我们在设计程序时,讲究六个字,高内聚,低耦合 封装就是我们对数据进行隐藏,多用于来封装属性,封装方法较少。 记住封装的核心,就是私有(private) 令属性为私有后我们调用不了类里面的属性,所以我们设置一些get方法set方法来操作私有的属性 get方法,set方法 public int getAge(){ return age; } public void setAge(int age){ this.age = age; } 具体代码应用 设置一个学生类,令其定义的属

weixin_48121041的博客 5430

Python 继承多态

本文介绍了Python中面向对象编程的核心概念——继承多态继承允许子类复用父类的属性方法,通过单继承继承实现代码复用与扩展,其中多继承需要注意方法解析顺序(MRO)。多态则通过统一接口实现不同行为,使代码更具灵活性。文章通过动物类示例演示了继承的实现方式、方法重写、super()的用法以及多态的应用场景,并分析了工厂模式等常见设计模式。最后提醒开发者避免滥用继承,注意多继承的复杂性,并合理使用super()方法。这些OOP特性可显著提升代码的可维护性扩展性。

余子越的博客 1271
上一篇: J2ME入门
下一篇: java多态性探析
zrd
zrd
博客等级 码龄22年 3粉丝 11原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值