前面介绍了许多数据类型,除了基本类型如整型int、双精度型double、布尔型boolean以外,还有高级一些的如包装整型Integer、字符串类型String、本地日期类型LocalDate等等,那么这些数据类型为什么会分红基本和高级两种呢?这与编程语言的发展历程息息相关,像中文、英文这些是人类社会的天然语言,而计算机可以识别的是机器语言,可是机器语言全为以0和1表达的二进制串,看起来仿佛天书通常,读都读不懂,更别说写出来了。为了方便程序员也能操纵计算机,科学家把机器语言所表达的一些常见操做概括起来,分别使用特定的英语单词来代替它们,例如MOV表示移动指令,ADD表示加法指令,SUB表示减法指令,MUL表示乘法指令,DIV表示除法指令等等。那时的数字则放在一个个寄存器中,所谓寄存器指的是某个存储单元,每一个存储单位可保存8位的二进制数,计算机中有八个通用的8位寄存器,分别是AH、AL、BH、BL、CH、CL、DH、DL。对于汇编语言来讲,指令至关于操做符,寄存器至关于变量,此时没有明确的数据类型之分,由于全部数据都是8位二进制数。虽然汇编语言比起机器语言来讲,总算能被程序员看懂了,可是它的表达手段无疑很原始,因此汇编语言属于计算机的低级语言。
然而汇编语言实在是过低级了,每次操做只能处理8位的二进制数,若是须要对很大的数字进行运算,汇编语言就得把大数运算拆分红若干条指令处理。好比300与400相加,因为300和400各需16位二进制数存放,所以它们的加法运算至少要分解为三条加法指令;第一条是两个数字的前面8位相加,第二条是两个数字的后面8位相加,假若第二条加法之和超出255,则第三条还得给第一条的运算结果加一。可见大数相加已然如此繁琐,大数相乘或者相除只会更加麻烦,为了进一步简化汇编语言,科学家又发明了以C语言为表明的中级语言。C语言相对汇编语言的一个显著进步,是把基本数据类型分门别类,推出了整型int、长整型long、浮点型float、双精度型double、布尔型boolean等类型,每种基本类型都有明确的数字表达范围,若在精度要求范围以内开展加减乘除四则运算,只要书写一次带有运算符+、-、*、/的操做语句便可。正由于C语言屏蔽了不一样数字类型在机器存储上的差别,使得程序员可以专一于业务逻辑层面的编码,从而促进了软件行业的飞跃发展。
但是C语言仅仅划分了基本的数据类型,若想处理更复杂的数据,就得定义新的结构体struct来存放复杂数据。这个结构体只是若干基本类型变量的堆砌,对结构体的操做等同于修改它的某个变量值,致使程序代码严重依赖于最初的编码人员,由于一个变量的含义每每只有他才知道,要是换了别人接手,得费老大的劲才能搞清楚某变量的涵义。因而科学家又设计了基于C的C++语言,C++提供了全新的类class意图替代结构体struct,在class这个类里面,变量被称做类的属性,函数被称做类的方法,外部经过类的方法来读写类的属性。这样作的好处是显而易见的,首先方法名能够起个有意义的名称;其次方法拥有输入参数和输出参数,可以处理更多的信息量;再次方法内部容许编写复杂的业务逻辑,而不只限于单纯读写某个属性。如此一来,C++经过类便能定义和处理接近于天然界的事物概念,比如你妈催你找对象,对象可不是几块布缝制而成的洋娃娃,而是有血有肉能说会唱的伊人。C语言的结构体犹如不会动的洋娃娃,C++的类才与活生生的伊人相仿,所以工业界将C++称做面向对象的编程语言,并纳入高级语言的行列。
至于Java语言,则是承继了C++的衣钵,一方面保留了面向对象的精髓,另外一方面去掉了繁琐的指针操做,即所谓的取其精华、去其糟粕。Java中的类一样使用关键字class来表达,类内部的各类要素被称为类的成员,例如类的属性也叫作成员属性,类的方法也叫作成员方法。先前介绍的那些高级类型诸如Integer、String、LocalDate,它们的源码都是经过class定义的,包含的成员属性与成员方法各不相同。譬如Integer拥有一个整型的成员属性,还有包括equals在内的几个成员方法;String拥有一个字符数组的成员属性,还有包括indexOf、replace在内的若干个成员方法;LocalDate拥有整型的年、月、日这三个成员属性,还包括getDayOfMonth、plusMonths、isLeapYear等等成员方法。不过Java开发包提供的高级类型毕竟是有限的,要想知足更加具体的业务需求,则需由程序员本身定义新的数据类型,也就是从头编写新的class。
早在本系列文章的一开始,便给出了一个以下所示的简单类定义:html
package com.donghan.nanjun.dangyang; // 东汉帝国南郡当阳县 public class Maicheng { }
以上的类定义代码,开头的public表示这个类对外开放,class是类的标识符,Maicheng则是类的名称,其后的左右花括号内部用来填写类的各类成员。如今往类内部添加几个成员属性,把它变成一个有实际意义的事物,就像下面的橘子类代码,定义了橘子的名称、重量、是否成熟、产地等物品特征:java
//演示如何定义类的属性 public class OrangeSimple { // 定义了橘子的名称 public String name; // 定义了橘子的重量 public double weight; // 定义了橘子是否成熟。true表示成熟,false表示未成熟 public boolean isRipe; // 定义了橘子的产地 public String place; }
上面的类代码合计定义了橘子的四种属性,接下来外部先利用关键字new建立橘子类的一个实例,再经过形如“实例名.属性名”的格式访问该实例的各个属性,具体的操做代码以下所示:程序员
// 演示OrangeSimple类的调用 private static void testSimple() { // 建立OrangeSimple的一个实例 OrangeSimple orange = new OrangeSimple(); orange.name = "橘子"; // 设置名称属性 orange.place = "淮南"; // 设置产地属性 orange.isRipe = true; // 设置是否成熟的属性 orange.weight = 200; // 设置重量属性 }
但是这个OrangeSimple类只有成员属性,没有成员方法,充其量是C语言时代的孑遗,还得补充几个成员方法,才配得上高级语言的身份。而且使用成员方法至少有下列几项好处:编程
一、把属性的读写操做分开。
好比经过get***方法获取某个属性的值,经过set***方法修改某个属性的值,此时属性定义的前缀须要把public改成private,表示该属性不对外开放。以名称字段name为例,新增getName方法用于读取橘子的名称,新增setName方法用于变动橘子的名称,另外把name属性的开放性改成private,修改以后的代码片断以下:数组
// 定义了橘子的名称 private String name; // 设置橘子的名称 public void setName(String inputName) { name = inputName; } // 获取橘子的名称 public String getName() { return name; }
二、一个方法能够同时修改多个属性的值。
古人云“橘生淮南则为橘,生于淮北则为枳”,可见橘子的名称与其产地是有关联的,一旦产地字段发生变动,则橘子名称也可能跟着变化。那么依照“橘生淮北则为枳”的规则,可将产地设置方法setPlace更改成如下逻辑:编程语言
// 设置橘子的产地 public void setPlace(String inputPlace) { place = inputPlace; if (place.equals("淮北")) { name = "枳子"; } else { name = "橘子"; } }
三、一个方法能够同时输出多个属性的值。
当某个类型拥有多个属性的时候,最好可以一次性输出全部属性值。譬如本地日期类型LocalDate,其内部包含年、月、日三种属性,调用日期实例toString方法,便可返回完整的年月日字符串。对于橘子类型来讲,也可在该类的内部定义一个toString方法,把该类的全部属性值拼接成字符串并返回,就像下面代码示范的那样:函数
// 输出各属性字段的取值 public String toString() { String desc = String.format("这个%s的重量是%f克,%s成熟,产地是%s。", name, weight, isRipe?"已":"未", place); return desc; }
综合上述的几点修改,获得添加了成员方法的OrangeMember类,它的完整定义代码以下所示:编码
//演示类的封装,对成员属性和成员方法的定义 public class OrangeMember { // 定义了橘子的名称 private String name; // 定义了橘子的重量 private double weight; // 定义了橘子是否成熟。true表示成熟,false表示未成熟 private boolean isRipe; // 定义了橘子的产地 private String place; // 设置橘子的产地 public void setPlace(String inputPlace) { place = inputPlace; if (place.equals("淮北")) { name = "枳子"; } else { name = "橘子"; } } // 获取橘子的产地 public String getPlace() { return place; } // 设置橘子的名称 public void setName(String inputName) { name = inputName; } // 获取橘子的名称 public String getName() { return name; } // 设置橘子的重量 public void setWeight(double inputWeight) { weight = inputWeight; } // 获取橘子的重量 public double getWeight() { return weight; } // 设置橘子是否成熟 public void setRipe(boolean inputRipe) { isRipe = inputRipe; } // 获取橘子是否成熟 public boolean getRipe() { return isRipe; } // 输出各属性字段的取值 public String toString() { String desc = String.format("这个%s的重量是%f克,%s成熟,产地是%s。", name, weight, isRipe?"已":"未", place); return desc; } }
而后外部在建立该类的实例以后,便能调用实例的成员方法进行相应操做了。下面是外部使用OrangeMember类型的代码例子:spa
// 演示OrangeMember类的调用 private static void testMember() { // 建立OrangeMember的一个实例 OrangeMember orange = new OrangeMember(); orange.setName("橘子"); // 调用名称设置方法 orange.setPlace("淮南"); // 调用产地设置方法 orange.setRipe(true); // 调用是否成熟的设置方法 orange.setWeight(200); // 调用重量设置方法 // 打印该实例的详细信息 System.out.println(orange.toString()); }
运行上面的例子代码,获得以下的日志信息,可见OrangeMember类的几个成员方法正常工做:设计
这个橘子的重量是200.000000克,已成熟,产地是淮南。
更多Java技术文章参见《Java开发笔记(序)章节目录》