深入理解java面向对象三大必杀技—封装,继承,多态

概述

Java是一种面向对象的语言,所以理解面向对象的编程思想对学习Java是相当重要的。

什么是面向对象?

首先来看第一个问题, 对于初学者来说想要一次性完全理解面向对象是很困难的,要有一定代码量之后再回头看就会有新的理解。这里就先灌输一个概念,只要有印象就行。

面向对象时一种符合人类思维习惯的编程思想,比如现实生活中有各种各样的事物,这些事物有着各种各样的联系。程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。

不能理解这段话没关系,我们可以对比面向过程来看看。面向过程是C语言的特点,它就是分析解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候一个一个调用便OK。而面向对象则是把解决的问题按照一定的规则划分为多个独立的对象,然后通过调用对象的方法来解决问题的。当然,一个程序会包含多个对象,通过多个对象相互配合来实现应用程序的功能,这样当程序发生需求变动的时候,只需要改动相关的对象,从而使代码更容易去维护。

如果用吃来做比喻,自己做则是面向过程,买菜、配菜、煮饭、炒菜,自己必须要依次实现这些过程,最后才能吃到美味可口的饭菜,面向对象则好比是下馆子,只需点菜而做菜的过程已经被饭馆封装起来,这里不需要关心厨师是如何做菜的只要品尝菜是否美味可口。

面向对象的三个特点:封装,继承,多态。

一丶封装

我们要如何理解封装?

封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道其实现细节,这就是封装思想。我们来看下面这段代码:

public class Test{

public static void main(String[] args){

Student stu = new Student();

stu.name = "妞妞";

stu.age = 1000;

stu.show();

}

}

这段代码中将年龄赋值为1000岁,这在程序中当然不会有任何问题,可是在现实生活中却是违背常识的。为了解决这个问题,在设计类的时候,应该对成员变量的访问做出限制,不允许外界随意访问,这就需要实现类的封装了。

从定义上来说,类的封装主要指在定义一个类的时候,将类中的属性私有化,即使用private关键字来修饰,被private修饰的属性只能在它所在类中被访问。同时,为了让外界访问私有属性,需要一些公共方法,其中就包括用于设置属性值的setter()方法和获取属性值得getter()方法,下面的代码就实现了类的封装:

深入理解java面向对象三大必杀技—封装,继承,多态

类的封装.JPG

在图中的Student类中,使用private关键字将属性name和age声明为私有不允许外界随意访问,只能通过setter方法来操作两个实例变量的值。而在setter方法中可以增加自己的控制逻辑,从而保证Student对象的name和age两个实例变量不会出现与实际不符合的情形。

另外在啰嗦两句,进行程序设计的时候,应尽量避免一个模块直接操作另一个模块的数据,模块设计追求的是高内聚(尽可能把模块的内部数据、功能实现细节隐藏在模块内部独立完成,不允许外界直接干预)低耦合(仅暴露少量的方法给外部使用)。正如我们平常使用的手机APP,不需要去关心里面的代码实现细节,只要能满足我们的需求便可以。

二丶继承

继承,从世俗的角度来解释便是子女得到父辈的财产或物品。程序中,继承是指两个类的从属关系,它可以使多种事物之间形成一种关系体系。例如贵宾和泰迪都是属于宠物犬,程序中便可以描述为贵宾和泰迪继承自动物。这离我们主要理清三个问题:

1.继承的概念是什么?

2.继承中如何重写父类的方法?

3.关键字super如何使用?

先看第一个问题,在Java中类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的类被称作子类,现有的类被称作父类,子类会自动拥有父类所有课继承的属性和方法。同时,程序中通常用extends关键字来声明一个继承另一个类,下面就通过一个案例来演示:

深入理解java面向对象三大必杀技—封装,继承,多态

继承的基本使用.

上面代码的运行结果是“动物的叫声”和“我的名字叫贵宾”。其中Dog类通过extends继承了Animal类,这样Dog类便是Animal类的子类。从运行结果可以看出,子类虽然没有定义name属性和shout方法,但是却能访问这两个成员,这也就说明了子类在继承父类的时候,会自动拥有父类的所有成员。但也有一些问题需要注意下:

1.Java中,类只支持单继承不允许多重继承,也就是说一个类只能有一个父类。

2.多个类可以继承同一个父类。

3.可以多层继承,即一个类的父类可以去继承另外的父类。

4.Java中的子列和父类只是一种相对概念。

接下来看第二个问题,继承中重写父类方法是怎么回事。

我们知道继承关系中,子类会自动继承父类中定义的方法,但有时在子类需要对继承的方法进行修改,即重写父类方法。好比父亲的理想,如果儿子不喜欢,可以去追求自己的梦想。

上面代码中,Dog类继承了Animal类中的shout方法,调用时会打印“动物的叫声”,这明显不是描述一种具体动物的叫声,Dog发出的叫声应该是“汪汪汪。。。”为了解决这个问题,可以在Dog类中重写父类Animal的shout()方法,具体代码如下:

深入理解java面向对象三大必杀技—封装,继承,多态

继承中重写父类方法

运行结果是“汪汪汪。。。”。从运行结果可以看到,在调用Dog类对象的shout方法是,只会调用子类重写后的方法。

最后来看第三个问题,如何正确使用super关键字?

从上一个代码中可以看到,当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,Java中专门提供一个super关键字用于访问父类的成员。super的作用主要体现在两个方面:

1.使用super关键字调用父类的成员变量和方法,格式如下

super.成员变量;

super.成员方法({参数1,参数2...});

2.使用super关键字调用父类构造方法,格式如下

super.({参数1,参数2...});

java中多态性的实现

三丶什么是多态

1.面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。

2.多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

3.实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

4.多态的作用:消除类型之间的耦合关系。

5.现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。

(一)相关类

1.class A ...{

2. public String show(D obj)...{

3. return ("A and D");

4. }

5. public String show(A obj)...{

6. return ("A and A");

7. }

8.}

9.class B extends A...{

10. public String show(B obj)...{

11. return ("B and B");

12. }

13. public String show(A obj)...{

14. return ("B and A");

15. }

16.}

17.class C extends B...{}

18.class D extends B...{}

(二)问题:以下输出结果是什么?

1.A a1 = new A();

2. A a2 = new B();

3. B b = new B();

4. C c = new C();

5. D d = new D();

6. System.out.println(a1.show(b)); ①

7. System.out.println(a1.show(c)); ②

8. System.out.println(a1.show(d)); ③

9. System.out.println(a2.show(b)); ④

10. System.out.println(a2.show(c)); ⑤

11. System.out.println(a2.show(d)); ⑥

12. System.out.println(b.show(b)); ⑦

13. System.out.println(b.show(c)); ⑧

14. System.out.println(b.show(d)); ⑨

(三)答案

① A and A

② A and A

③ A and D

④ B and A

⑤ B and A

⑥ A and D

⑦ B and B

⑧ B and B

⑨ A and D

(四)分析

①②③比较好理解,一般不会出错。④⑤就有点糊涂了,为什么输出的不是"B and B”呢?!!先来回顾一下多态性。

运行时多态性是面向对象程序设计代码重用的一个最强大机制,Java多态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。

方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中Java多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。

当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。 (但是如果强制把超类转换成子类的话,就可以调用子类中新添加而超类没有的方法了。)

好了,先温习到这里,言归正传!实际上这里涉及方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。让我们来看看它是怎么工作的。

比如④,a2.show(b),a2是一个引用变量,类型为A,则this为a2,b是B的一个实例,于是它到类A里面找show(B obj)方法,没有找到,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(A obj),输出为"B and A”。

再比如⑧,b.show(c),b是一个引用变量,类型为B,则this为b,c是C的一个实例,于是它到类B找show(C obj)方法,没有找到,转而到B的超类A里面找,A里面也没有,因此也转到第三优先级this.show((super)O),this为b,O为C,(super)O即(super)C即B,因此它到B里面找show(B obj)方法,找到了,由于b引用的是类B的一个对象,因此直接锁定到类B的show(B obj),输出为"B and B”。

按照上面的方法,可以正确得到其他的结果。

问题还要继续,现在我们再来看上面的分析过程是怎么体现出蓝色字体那句话的内涵的。它说:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。还是拿a2.show(b)来说吧。

a2是一个引用变量,类型为A,它引用的是B的一个对象,因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出"B and B”才对。但是为什么跟前面的分析得到的结果不相符呢?!问题在于我们不要忽略了蓝色字体的后半部分,那里特别指明:这个被调用的方法必须是在超类中定义过的,也就是被子类覆盖的方法。B里面的show(B obj)在超类A中有定义吗?没有!那就更谈不上被覆盖了。实际上这句话隐藏了一条信息:它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(A obj),如果子类B没有覆盖show(A obj)方法,那么它就调用A的show(A obj)(由于B继承A,虽然没有覆盖这个方法,但从超类A那里继承了这个方法,从某种意义上说,还是由B确定调用的方法,只是方法是在A中实现而已);现在子类B覆盖了show(A obj),因此它最终锁定到B的show(A obj)。这就是那句话的意义所在,到这里,我们可以清晰的理解Java的多态性了。

总结

到这里深入理解java面向对象三大必杀技—封装,继承,多态。结束了,不足之处还望大家多多包涵!!觉得收获的话可以点个关注收藏转发一波喔,谢谢大佬们支持。(吹一波,233~~)

下面和大家交流几点编程的经验:

1、多写多敲代码,好的代码与扎实的基础知识一定是实践出来的

2丶 测试、测试再测试,如果你不彻底测试自己的代码,那恐怕你开发的就不只是代码,可能还会声名狼藉。

3丶 简化算法,代码如恶魔,在你完成编码后,应回头并且优化它。从长远来看,这里或那里一些的改进,会让后来的支持人员更加轻松。

最后,每一位读到这里的网友,感谢你们能耐心地看完。希望在成为一名更优秀的Java程序员的道路上,我们可以一起学习、一起进步。

想了解学习以上内容可加群569068099  验证:(009)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值