书接上文,我们聊完了Java的类和对象,有没有唤起你脑海的一些记忆呢,我们有了类和对象的基础之后,我们就可以衍生出来封装继承和多态。
封装
我理解一个东西,我一般会先想这个是什么,再是怎么用,用他可以怎么为我们服务(可以给我们提供什么便利)所以我们先来看看封装是什么东西(他表达了什么含义),说到封装你可以想到什么东西,离我们最接近的就是我们手上的计算机,而这个计算机,你知道哪里封装了吗,我们就看一个台式机来参考
这个就是我们看到的一般的主机,而下面这个就是我们把主机外面的那一层壳拆开了
而外面再计算机的主机外面加的壳,这样的操作手法就是封装,而你想想为什么外面要给主机装一层壳啊,从最直观的角度来说,就是看着舒服,对吧,就是像是你自己的桌面,肯定是干净整洁的好看啊,所以主机也是这样,外面要做到干净整洁,才会让客户舒服吧,而这个就是最表面的好处,你再想,假如你拿下面的主机开机,是不是开机键都不好找(或者需要有一个人事先告诉你)开机键在哪里,这个是不是提高了你开机需要花费的心事,所以没有封装的东西,看着又头大,我要找相关的功能又不好找,这样是不是就提高了我需要花费的精力,而我们给主机封装一下,客户看的安心,用的舒心,是不是非常完美(也不是,因为提高了我们的工作难度啊啊啊),所以封装对于实际应用来说是非常有必要的,所以我们才会聊这个话题嘛。
而封装我们要这么实现呢,就是关键字public,这个关键字我们接触很久了,从一开始写开始程序的时候就见到了,而现在我们就可以来理解他的意思了,public的英文就是公开的,所以在封装里面就是可以让外界开到的属性(因为是公开的嘛)而与他对应的就是private(英文意思是私人的),在封装里面就是隐藏,不能让外界看到的属性,但是因为是私人的嘛,所以还是可以让自己人看到的啊(不然谁都看不到,还有什么用啊),如果到这里就结束了,是不是感觉少了点什么东西啊,因为这个可以干什么啊,所以要干的来了,还是以电脑主机为例,你想一个主机,你需要它干什么,最基本的不就是开机嘛,使用我们也要这个东西可以做一些什么,我们就要在这个类里面加方法,来对这些属性进行调用,就比如
是不是就会有人要说了,你看看你把name的属性变为private,后面要使用的时候,还要再写一个方法来调用,这个不是多此一举啊,你这样看确实是多此一举,但是你想想,我把他变为private的,外面的人是不是就不好改啊,(放屁,我们调用初始化的时候不就可以改的,但是假如我把它的初始化的类型变为true和false,我就让你给你两个选择,是不是你就不好改了),这样我们就可以用private这种来限制用户的输入(主要是怕你们乱搞,就性别来说,我国性别只有两种,但是别的国家就不知道了,tm的搞个百八十种,我都佩服他们因为我这辈子都只想的出来3种)而我们设置了4种关键字来限制权限
但是我们在日常写代码中一般就会用到public和private,所以别的大家看看就好,留一个影响就行,而在表格里面,我们看到的包又是什么呢,其实说白了就是一个文件夹,把我们写的代码装在一起,方便我们看,而在c语言中我们用include来包含别的文件,在Java我们也需要这样,但是因为我是idea用户,所以会自动添加,所以idea用户,可能很难体验到这个操作。补充一个重点,就是大家规定属性都无脑定义为private,而方法就具体问题具体分析
接下来就是一个小分支static
我们看他的英文翻译叫静止的,但是它的意思和翻译没有一点关系(但是又用一点关系,想知道主机搜吧,因为知不知道都不影响你理解static的意思)
static修饰变量,这个变量就变为了类变量,而类变量1.不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中 2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问 3. 类变量存储在方法区当中 4. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)这个是定义。
是不是看起来有点头大,我来讲一讲我的理解,你把类理解为集体,而方法理解为个人,而一个变量就是一个物品,这个物品本来是你自己私人的,后面你给这个物品加了static关键字,而这个物品就是集体的了(因为集体的利益在个人利益之上)而集体的东西就是我们大家都可以用了(因为不是你私人的了)
我们说一个实例,就是雷总在发布会上发布的一个机器狗叫钢蛋,而雷总说了一句钢蛋别跟我了,后面钢蛋就入伍了,而这个操作就相当于在钢蛋前面加了一个static,而这个钢蛋是不是以后就不跟雷总而是跟国家了(对应上面的 不存储在某个对象的空间中和3. 类变量存储在方法区当中),以后我们叫钢蛋的时候,我们可以说这个是雷军的钢蛋吗(假如你一定要这样说,也有一定道理,所以在idea里面也可以编译,但是不建议,就是能不要这样写就不要这样写),我们要叫国家的钢蛋了(对应2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问)而之前钢蛋在雷总那里的时候是不是就是和雷总的公司同生共死,而钢蛋跟了国家之后,就是和国家一起了(对应4. 生命周期伴随类的一生)而钢蛋跟了国家以后,就是我们大家共同所有的(对应1.不属于某个具体的对象,是类的属性,所有对象共享的)这个就是static修饰变量,我们来看一个代码
你们先猜猜输出结果是什么,我先声明一下哦,这个属性test1,2确实要private,但是我因为要直接看,所以才设置为public,还有就是test1.n我们是不建议这样写的,但是我为了方便大家看,才这样写的
大家有没有想到呢,我们之前明明把test1的n设置为了100啊,为什么输出的是1000呢,其实,这个就是上面的static修饰变量,把变量变为共有的了,所以test1和test2公用一个地方,而这个地方在哪里呢,我们来看一个图
大家的n(就是test1 和test2公用)在执行test1时确实被赋值为了100,但是在执行test2的时候被改为了1000,而我们的输出在最后面,所以test1,2里面的n都为1000,所以才会输出n=1000。
这个就是static修饰变量,下面我们来来聊一聊static修饰方法
,而static修饰方法和修饰变量还是有不小的区别的,老规矩我们看定义1. 不属于某个具体的对象,是类方法 2. 可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者 3. 不能在静态方法中访问任何非静态成员变量。
现在我来说一说我对它的理解,首先static修饰方法和修饰变量一样,都是把变量(方法)从私人那里变为了公用的,所以我们static修饰的方法大家都可以使用(就是我们可以用普通的方法调用对应1. 不属于某个具体的对象,是类方法 )而这个方法也从私人的名下转到了集体的名下(对应2. 可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,但是我们推荐写后面这个,因为就比如说一个东西本来是我的,但是后面我给你了,别人要指出这个东西,一般人都会说是你的上面东西,而不会说是我的,但是如果你硬要说是我的,别人也可以理解)而3我们就要好好说一下了,还是按上面的规则,我们把static修饰方法的比喻为集体,而普通的方法比喻为我们自己,因为我们是社会主义,所以,集体里面的物品(变量和方法),我们就是可以使用的,但是我们自己的物品(变量和方法)别人是不能使用的,集体也不行(因为是我们自己的,我们还没有奉献给集体),所以static修饰的方法,不能调用普通方法,但是普通方法可以调用static方法(我们可以使用集体的物品啊),
还有一个小知识点,就是static修饰的变量的初始化,我们直接在一开始写的时候,给定一个值就可以了,没必要搞这些那些的。
以上就是封装的内容了,下面开始我们的继承
继承
什么是继承,你先带着这个问题看下面的一段文字
在大自然中,动物的基因决定了动物长什么样子,而基因是一代一代继承下去的,而这个继承就是把父类有的特征保留下来,但是因为基因突变,所以子类不会和父类一模一样,而是有所区别,这里涉及的继承和基因突变,就是我们编程里面的继承。
我们编程里面的继承,就和上面基因一样,我们要先有一个父类,子类继承至父类,而子类又不会完全和父类一样,子类有自己的特点,这个就是我们编程里面的继承。所以我们要先创建一个父类比如,我们先创建一个父类Animal
而我们在写一个Dog的子类
我们用extends来表示,Dog这个子类继承于Animal这个父类,而我们在子类中一定要加别的东西,不然你还要子类干嘛,有父类不就够了啊。
当我们的子类继承了父类之后,父类有的子类就有,子类可以用父类中的方法,子类也可以用这个的方法,mew就是子类中自己的方法
额外说一点,就是假如你不小心把父类和子类的变量设置为了同一个名字,而你在后续使用的时候,我们会优先考虑子类的变量,这个也很好理解,既然你在子类中又创建了这个变量,就是说明这个变量是你在后续要用到,所以计算机会默认为是子类中的变量。而在日常生活中,如果父类和子类的变量名一样的话,你不仅仅会使用到子类的变量,你还会要用到父类的变量,而在父类中的变量我们就用一个super关键字来表示,所以我们现在来聊一聊super关键字的一些用法,super的英文名大家应该很熟悉了吧,比如superhero超级英雄(大家会看一些漫威啊,DC之类的不)所以super的英文意思就是超级,而这个super对应的就是父类的意思,而super的用法也不难,就是在子类中要使用父类的时候,你就写super,计算机就知道这个变量是父类中的变量和方法,现在,我们就可以来聊一聊构造方法了。
构造方法
我们在上面的图片中可以看到,我们创建的Cat都是没有写名字的,以及后面的打印,我们都是null在吃饭,这个就是因为我们在创建变量的时候,没有给一个名字,都是在一般情况下,我们都是不要再创建的时候就给一个名字的,我们一般再使用过程中,要一只小猫,在这个时候把名字给他加上,所以我们就可以在子类创建的时候给他加一个构造方法,
想这样,然后就报错了,报错原因是name在父类是私人变量,不能给别人使用。我们想想,我们的属性不是都设置为了private,而private这个关键字修饰的变量,就只能在这个的类里面使用,子类都不行,所以才会报这样的错。但是这样我们要怎么解决呢,最简单的就是把private改为public但是这样我们又怕别人在使用的时候会乱改,所以是不行的,但是我们提供的关键字不止这几个,
看这个图,我们protected是不是刚好符合啊,所以我们可以把父类中的属性设置为protected,这样就可以使用了,我们还要一个方法就是在父类中用一个方法把名字返回
再在子类里面调用这个方法就可以了,
而我们在创建子类的时候,父类中的构造也会执行,因为先有父再有子啊
是吧,而这个是怎么出现的呢,我们在子类的代码里面,计算机会自动添加一个super()来调用父类的构造方法,就接着我们就来聊一聊初始化了,本来之前要写的,但是我想反正后面都要写还不如一起写,这样还更有内聚性。
初始化
我们的初始化有三种,第一是,静态代码块(加static的)第二是,实例代码块(就是那()这个括起来的),第三是构造方法。这个其实,我们在计算机上面运行一下就知道先后顺序了,这里就直接说了,先静态(因为静态就是加了static的,这个是集体的,和集体共存亡,集体有他就在)后在实例,最后才是构造,这个我也没有什么好背的方法(但是实例用的不多)而现在我们有父类和子类了,这个初始化会不会有什么变化呢,我们来看看
其实,这个应该是意料之中,因为静态代码块(static修饰的)是类方法,肯定的在第一位的,而父类的优先级肯定要比子类高的,所以这个就是1.2.名,而后面的还是先执行父类,把父类的全部执行完了,再执行子类。继承的代码大概逻辑就是这样,现在我们看看继承的逻辑
继承的逻辑
我们继承有几种逻辑,第一是,就一个父类和一个子类,这个没有什么可以说的。第二就是有一个父类还有一个子类,而这个子类下面还有子类(子子孙孙无穷尽也),但是因为这样写代码别人看着可能会问候你,所以我们一般就到顶4,5层。第三,就是一个父类多个子类,这个也是很常见的。第四,就是一个子类多个父类,这个就不常见了,但是还是有的,就比如
大丈夫身居天地之间,岂能郁郁久居人下,飘零半身,只恨未逢明主,公若不弃。
但是大家还是尽量不要这样啊,因为名声不好听啊,
所以我们在编程里面也不要这样啊,幸好我们是Java,Java不支持这种写法,但是c++支持。
final
我们先聊一个简单的final,小小休息一下,final这个关键字的英文意思是最后的(我的理解是既然都是最后的了,后面就不能再改变,继承,重写了呗,就是这个变量还可以用,就是不能做改变了)
组合
组合,确实很简单,就比如我们创建的Animal这个类,我们下面分了Cat和Dog,而Cat和Dog就是一对组合,所以没有什么好说的。
下面就开始,我们的最后一个
多态
多态这个东西,相比起封装和继承来说是最抽象的,但是放心我会把我理解的奉献出来,我们按字面意思来理解,多态就是一个东西有多种状态,什么叫多种状态呢,不是你打游戏的,看到人,就半血,中一枪就大残的那个状态,我们举一个例子,我们有很多人喜欢养狗,喜欢养猫等一些小动物,我们假如这个人非常喜欢这些小动物,它把狗和猫都叫儿子,后面他叫他朋友给他儿子搞一点东西吃的时候,他的朋友是不是就要想,他是要我喂猫还是喂狗,而这个人就要根据上下文来推断出来,我们就看这个实例,他叫儿子,而这个儿子是不是有两种可能,而因为有两种不同的可能我们就要做出不一样的事情,一种可能是猫,一种可能是狗,因此,一种状态是猫(猫我们就要喂猫粮),一种状态是狗(狗我们就要喂狗粮),因此儿子就有两种状态,所以我们把儿子这种因为不同状态发生不同结果叫多态。这个就是多态的含义。总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。而我们要实现多态,离不开重写,我们先把重写理解了,就可以开始写多态了
重写
重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定 于自己的行为。 也就是说子类能够根据需要实现父类的方法。这个是重写的定义,看着好像很复杂,其实就是返回值和形参类型不变(返回的实际的值可以变,但是类不能变),但是中间我们要实现的功能可以变,就是相当于一个工厂,假如是生产桌子的,我们的原材料要木材,所以我们要把木材(传过来的形参)放进去,我们的成品是一个桌子(返回值的类型)但是中间我们怎么生产的过程,我们可以改。返回值的类型你说可以变,好像也可以,但是是有前提条件的(就是要有父子关系),我们为什么要怎么说,我们抛开事实不谈,子类的核心就是父类,因为子类是继承至父类,因此,他们大部分是相同的,所以我们可以再这个小部分姑且认为他们类型的相同的
而我们要实现多态(就是不同的状态发生不一样的事情),就需要用到重写。看代码
我在父类Animal里面,写的是不知道什么东西在吃东西。
而我在子类里面写在吃鱼,而我们在调用的时候
这里应该会有一个小问题就是为什么我在创建的时候,不是Cat cat = n~,而是Animal animal1这个就是我们之前的说的父类和子类的东西了,但是我们之前说的是,返回值和形参,现在我们可以看到,我们创建的值也是可以的。
多态,感觉还有很多没有和大家聊,但是感觉必要的就这么多,放心,后面我们还好有很多接触多态的机会,就比如下一篇的抽象类和接口,拜拜了。