JavaSE基础知识(五)--面向对象(三)

Java SE 是什么,包括哪些内容(五)?

本文内容参考自Java8标准

一、面向对象(代码实现):

首先,在这里我需要说明一个根本性的问题:实际上,面向对象编程包括了两部分,一个是你的编程思想,一个是代码环境的支撑。我前面的两篇博文[JavaSE基础知识(五)–面向对象(一)JavaSE基础知识(五)–面向对象(二)]非常细致地说明了面向对象的编程思想(也就是说,你需要先理解面向对象的编程思想是什么样的,然后再结合代码环境的支撑,去构造并且实现你的思想),那么,在这里,我将再次非常细致地说明,在Java的整个环境中,代码层面对面向对象的编程思想具有什么样的支撑!
JavaSE基础知识(五)–面向对象(一) 这篇博文中,有一段描述是将汽车类型抽象成代码的表示:如图
在这里插入图片描述
在这里,第一次谈到了类类型的概念,也就是说,在我们利用代码创建并使用一个对象之前,首先需要有这个对象的类类型代码,实际上,任何一个对象都是属于某一类的(在创建这个类型的对象之前,都是需要有这个类类型的代码的。),那么问题就很明确了,我们只需要清楚:Java的代码环境,对于我们实现一个类类型代码提供了什么支撑?要说清楚这个问题,需要分很多步来说明
1、一个类类型的代码需要包括什么内容?
这个问题一听起来可能会觉得很宽泛,但是实际上,截止目前已经明确了两大项内容:
状态: 要说清楚状态,需要通过实际的例子来说明,比如汽车类型,汽车类型的状态可能会有重量,价格,长,宽,高,颜色,品牌等(如果状态无法用八类基础类型[byte、short、char、int、long、float、double、boolean]来表述,那只能用另外的类类型来表述,通过这里你就能知道,Java中的类类型能通过其他的类类型进行组合而得到,所以你在创建一种类类型的时候,必须要考虑到别人以后可能会用到你现在创建的这个类类型去组合其他的类类型,那么,你现在创建的这种类类型必须是健壮的,通用的,在别人使用的时候不能出任何问题)。电脑类型的状态可能会有重量,价格,品牌,是否开关机,性能好坏等,商品房类型的状态可能会有品牌,楼层,价格,面积、地址/地段,舒适度,采光好坏,朝向等。通过以上举例,你会发现,状态都是尽可能详细的去描述一种类型比较突出的特点,或者说是它本身就具有的属性,但是,你必须明确的是,状态这种叫法是处于面向对象编程思想中的,也就是说,从面向对象编程思想的角度来说,我们称以上内容是对象的状态(因为只有对象才有状态),你用一种类类型的代码去创建一个对象,那么这个对象相对于类类型来说,唯一的区别是以上的状态都将具有具体的或者是结果,比如,创建一个商品房的对象,我们知道,商品房类类型具有品牌,楼层,价格,面积、地址/地段,舒适度,采光好坏,朝向这些状态,那么,创建出来的这个商品房对象其实就是对应具体的一套商品房了,比如,某套房子的品牌恒大楼层25层价格136万面积135m2地址是:赣州市章贡区瑞金路25号1栋2单元1501舒适度舒适采光好坏是好,朝向是:坐北朝南,通过以上这些具体的内容,你是否能在脑海中对这个商品房有一个具体的印象?如果需要你开发一个商品房销售系统,你首先就需要构建一个商品房类类型,然后添加功能就是利用商品房类类型创建一个个的商品房对象出来,有多少套就创建多少套(每套的状态可能都不一样,也可能有的是一样的),再将它们存储进数据库中,这是基本的思路(在这里,你是否能想到,根据这个商品房系统的特殊性,你还能再给这个商品房类类型加一个状态:是否售出),同时,你也能这么理解,一种类的类类型规定了这个类类型对象具有哪些状态(属性),当你创建对象的时候,必须为所有的状态(属性)赋值
那么,从编程代码的角度来说,状态对应的是什么呢?你们也许听说过,叫做变量。也就是说,代码是通过变量来表示状态的(编程思想中是对象,状态,但是编程代码中是类类型,变量,对象与类类型对应,状态与变量对应,这个在实际的编程过程中需要时刻分清楚!),既然说到了代码,那我们就通过具体的代码来举例吧:
下面就创建一个商品房的类类型

// 商品房类型
  public class house{
       //品牌:记得初始化.
       private String pinPai = null;
       //楼层:记得初始化.
       private int louCeng = 0;
       //价格:记得初始化.
       private double jiaGe = 0.0;
       //面积:记得初始化.
       private double mianJi = 0.0;
       //地址:记得初始化.
       private String diZhi = null;
       //舒适度:记得初始化.
       private boolean shuShiDu = false;
       //采光:记得初始化.
       private boolean caiGuang = false;
       //朝向:这里的需求是,需要固定朝向的取值,后期不管创建了多少个对象,朝向的取值都必须
       //在一定的取值范围内,不能有其他的选项。
       //所以这里直接初始化了数组类型的变量caoXiang,它的值一共有6个,分别是:
       //"坐北朝南","正东","正西","正南","正北","其他"
       private String[] caoXiang = {"坐北朝南","正东","正西","正南","正北","其他"};
       //是否售出:记得初始化.
       private boolean inorOut = false;
  }

上面代码的详细解释:
1、品牌,为什么品牌用String类型?因为,品牌是名称,是文本(文字),String类型就是用来保存文本内容的。
2、楼层,为什么楼层用int类型?因为楼层可以用一个整数来表示,不是5楼就是6楼,不会出现5.5楼。
3、价格,为什么价格用double类型,因为价格是以万元为单位,一套房子一般都是几十上百万,比如115.34万(double是浮点数类型)。
4、面积,为什么面积用double类型,因为面积是以m2(平方米)为单位,一般都是在几十到一百多平方米,比如115.34m2
5、地址,为什么地址用String类型,因为地址就是一段文本(文字)表示。
6、舒适度,为什么用boolean呢?在这里,我考虑的比较简单,仅仅考虑了两种情况,舒适(true)和不舒适(false),如果有更多的选项,就需要用数组了,比如:private String[] shuShiDu = {“一般舒适”,“非常舒适”,“100%好评”,“不舒适”,“差评”}
7、采光,为什么用boolean呢?在这里,我也是考虑的比较简单,仅仅考虑了两种情况,采光好(true),和不好(false),如果有更多种情况,可以考虑使用数组。
8、朝向,为什么使用数组呢?因为朝向会有多种选择。数组能同时包括多个选项的取值。
9、是否售出,为什么使用boolean呢?因为只有两种情况,要么已售出(true),要么待售(false)。
那么,代码中这些变量有什么用呢?我们再深入一点,从硬件方面去理解一下。
我这里暂时还没有涉及到创建对象的代码语法和构造函数语法,这里稍微提一下这两个概念,在这里,你只需要知道,他们都是为创建对象服务的就行了。
当你用类类型house的代码去创建一个对象时,Java虚拟机在运行到private String pinPai = null这行代码的时候,会在内存(硬件)中增开一个空间,那么,这个空间是用来干什么的呢?它就是用来存储这个对象的名称为pinPai的变量的值的(其中,这个空间的名字叫pinPai,这个空间允许存储值的类型是String),那么,你初始化的时候用的是null,实际上就是表示了,这个空间目前暂时没有存储任何的值(有的时候你会看到有的人这么写:private String pinPai = ""或者是private String pinPai = " “,这实际上是表示这个空间存储了值,存储的值就是”“或者” “,因为”“和” "与"abc"一样,都是String类型对象!这点非常重要,需要严格区分。),到这里,你应该能理解在代码中它们为什么叫变量了,再来看看这行代码的形式:private String pinPai = null(变量名称为pinPai,变量的值是等号右边的值,如果后面还有代码,是可以按需随意改变这个值的),等号左边的内容都是固定的,不论你后面代码怎么写,都是固定的,无法改变,但是等号右边就不是了,因为等号右边是这个名称为pinPai的空间存储的值,如果后面还有代码的话,这个值是可以按需随意改变的,怎么修改呢?你只需要通过变量名称pinPai就行,比如pinPai = “abc”,这个时候,这个变量名称为pinPai存储的值就是"abc"了。再比如,下一行代码是:pinPai = “bbc”,那么之前的"abc"就被覆盖了,最新存储的值就是"bbc"了。
如下代码所示:

// 变量示例
//声明一个类型为String,名称为pinPai的变量,初始化的值为null.
private String pinPai = null;
//修改变量pinPai的值为abc;
pinPai = "abc";
//再次修改变量pinPai的值为bbc;
pinPai = "bbc";

通过以上相对啰嗦以及详细的解释,你就能明白,编程过程简单总结实际上就是增开足够的内存空间,然后再根据需要去修改内存空间存储的值,以达到计算的目的,得到结果!编程的难点在于:还需要去考虑程序执行效率以及后期的多线程问题,程序流程控制等(就是所谓的if、for、while循环等等)。
house类类型的代码中,除了上面提到的名称为pinPai的变量之外,还有名称louCeng、jiaGe等其他变量,本质与pinPai都是类似的,只是类型不同,这里就不再一一赘述了。
PS:不要单纯的认为计算机的计算就是加减乘除,不只这些,因为它还有其他比数字更复杂的类型和比加减乘除更复杂的操作。
PS:截止目前,代码表示的类类型在实际中都会有具体的参照物,比如房屋,汽车等等,但是越往后,会遇到越来越多看不懂的,晦涩的类类型、对象等,是在实际中找不到参照物的,都是需要用脑子的抽象能力去想象,但是实际上又非常使用,比如翻页管理对象、各种代理对象等。
这里还有一个非常重要的难点需要提示一下,就是硬件内存的类型,了解了硬件内存的类型对以后的编程有很大的帮助,尤其是对Java编程(以下内容我还是秉承尽可能详实的叙述,所以看上去,会有一些啰嗦。)。
硬件内存的类型分为以下五种:
寄存器:寄存器是最快的存储区,它位于不同于其他存储区的地方–处理器内部,同时寄存器的数量及其有限,所以寄存器是根据需求分配,程序无法直接控制(在程序中是感觉不到寄存器存在的迹象的 [在C和C++中允许控制寄存器的分配方式])。
对于寄存器,Java中没有明确的与它对应的操作。
堆栈:位于内存的随机访问存储器中,处理器(CPU)是通过堆栈指针直接控制堆栈的内存分配的,若指针向下移动,就是分配一个新的内存空间,如果指针向上移动,就是释放分配的内存空间,这是一种快速有效的分配方法,它的效率仅次于寄存器。
对应堆栈,Java中有具体的与它对应的操作–回到上文刚提到的变量,基础类型的变量,值是直接存储在堆栈中的,但是类类型的变量,仅仅是它的对象实际地址值存储在堆栈中(对象本身是存储在堆中的),使用对象的时候,需要先访问堆栈,找到对象的地址,然后再去堆中找实际的对象。以上情况存在的根本性原因就是,随着程序代码的执行,堆栈中的内容是不断的变化的,存储在堆栈中的所有内容都必须有一个固定的存活时间,也就是说,代码开始的时候,你可以按需新增堆栈中的空间,无论怎么分配,分配多少都行,但是在你的代码结束以后,堆栈必须是空的,不能再有任何的内容,所以你在后期的Java学习过程中经常会涉及到值传递,对象引用的传递等知识,比如后期提到的方法,在方法里也可以创建变量,但是在这个方法的代码结束以后,这个变量的值是会在这个方法的堆栈中消失的,如果你后面的方法还会用到这个值,你必须将它用其他名称的变量保存起来,这就是传递出去了,叫做值传递,避免多次重复创建,也可以反过来理解,一个变量存储了值以后,它是可以通过传递代替多次创建。对象也是一样的,在实际编程中,如果一个对象可能会被用到多次,那么在第一次创建它以后,它本身是存储在堆中,但是它的地址值是存储在堆栈中的,一旦这个地址值未在它的程序有效范围内传递出来,那么堆中的这个对象,后面的程序将再也无法使用,因为首次创建对象生成的地址值,一旦你未在它消失前传递出来,后期就再也无从知道这个地址值是多少,所以对应的堆中的这个对象要么一直存储在堆中,要么被垃圾回收器回收,这是Java中运行机制的问题,后期如果遇到值传递,引用传递等问题,需要梳理清楚程序的流程,避免最后弄得乱七八糟。
:一种通用的内存池,用于存放所有的Java对象,堆不同于堆栈的好处是,编译器不需要知道存储在堆中的数据到底存活多长时间,因此,存储在堆里有很大的灵活性。当然,为了这种灵活性必须要付出相应的代价:用堆进行存储分配和清理要比用堆栈进行存储分配和清理需要更多的时间。
对应堆,Java中有具体的与它对应的操作–Java中创建的所有对象都是存储在堆中,为什么会有这种机制呢?在堆栈中提到了,存储在堆栈中的所有内容都必须有具体的生存周期,一旦程序代码有效范围一结束,堆栈中一定是空的,那么我们知道,创建一个对象是比较繁琐以及耗时的,如果将对象直接存储在堆栈中,那么只有一种方法,就是需要就创建,需要就创建,如果这样,不仅会降低程序的执行效率,而且,程序容易乱,并且,常常会因为何时销毁对象而感到烦恼[对象之间常常是相互依赖的,一个对象可能会依赖多个对象,如果其中一个被依赖的对象被提前销毁了,程序很可能停止,或者是BUG一堆堆。C和C++中的对象就是存储在堆栈中的],Java中避免了将对象本身存储在堆栈中,改进的方法是将对象的地址值存储在堆栈中,如果你想继续使用对象,没关系,你只需要在这个堆栈内容消失之前将这个对象的地址值传递出来,放入另一个堆栈中就行(也有可能是同一个堆栈中,因为一个堆栈中可以多次存储同一个对象的地址值),这样,你还能继续使用同一个对象(因为有它的地址,你就能在堆中找到它),所以,Java中的对象,如果你程序写的漂亮,基本上所有的对象只需要创建一次就行了(基本类型变量同理,创建一次,如果还需要用,将它传递出来!)。你会发现,Java的堆栈中,存储的都是值,八类基本类型存储的是值,类类型存储的也是一个值(地址值),这样就方便管理了,以上内容也说明,堆实际上就是一个单纯的存储空间,它与程序代码运行无关,存储在它里面的内容并没有所谓的生命周期,所以,之前被垃圾回收机制迷惑过的程序员(垃圾回收器如何判断对象的回收时机?)在这里应该能明白了,垃圾回收机制,可能就是在堆空间快满的时候出来工作一下,如果堆空间充分,它可能一直不会工作。所以,在Java中我们能将精力全部投入到程序功能的实现上面,在C和C++中难处理的问题(C和C++程序员可能一半职业生涯的时间都用在考虑何时销毁对象上了!)被Java很好的解决了。
常量存储:常量值通常直接存放在程序代码内部,这样做是安全的,因为他们永远不会被改变。
对应常量存储,在Java中有具体的操作与它对应,就是关键字final,被final管理的变量,实际上就是常量,它与变量唯一的区别就是,一旦被初始化,后期再也无法改变它的值!
下面,我将再过通过表格来形象地表示堆栈和堆以及它们之间的关系:

堆栈
特点:与程序代码的执行有关,程序执行完毕,内容将被清空!它里面的所有内容在程序代码的执行过程种将会有具体的申明周期,也就是说,它里面的所有内容,都能在程序代码找到创建和销毁的实现 特点:与程序代码的执行无关,它只是一个单纯的存储空间,存储在它里面的内容可以一直存在,你可以在Java的程序代码中找到创建它里面内容的实现,但是销毁是通过Java中的守护线程(垃圾回收器实现的)。
举例 举例
int a = 5:这块堆栈内存的名称是"a",它存储的值是5。 基本类型不存储在堆中。
car c = new car()这是Java中创建对象的方代码实现,这块堆栈内存的名称是c,存储的值是这个car对象在堆中的地址,同时c也称作这个car对象的引用。 Java中创建的所有对象,都存储在堆中。
float b = 5.5f:这块堆栈内存的名称是"b",它存储的值是5.5。 基本类型不存储在堆中。
boolean c = true:这块堆栈内存的名称是"c",它存储的值是true。 基本类型不存储在堆中。

在一个堆栈中,是不能同时声明两个同名的变量的,因为使用变量的时候,都是通过变量的名称来使用,如果变量同名,机器将无法识别!在具体的代码运行过程中,每个方法代码执行都会有一个堆栈,整个类类型代码执行也会由一个堆栈,所以方法内变量名称不受整个类类型代码内变量的限制,它们可以有重名现象。
非RAM存储:数据完全存存活于程序之外,它不受程序的任何控制,在程序没有运行的时候也可以存在,其中两个最基本的例子是流对象和持久化对象(在流对象中,对象转化成字节流,通常被发送给另一台机器,在持久化对象中,对象被存放于磁盘上,因此,即使程序终止,她们仍然可以保持自己的状态,这种存储方式的技巧在于:把对象转化成可以存放在其他媒介上的事物,在需要时,可以恢复成常规的,基于RAM的对象。Java提供了对轻量级持久化的支持,而诸如JDBC和Hibernate则提供了更加复杂的对在数据库中存储和读取对象信息的支持!)
对应非RAM存储,在Java中有具体的操作与它对应,目前我了解到的,最明显的就是在对象序列化操作上,对象序列化操作就是将对象目前所处的状态直接保存,待需要的时候直接恢复,后期博文梳理流知识的时候会详细提及(这里提一点,为什么会出现保留对象状态的需求?可能你在某个轨迹中形成的处于某种状态的对象在后期可能用得到,你要么重现实现它状态的轨迹,要么直接保存当前状态,当然是后者更容易做到,Java中能实现这个功能的类类型在流知识中,官方名称叫做序列化。)!
有关状态的知识点基本就以上那么多了。如果还有其他想了解的,可以留言!
行为: 在这里,我先提出一个问题,是什么改变了变量的值?换句话说就是,是什么改变了对象的状态?只有一个标准的答案,行为行为这个称呼同样是从编程思想角度出发的,那么在代码中,行为对应什么呢?是方法,也就是说,在代码中,只有通过方法才能改变变量的值(在状态中提到的变量值传递和对象地址值传递!)!到这里,我们能完整地概括:一个类类型的代码中,99%只包括两大类:一种是声明变量代码,一种是方法代码,还有1%代码块,实际上,你也可以把它当作是方法(只是它的样子看上去与正宗的方法稍有差异),那么方法来源是什么呢?凭空自己想象吗?不是的,需要根据具体的类类型来,比如汽车类类型,会有什么方法呢?首先想到的是启动(对应实际中先用钥匙点火启动),汽车会有启动的行为吧,还有什么?停止,加速,减速,拐弯,开灯,关灯,以上是比较基本的方法。可能还会有其他个性化方法,这里就不一一举例了。下面我们通过具体的代码来实现一下以上提到的方法。

// 汽车类类型中基础的方法
public class Car{
   //表示汽车速度的变量
   private int Speed = 0;
   //表示汽车转速的变量
   private int Zspeed = 0;
   //表示加速度的变量
   private UpSpeed = 0;
   //表示汽车开关状态的变量
   private boolean light = false;
   //表示汽车可能方向的数组
   private String[] direction = {"东","南","西","北","东南","东北","西南","西北"};
  //启动的方法
  public void start(){
     //在这里,如果需要实现start方法,刚启动是不是表示汽车的速度是0?很明显,
     //需要一个表示速度的变量,表示速度多少。
     this.Speed = 0;   
     //如果稍有常识的是不是知道,汽车除了速度,还会有一个转速?那么是不是需要一个表示转速的变量?
     this.Speed = 800;
  }
  //汽车停止的方法
  public void stop(){
     //在这里,如果要实现stop方法,汽车的速度是0,是不是表示汽车停止了?
     this.Speed = 0;
     //同时,汽车转速是不是也应该是0?
     this。Zspeed = 0;
  }
  //加速
  public void sppedUp(){
     //如果有一些物理常识的,要表示加速,除了提升速度,还有一种叫"加速度"的词。
     //那么这里需要有一个表示加速度的变量,暂且初始化为5吧,表示每秒速度提升5。
     this.UpSeepd = 5;
     //如果调用一次这个方法,速度的值就增加5;
     this.Speed += UpSpeed;
 }
  //减速
  public void speedDown(){
     //与加速的思路是一样的。
     this.UpSpeed = -5;
     this.Speed -= UpSpeed;
 }
  //拐弯
  public void turnDirection(int direction){
      String direction = null;
      direction = this.direction[direciton];
     //这个方法的实现可以有很多思路,更复杂的是具体写一个算法,通过传递方法参数由算法计算得出最终的方向。
     //具体的实现我在这里就不写了。
     //我这里的实现相对来说比较简单。
  }
  //开灯
  public void lightUp(){
    //这里需要有一个表示等开关的状态,因为只有开或者关两种状态.所以可以使用用布尔类型!
    this.light = true;
    //在这里,因为是程序,你可以做一个判断,如果light的值是true,则显示亮灯的图片。
    //这种抽象的方法,只要效果看上去与实际种类似就行。
  }
  //关灯
  public void lightDown(){
    //light的取值与lightUp()方法相反
    this.light = false;
    //在这里,因为是程序,你可以做一个判断,如果light的值是false,则显示不亮灯的图片。
    //这种抽象的方法,只要效果看上去与实际种类似就行。
  }
  //如果你还想到了其他的方法,可以自己尝试去写一写
}

通过以上代码的实现,我们更加印证了,改变状态的确实是方法,更甚至的是,声明一个变量也基本是通过在方法的实现过程种需要它才会去创建。所以,实现一个类类型的代码时,需要先列出它可能存在的方法,在实现方法的过程种,去考虑它需要什么变量。避免声明不必要的变量,浪费内存空间。
实际上,在方法代码范围内,你也是可以单独为这个方法创建多个变量的[变量类型的范围与类类型代码是一样的],当然,也是按需的,超出代码范围(也就是代码的"{}")外,这个变量就无效了,它仅仅在方法体内使用!
以上内容从代码的角度浅谈了面向对象的思想,在下一篇博文种,我将提及有关创建类类型代码所有关键字的作用,有兴趣的可以关注。
在这里,还有一个很重要的点需要说明:因为Java是面向对象的,它本身也提供了很多实用的类类型供开发人员使用,所以,在你需要实现一个方法的时候,首先应该考虑:在Java提供的这些类类型中,是否有能帮助你直接实现你功能的现成的类类型,如果有,就直接创建它的对象,调用它的方法既可,其次,才是你自己去考虑如何通过最基础的方式来实现你的方法[包括变量设置,流程控制,关键字使用,算法实现,加减乘除模运算等等]。
PS:时间有限,有关Java SE的内容会持续更新!今天就先写这么多,如果有疑问或者有兴趣,可以加QQ:2649160693,并注明CSDN,我会就博文中有疑义的问题做出解答。同时希望博文中不正确的地方各位加以指正!

猜你喜欢

转载自blog.csdn.net/ruidianbaihuo/article/details/88803683