Java基础知识之封装+继承+多态详解

前言

这篇博客是基于Java类和对象的基础之上的相关知识点。因为特别重要且语法规则较多,所以想单独总结方便之后复习。

本篇博客涉及知识点思维导图:

目录

     1.封装

     2.继承

     3.多态


1.封装

          生活中有很多东西我们并不想让其它人知道,比如我的身份证号码,我的存款等等。在Java语言中,我们就需要了解java面向对象的三大特性之一——封装

         封装就是隐藏对象的属性和实现细节,仅提供公共访问方式来让外界访问。比如。那么问题来了,我们该如何实现封装呢?这就涉及到了Java中访问修饰符的知识。在Java语言中,访问修饰符分为四类:private,默认(什么也不加),protected,public。那它们有什么作用呢?我们从private修饰符开始:

 可以看出Person类中用private修饰的成员变量,只能在Person类中使用,且只能由我们决定外界是否能访问它。如果我们想要外界访问它,只能提供公开访问的方法让外界可以去访问,这里我们给私有属性name提供setName和getName方法,外界就可以通过setName方法对私有属性name的值进行修改,且能使用getName方法去获得name的值,具体实现如下:

运行结果:


因为接下来的知识点涉及到包的概念,我先简单给大家介绍一下包的概念及使用。

其实包 类比于我们磁盘下的文件夹(树形结构),如图:

 这就能更好的管理我们的Java文件,且能一定程度上避免因为类同名造成的冲突。

 Java也有很多自带的包,当我们要使用Java中某个类时,也需要进行导包(导入某个包的要使用的类),如当我们需要获取用户输入的数据时,得用到Scanner类,这时候就要在Java文件中导入util包下的Scanner类:

 当然啦!我们也可以创建自己的包,步骤如下:

 

注:开头com.example位置一般为公司所对应的域名的倒置,且包名的每个部分都对应一个子目录。

包创建成功后,点击齿轮--->Tree Appearance--->Compact Middle Packages 可以显示每个子目录:

 

这样选中包下的对应目录,右击便可以创建.java文件了。


接下来我们继续讲默认(什么都不加)的访问限定符。如图:

 

成功运行并输出:

 

那如果是在不同包的类中可以访问用默认访问限定符修饰的成员变量或方法吗?

编译失败,由此我们可以知道,name用默认访问限定符修饰,所以不能在不同包的类中使用。所以我们也将默认访问限定符叫做包访问权限,也就是说使用默认访问限定符修饰的成员变量或方法是不能在不同包的类中访问的。


Java类中用public访问限定符修饰的成员变量或方法不管是在不同类还是不同包都可以访问,处处可修改并获取。我们来测试一下~:

同一个包的不同类:

 

不同包的不同类:

 由图看出,用public访问限定符修饰的成员变量在任何位置都可以访问。所以public访问限定符也叫公共访问权限。

最后附上四种访问限定符的权限范围表格:

 注:因为protected访问限定符的使用涉及到继承的知识点,所以咱先不讲。


2.继承

     想到继承,大家可能都跟我一样首先想到的是父亲留下的财产继承(都是大孝子哈哈哈哈哈)。但是在Java中继承就是将某些(B,C,D....)类中相同属性提取出来放入A类中,用extends关键字实现继承之后,那A类就成为这些类的父类,而这些类就会被称为A类的子类。为了方便大家理解,可以看看我画的逻辑图例:

蓝色框框的就是学生和老师共有的属性和行为,Person类为Student类和Teacher类。 具体代码实现:

 在main方法中测试结果:

 大家可以看出,我们可以使用子类继承父类(共性的抽取)的方式去实现代码的复用

那么这时候又有一个问题了:如果父类中的某成员变量是private私人的,子类还会继承和该成员变量或方吗?我们来调试一下:

  

 从图中可以得出:子类无法访问父类中用private修饰成员变量。打开调试,我们看看student和teacher对象中是否继承了父类中用private修饰的name成员变量:

这样我们可以得出:父类中用private修饰的成员变量是会被子类继承的,但是不能直接访问,只能通过公共访问的成员方法对其进行访问。如下:

这时候大家可能就会想:如果父类中的成员属性名或方法名和子类中成员属性名或方法名同名,那访问的是子类的成员还是父类的?一切问题从调试开始:

由图我们可以得出:当父类成员变量与子类成员变量出现同名冲突时,优先访问子类的成员变量。

那我们就想访问父类中的同名成员变量呢?这时候就得用到super这个关键字(注:其不是父类的引用,只是个关键字,用于更直观地理解代码),使用super. 成员变量名访问父类中同名的成员变量,super.成员方法名()访问父类中同名的成员方法。测试如下:

 接下来大家可以想想这段代码为什么会报错?

哎我就想在创建父类的时候就对name进行初始化,所以给它写上了一个构造方法,然后子类编译错误了。大家仔细看看报错提示: 

在我上篇博客中,提到过这个知识点,也就是每个类编译器都会生成一份默认无参的构造方法(但是不会显示出来),但是当我提供了任意的构造方法后,那编译器提供的默认无参的构造方法就不会生成。那为什么我不自定义构造方法时,子类不会报错呢?由此可以得出,子类会默认帮助父类进行初始化。当我给父类自定义构造方法时,父类默认无参构造方法不存在,那子类就无法默认帮父类进行无参构造,所以才会编译失败。这里我们还是使用super(...)调用父类的构造方法帮助父类构造。(帮助父类的成员变量进行初始化)

 嘿嘿不报错了~但是大家还要注意一点哦:子类帮助父类进行构造只能在子类构造方法的第一行哦!这时候大家可能就会问了那想用this调用子类其它构造方法,也要放第一行,那这两者谁先谁后啊?答案是它俩不能一起用!(要打架就把它们分开) ,大家看如下测试:

看不是我在胡说八道吧!嘿嘿连编译错误提示都说super()必须得放第一行。

看它俩都要第一行,所以当子类帮助父类构造时是不能使用this调用子类另一个构造方法的。

但是这样是可以的:

相信大家都能对继承有初步的认识并且了解了一些语法规则。

当你不想某个类被继承时,可以加final(修饰变量时变量无法更改,修饰方法时,方法不能重写)修饰:

注:Java中只允许单继承,不能多继承哦!就像我们例子中的学生类和老师类一样,它们都只有一个父类(类比于每个人的亲生父亲只有一个),但是它们可以多层继承,如图:

编译错误提示:不能继承多个类

支持多层继承


3.多态

     在我们现实生活中,多个人做同一件事不可能完全相同,比如对于吃饭这件事,有的人吃冒菜,有的人吃螺蛳粉,有的人吃烧烤等等。在Java中,多态是同一个行为具有不同的表现方式或形态。那在什么条件下,才能实现多态呢?答案是:在继承的基础上,重写父类中的成员方法并定义父类引用指向子类对象(向上转型)

示例(还是以人为例,更好理解)如下:

大家可能疑问既然有向上转型(不用进行强制转换,可以调用父类中所有成员,但是不能调用子类中特有成员),那有向下转型吗?答案是:有,向下转型(子类对象指向父类引用)与向上转型相反,但是它是不安全的,如果父类引用对象是父类本身,进行向下转型时,即使 使用强制类型转换后,也只能保证编译不出错,运行时还是会报无法进行强制类型转换的错误。(一般用instanceof运算符避免这种错误)。如下:

 只有当父类引用指向子类对象,再进行向下转型时,才是安全的

注:不管的进行向上转型还是向下转型,都是要在继承的基础上才可以。

说到这里,大家一定会对重写产生疑问吧?其实重写很好理解,本质就是在不改变父类原有成员方法(一定要是非静态,非private,final修饰,非构造方法...)的基础上,重新在子类中实现该方法。跟重载不同的是重写的参数,返回值类型(除非两个返回值类型构成父子关系)和访问限定符(子类的访问权限必须得比父类的访问权限大或相等)都不能修改!

注:尽量避免在子类构造方法中调用重写方法,不然可能会造成子类对象还未构造完成,在使用其成员变量时,成员变量为默认值而不是其初始化后的值。


以上就是我对Java面向对象三大特性的理解,欢迎大家和我一起探讨学习,共同进步~

  • 21
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java中的封装是一种面向对象编程的重要概念,用于隐藏类的内部细节,并提供公共接口以便其他类可以使用。封装可以保证数据的安全性和一致性,并且可以使代码更易于维护。 Java中的封装通常通过访问修饰符来实现,其中public、protected、private是三个最常用的访问修饰符。public表示该成员可以被任何类访问,protected表示该成员可以被同一个包中的类和继承该类的子类访问,private表示该成员只能被该类的方法访问。 封装的主要思路是将类的数据成员设置为私有,然后通过公共的方法提供访问这些私有成员的接口。这些公共方法通常被称为getter和setter方法,其中getter方法用于获取类的私有成员变量的值,setter方法用于修改类的私有成员变量的值。 以下是一个简单的Java类的封装示例: ``` public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { if (age >= 0 && age <= 120) { this.age = age; } else { System.out.println("Invalid age!"); } } } ``` 在上面的代码中,name和age被设置为私有成员变量,只能通过公共的getter和setter方法进行访问。setName和setAge方法包含一些条件判断,以确保输入的值是有效的。这种封装可以防止类的数据被错误地修改,并提供了更好的代码可读性和可维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值