如何理解类的三大特性(封装、继承、多态)

如何理解类的三大特性(封装、继承、多态)


类是什么
类是具有相同属性和行为的一组对象的集合 。类有封装,继承,多态三大特性。

什么是封装
Java中封装的实质是将类的状态信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
封装反映了事物的独立性,有效避免了外部错误对此对象的影响,并且能对对象使用者由于各种原因产生的错误操作起到预防作用,也起到了对象之间的松耦合关系。
封装的好处在于隐藏类的实现细节,让使用者只能通过程序员规定的方法来访问数据,可以方便地加入存取控制修饰符,来限制不合理操作。

封装的实现
我们可以用下面的例子来进一步说明类的封装。

修改属性的可见性

如何理解类的三大特性(封装、继承、多态)
上述代码中,将访问修饰符修改为private后,其他类就无法访问了,如果要访问必须通过封装定义别的方法来实现。

定义方法
如何理解类的三大特性(封装、继承、多态)

如何理解类的三大特性(封装、继承、多态)

运行结果如下:
如何理解类的三大特性(封装、继承、多态)
以上就是Java封装的典型实现。

继承

什么是继承
继承可以解决编程中代码冗余的问题,是实现代码重用的重要手段之一。继承是软件可重用性的一种表现,新类可以在不增加自身代码的情况下,通过从现有的类中继承其属性和方法,来充实自身内容,这种现象或行为就称为继承。此时新类称为子类,现有的类称为父类。继承最基本的作用就是代码重用,增加软件的可扩性。
Java中只支持单继承,即每个类只能有一个直接父类。

  • 根父类

在Java中,即使没有声明父类,也有一个隐含的父类,这个父类叫Object。Object没有定义属性,但定义了一些方法。
这里有必要讲讲toString()方法,toString()方法的目的是返回一个对象的文本描述,这里可以直接被所有类使用。比如以下代码:
如何理解类的三大特性(封装、继承、多态)
运行结果如下:
如何理解类的三大特性(封装、继承、多态)
这是什么意思呢?@之前是类名,@之后是父类hashCode()返回一个对象的哈希值。这种输出方式不是很友好,用户看不懂意思,于是我们重写toString()方法。

  • 重写

这次,我们来重写toString()方法,就是在原来的Point类文件中末尾添加带有@Overrid的toString方法,代码如下:
如何理解类的三大特性(封装、继承、多态)

运行结果如下:
如何理解类的三大特性(封装、继承、多态)

继承体系
下面将把人类作为父类,学生继承人类,研究继承学生类进一步解释Java中的继承

  • 父类 Person
  • 子类 Student
  • 子类的子类 PostGraduate

Person类
如何理解类的三大特性(封装、继承、多态)

Student类
如何理解类的三大特性(封装、继承、多态)

PostGraduate类
如何理解类的三大特性(封装、继承、多态)

如何理解类的三大特性(封装、继承、多态)

分析如下:
在执行new PostGraduate(“小明”,“南京大学”,“李老师”,“计算机信息技术”)后,创建了4个对象,依次调用了Object(),Person(String name),Student(String name,String school),PostGraduate(String name,String school,String guide,String major)。

运行结果如下:
如何理解类的三大特性(封装、继承、多态)

父子类型转换
子类型的对象可以赋值给父类型的引用变量,这叫向上转型。那反过来能将父类型的变量赋值给子类型的变量吗?在语法上可以进行强制类型转换,但不一定能成功转换。
比如:
如何理解类的三大特性(封装、继承、多态)
PostGraduate p=(PostGraduate)stu就是将变量stu的类型强制转换为PostGraduate并赋值为p,这是没问题的,因为stu的动态类型就是PostGraduate,这是还原其子类本身,运行结果如下:
如何理解类的三大特性(封装、继承、多态)

但下面的代码是不行的:
如何理解类的三大特性(封装、继承、多态)
运行结果如下:
如何理解类的三大特性(封装、继承、多态)
语法上Java不会报错,但运行时会抛出错误,错误为类型转换异常。

一个父类的变量能不能转换为一个子类的变量,取决于这个父类变量的动态类型(即引用的对象类型)是不是这个子类或这个子类的子类。
给定义个父类的变量能不能知道它到底是不是某个子类的对象,从而安全地进行类型转换呢?答案是可以的,通过instanceof关键字,比如下面代码:

如何理解类的三大特性(封装、继承、多态)
运行结果如下:
如何理解类的三大特性(封装、继承、多态)

防止继承final
有的时候我们不希望父类方法被子类重写,有的时候甚至不希望被继承,可以通过final关键字来实现。final可以修饰变量,而这是final的另一种用法。一个Java类,默认情况下都是可以被继承的,但加了final关键字之后就不能被继承了,比如:
如何理解类的三大特性(封装、继承、多态)
一个非final得类,其中public/protected实例方法默认情况下都是可以被重写的,但加了final关键字后就不能被重写了,比如:
如何理解类的三大特性(封装、继承、多态)

多态

什么是多态
多态就是一种类型,多种表现形式。
多态的存在有三个前提:

  • 要有继承关系
  • 子类要重写父类的方法
  • 父类引用指向子类对

如何理解类的三大特性(封装、继承、多态)
我们修改上述Person类,Student类,PostGraduate类的代码,修改结果如下:
Person类
如何理解类的三大特性(封装、继承、多态)

Student类
如何理解类的三大特性(封装、继承、多态)

PostGraduate类
如何理解类的三大特性(封装、继承、多态)

如何理解类的三大特性(封装、继承、多态)

运行结果如下:
如何理解类的三大特性(封装、继承、多态)

上述代码中,Student类继承Person类,PostGraduate类继承Student类,它们之间有继承关系,并且重写了父类的study()方法,并且程序在堆内存中开辟了子类的对象,并把栈内存中的父类的引用指向了对象。
可以看出来Student重写了父类的Person()方法,输出结果为:学生在学习。同样PostGraduate重写了父类的student()方法,输出结果为:研究生在学习。

多态的利与弊
Java的多态可以将一种类型表现为多种形态,这就是多态的魅力所在,不过它也有弊端,比如:
如何理解类的三大特性(封装、继承、多态)
上述代码中,Person引用了一个PostGraduate对象person,PostGraduate有自己的setGuide/getGuide()方法,但是person不能调用这2个方法,编译不能通过,必须通过下面的方法才能调用。
如何理解类的三大特性(封装、继承、多态)
运行结果如下:
如何理解类的三大特性(封装、继承、多态)
虽然Java中的多态有缺点,但是它确实十分灵活,我们可以好好的运用它的特性减少多余对象的创建。

至此,Java三大特性已经全部介绍完毕,如果大家能从中得到更深的理解请点个赞吧!