前面介绍了许多数据类型,除了基本类型如整型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。
早在本系列文章的一开始,便给出了一个如下所示的简单类定义:

package com.donghan.nanjun.dangyang; // 东汉帝国南郡当阳县

public class Maicheng {
}

以上的类定义代码,开头的public表示这个类对外开放,class是类的标识符,Maicheng则是类的名称,其后的左右花括号内部用来填写类的各种成员。现在往类内部添加几个成员属性,把它变成一个有实际意义的事物,就像下面的橘子类代码,定义了橘子的名称、重量、是否成熟、产地等物品特征:

//演示如何定义类的属性
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语言时代的孑遗,还得补充几个成员方法,才配得上高级语言的身份。并且使用成员方法至少有下列几项好处:

1、把属性的读写操作分开。
比如通过get***方法获取某个属性的值,通过set***方法修改某个属性的值,此时属性定义的前缀需要把public改为private,表示该属性不对外开放。以名称字段name为例,新增getName方法用于读取橘子的名称,新增setName方法用于变更橘子的名称,另外把name属性的开放性改为private,修改之后的代码片段如下:

	// 定义了橘子的名称
private String name; // 设置橘子的名称
public void setName(String inputName) {
name = inputName;
} // 获取橘子的名称
public String getName() {
return name;
}

  

2、一个方法可以同时修改多个属性的值。
古人云“橘生淮南则为橘,生于淮北则为枳”,可见橘子的名称与其产地是有关联的,一旦产地字段发生变更,则橘子名称也可能跟着变化。那么依照“橘生淮北则为枳”的规则,可将产地设置方法setPlace更改为以下逻辑:

	// 设置橘子的产地
public void setPlace(String inputPlace) {
place = inputPlace;
if (place.equals("淮北")) {
name = "枳子";
} else {
name = "橘子";
}
}

  

3、一个方法可以同时输出多个属性的值。
当某个类型拥有多个属性的时候,最好能够一次性输出所有属性值。譬如本地日期类型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类型的代码例子:

	// 演示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开发笔记(序)章节目录

Java开发笔记(四十五)成员属性与成员方法的更多相关文章

  1. Java开发笔记(十五)短路逻辑运算的优势

    前面提到逻辑运算只能操作布尔变量,这其实是不严谨的,因为经过Java编程实现,会发现“&”.“|”.“^”这几个逻辑符号竟然可以对数字进行运算.譬如下面的代码就直接对数字分别开展了“与”.“或 ...

  2. Java开发笔记(一百五十)C3P0连接池的用法

    JDBC既制定统一标准兼容了多种数据库,又利用预报告堵上了SQL注入漏洞,照理说已经很完善了,可是人算不如天算,它在性能方面不尽如人意.问题出在数据库连接的管理上,按照正常流程,每次操作完数据库,都要 ...

  3. Java开发笔记(九十五)NIO配套的文件工具Files

    NIO不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具Paths.路径工具Path.文件组工具Files.先看路径组工具Paths,该工具提供了静态方法get,输入某个文件的 ...

  4. Java开发笔记(一百五十一)Druid连接池的用法

    C3P0连接池自诞生以来在Java Web领域反响甚好,业已成为hibenate框架推荐的连接池.谁知人红是非多,C3P0在大型应用场合中暴露了越来越多的局限性,包括但不限于下列几点:1.C3P0管理 ...

  5. Java开发学习(二十五)----使用PostMan完成不同类型参数传递

    一.请求参数 请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数? 关于请求参数的传递与接收是和请求方 ...

  6. Java基础笔记(十五)——封装(续)static关键字

    static 静态的,用static修饰的成员叫静态成员或类成员.类实例化的所有对象都会共用同一块静态空间.一个对象将值改变,其它对象的值也就随之改变了. 如:public static int pr ...

  7. JAVA:类,对象,成员属性,成员方法,构造方法,类变量,类方法<2>

    一.类的定义 一个全面的类定义是比较复杂的,  定义如下:

  8. Java开发笔记(十四)几种运算符的优先级顺序

    到目前为止,我们已经学习了Java语言的好几种运算符,包括算术运算符.赋值运算符.逻辑运算符.关系运算符等基础运算符,并且在书写赋值语句时都没添加圆括号,显然是默认了先完成算术.逻辑.关系等运算,最后 ...

  9. Java学习笔记(十五)——javadoc学习笔记和可能的注意细节

    [前面的话] 这次开发项目使用jenkins做持续集成,PMD检查代码,Junit做单元测试,还会自动发邮件通知编译情况,会将javadoc生成的文档自动发到一个专门的服务器上面,每个人都可以看,所以 ...

  10. Java从零开始学四十五(Socket编程基础)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...

随机推荐

  1. JDK、JRE

    JRE: java Runtime environment (java运行环境) JVM:java virtual machine (java 虚拟机) java程序就在jvm中运行. JDK: ja ...

  2. php 将一个或多个二维数组组合成一个二维数组并根据某个字段排序排序

    最近再写项目的时候,碰到一个问题:如何将一个或多个二维数组组合成一个二维数组并根据某个字段排序排序:实在是想不到哪个php库中有哪个函数能实现,只能自己写一个了,将代码写出来后,发现自己的代码繁琐,并 ...

  3. Mesos源码分析(13): MesosContainerier运行一个Task

    MesosContainerizer的实现在文件src/slave/containerizer/mesos/containerizer.cpp中   Future<bool> MesosC ...

  4. gps 经纬度 转换实际距离

    <!doctype html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...

  5. VUE插件大总结

    UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组件库 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开 ...

  6. 从SQL注入到内网漫游

    前言 在一次渗透实战中,发现了一个注入点,最后成功的漫游了内网. 正文 在渗透中遇到一个站点,顺手测试了一下,在搜索框随便输入了一个字符加个单引号直接报错了,差不多可以确认这里存在注入了.一般这种站安 ...

  7. &和&&的共同点和区别、Java字符含义和Java创建对象的几种方式

    一.&和&&的共同点和区别 1.&和&&的联系(共同点): &和&&都可以用作逻辑与运算符,但是要看使用时的具体条件来决定. 操 ...

  8. Kali学习笔记42:SQL手工注入(4)

    前三篇文章都是在讲发现SQL注入漏洞 如何查询得到所有的信息 那么另一条思路还未尝试过:能否修改数据? 例如这样: '; update users set user='yiqing' where us ...

  9. [Swift]LeetCode170.两数之和III - 数据结构设计 $ Two Sum III - Data structure design

    Design and implement a TwoSum class. It should support the following operations:add and find. add - ...

  10. [Swift]LeetCode647. 回文子串 | Palindromic Substrings

    Given a string, your task is to count how many palindromic substrings in this string. The substrings ...