《Java从小白到大牛》之第10章 面向对象基础(上)

《Java从小白到大牛》之第10章 面向对象基础(上)

《Java从小白到大牛》纸质版已经上架了!!!
Java从小白到大牛书皮

面向对象是Java最重要的特性。Java是彻底的、纯粹的面向对象语言,在Java中“一切都是对象”。本章将介绍面向对象基础知识。

面向对象概述

面向对象的编程思想:按照真实世界客观事物的自然规律进行分析,客观世界中存在什么样的实体,构建的软件系统就存在什么样的实体。

例如:在真实世界的学校里,会有学生和老师等实体,学生有学号、姓名、所在班级等属性(数据),学生还有学习、提问、吃饭和走路等操作。学生只是抽象的描述,这个抽象的描述称为“类”。在学校里活动是学生个体,即:张同学、李同学等,这些具体的个体称为“对象”,“对象”也称为“实例”。

在现实世界有类和对象,面向对象软件世界也会有,只不过它们会以某种计算机语言编写的程序代码形式存在,这就是面向对象编程(Object Oriented Programming,OOP)。作为面向对象的计算机语言——Java,具有定义类和创建对象等面向对象能力。

面向对象三个基本特性

面向对象思想有三个基本特性:封装性、继承性和多态性。

封装性 {#-0}

在现实世界中封装的例子到处都是。例如:一台计算机内部极其复杂,有主板、CPU、硬盘和内存,而一般用户不需要了解它的内部细节,不需要知道主板的型号、CPU主频、硬盘和内存的大小,于是计算机制造商将用机箱把计算机封装起来,对外提供了一些接口,如鼠标、键盘和显示器等,这样当用户使用计算机就变非常方便。

那么,面向对象的封装与真实世界的目的是一样的。封装能够使外部访问者不能随意存取对象的内部数据,隐藏了对象的内部细节,只保留有限的对外接口。外部访问者不用关心对象的内部细节,使得操作对象变得简单。

继承性 {#-1}

在现实世界中继承也是无处不在。例如:轮船与客轮之间的关系,客轮是一种特殊轮船,拥有轮船的全部特征和行为,即数据和操作。在面向对象中轮船是一般类,客轮是特殊类,特殊类拥有一般类的全部数据和操作,称为特殊类继承一般类。在Java语言中一般类称为“父类”,特殊类称为“子类”。

提示 在有些语言如C++支持多继承,多继承就是一个子类可有多个父类,例如,客轮是轮船也是交通工具,客轮的父类是轮船和交通工具。多继承会引起很多冲突问题,因此现在很多面向对象的语言都不支持多继承。Java语言是单继承的,即只能有一个父类,但Java可以实现多个接口,可以防止多继承所引起的冲突问题。

多态性 {#-2}

多态性是指在父类中成员变量和成员方法被子类继承之后,可以具有不同的状态或表现行为。有关多态性详细解释,请参考12.4节,这里不再赘述。

类是Java中的一种重要的引用数据类型,是组成Java程序的基本要素。它封装了一类对象的数据和操作。

类声明 {#-0}

Java语言中一个类的实现包括:类声明和类体。类声明语法格式如下。

[public][abstract|final] class className [extends superclassName] [implements interfaceNameList] {

//类体

}

其中,class是声明类的关键字,className是自定义的类名;class前面的修饰符public、abstract、final用来声明类,它们可以省略,它们的具体用法后面章节会详细介绍;superclassName为父类名,可以省略,如果省略则该类继承Object类,Object类所有类的根类,所有类都直接或间接继承Object;interfaceNameList是该类实现的接口列表,可以省略,接口列表中的多个接口之间用逗号分隔。

提示 本书语法表示符号约定,在语法说明中,括号([])部分表示可以省略;竖线(|)表示“或关系”,例如abstract|final,说明可以使用abstract或final关键字,两个关键字不能同时出现。


声明动物(Animal)类代码如下:

// Animal.java

public class Animal extends Object {

//类体

}

上述代码声明了动物(Animal)类,它继承了Object类。继承Object类extends Object代码可以省略。

类体是类的主体,包括数据和操作,即成员变量和成员方法。下面就来展开介绍一下。

### 成员变量 {#-1}

声明类体中成员变量语法格式如下:
```java
class className {

[public | protected | private ] [static] [final] type variableName; //成员变量

}

其中type是成员变量数据类型,variableName是成员变量名。type前的关键字都是成员变量修饰符,它们说明如下:

  1. public、protected和private修饰符用于封装成员变量。
  2. static修饰符用于声明静态变量,所以静态变量也称为“类变量”。
  3. final修饰符用于声明变量,该变量不能被修改。

下面看一个声明成员变量示例:

// Animal.java

public class Animal extends Object {

//动物年龄

int age = 1;

//动物性别

public boolean sex = false;

//动物体重

private double weight = 0.0;

}

上述代码中没有展示静态变量声明,有关静态变量稍后会详细介绍。

成员方法 {#-2}

声明类体中成员方法语法格式如下:

class className {

[public | protected | private ] [static] [final | abstract] [native] [synchronized]

type methodName([paramList]) [throws exceptionList] {

//方法体

}

}

其中type是方法返回值数据类型,methodName是方法名。type前的关键字都是方法修饰符,它们说明如下:

  1. public、protected和private修饰符用于封装方法。
  2. static修饰符用于声明静态方法,所以静态方法也称为“类方法”。
  3. final | abstract不能同时修饰方法,final修饰的方法不能在子类中被覆盖;abstract用来修饰抽象方法,抽象方法必须在子类中被实现。
  4. native修饰的方法,称为“本地方法”,本地方法调用平台本地代码(如:C或C++编写的代码),不能实现跨平台。
  5. synchronized修饰的方法是同步的,当多线程方式同步方法时,只能串行地执行,保证是线程安全的。

方法声明中还有([paramList])部分,它是方法的参数列表。throws exceptionList是声明抛出异常列表。

下面看一个声明方法示例:

public class Animal {// extends Object {

//动物年龄

int age = 1;

//动物性别

public boolean sex = false;

//动物体重

private double weight = 0.0;

public void eat() { ①

// 方法体

return; ②

}

int run() { ③

// 方法体

return 10; ④

}

protected int getMaxNumber(int number1, int number2) { ⑤

// 方法体

if (number1 > number2) {

return number1; ⑥

}

return number2;

}

}

上述代码第①、③、⑤行声明了三个方法。方法在执行完毕后把结果返还给它的调用者,方法体包含“return 返回结果值;”语句,见代码第④行的“return 10;”,“返回结果值”数据类型与方法的返回值类型要匹配。如果方法返回值类型为void时,方法体包含“return;”语句,见代码第②行,如果“return;”语句是最后一行则可以省略。

提示 通常return语句通常用在一个方法体的最后,否则会产生编译错误,除非用在if-else语句中,见代码第⑥行。

在程序代码中给类起一个名字是非常重要的,但是有时候会出现非常尴尬的事情,名字会发生冲突,例如:项目中自定义了一个日期类,我为它取名为Date,但是会发现Java SE核心库中还有两个Date,它们分别位于java.util包和java.sql包中。

包作用 {#-0}

在Java中为了防止类、接口、枚举和注释等命名冲突引用了包(package)概念,包本质上命名空间(namespace)[^9]。在包中可以定义一组相关的类型(类、接口、枚举和注释),并为它们提供访问保护和命名空间管理。

在前面提到的Date类名称冲突问题,很好解决,将不同Date类放到不同的包中,我们自定义Date,可以放到自己定义的包com.a51work6中,这样就不会与java.util包和java.sql包中Date发生冲突问题了。

包定义 {#-1}

Java中使用package语句定义包,package语句应该放在源文件的第一行,在每个源文件中只能有一个包定义语句,并且package语句适用于所有类型(类、接口、枚举和注释)的文件。定义包语法格式如下:

package pkg1[.pkg2[.pkg3…]];

pkg1~ pkg3都是组成包名一部分,之间用点(.)连接,它们命名应该是合法的标识符,其次应该遵守Java包命名规范,即全部小写字母。

定义包示例代码如下:

// Date.java文件

package com.a51work6;

public class Date {

}

com.a51work6是自定义的包名,包名一般是公司域名的倒置。

提示 我们公司的域名是51work6.com,倒置后是com.51work6,其中51work6是非法标识符(不能用数字开头),所以com.51work6包名是非法的,于是将包名改为com.a51work6。

如果在源文件中没有定义包,那么类、接口、枚举和注释类型文件将会被放进一个无名的包中,也称为默认包。

定义好包后,包采用层次结构管理这些类型(类、接口、枚举和注释),如图10-1所示是在Eclipse包资源视图中查看包,可见有默认包和com.a51work6包。如果文件系统中查看这些包,会发现如同10-2所示的层次结构,源文件目录是根目录,也是默认包目录,可见其中有一个HelloWorld.java文件。com是文件夹,a51work6子文件夹,在a51work6中包含:Animal.java和Date.java两个文件。Java编译器把包对应于文件系统的目录管理,不仅是源文件,编译之后的字节码文件也采用文件系统的目录管理的。

图10-1 Eclipse包资源视图中查看包

图10-2 文件系统目录与包

包引入 {#-2}

为了能够使用一个包中类型(类、接口、枚举和注释),需要在Java程序中明确引入该包。使用import语句实现引入包,import语句应位于package语句之后,所有类的定义之前,可以有0~n条import语句,其语法格式为:

import package1[.package2…].(类型名|*);

“包名.类型名”形式只引入具体类型,“包名.*”采用通配符,表示引入这个包下所有的类型。但从编程规范的角度提倡明确引入类型名,即“包名.类型名”形式可以提高程序的可读性。

如果需要在程序代码中使用com.a51work6包中Date类。示例代码如下:

// HelloWorld.java文件

import com.a51work6.Date; ①

public class HelloWorld {

public static void main(String[] args) {

Date date = new Date(); ②

System.out.println(date);

}

}

上述代码第②行使用了Date类,需要引入Date所在的包,见代码第①行,import是关键字,代码第①行的import语句采用“包名.类型名”形式。

提示 如果在一个源文件中引入两个相同包名+类型名,见如下代码,代码第②行会发生编译错误。为避免这个编译错误,可以在没有引入包的类型名前加上包名,详见如下代码第②行中的java.util.Date。

// HelloWorld.java文件

import com.a51work6.Date;

//import java.util.Date; ①

public class HelloWorld {

public static void main(String[] args) {

Date date = new Date();

System.out.println(date);

java.util.Date now = new java.util.Date(); ②

System.out.println(now);

}

}

注意 当前源文件与要使用的类型(类、接口、枚举和注释)在同一个包中,可以不用引入包。

常用包 {#-3}

Java SE提供一些常用包,其中包含了Java开发中常用的基础类。这些包有:java.lang、java.io、java.net、java.util、java.text、java.awt和javax.swing。

  1. java.lang包

java.lang包含中包含了Java语言的核心类,如Object、Class、String、包装类和Math等,还有包装类Boolean、Character、Integer、Long、Float和Double。使用java.lang包中的类型,不需要显示使用import语句引入,它是由解释器自动引入。

  1. java.io包

java.io包含中提供多种输入/输出流类,如InputStream、OutputStream、Reader和Writer。还有文件管理相关类和接口,如File和FileDescriptor类以及FileFilter接口。

  1. java.net包

java.net包含进行网络相关的操作的类,如URL、Socket和ServerSocket等。

  1. java.util包

java.util包含一些实用工具类和接口,如集合、日期和日历相关类和接口。

  1. java.text包

java.text包中提供文本处理、日期式化和数字格式化等相关类和接口。

  1. java.awt和javax.swing包

java.awt和javax.swing包提供了Java图形用户界面开发所需要的各种类和接口。java.awt提供是一些基础类和接口,javax.swing提供了一些高级组件。

[^9]: 命名空间,也称名字空间、名称空间等,它表示着一个标识符(identifier)的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他命名空间中。 ——引自于 维基百科 https://zh.wikipedia.org/wiki/命名空间

方法重载(Overload) {#overload}

在第10章介绍字符串时就已经用到过方法重载,这一节详细介绍一下重载。出于使用方便等原因,在设计一个类时将具有相似功能的方法起相同的名字。例如String字符串查找方法indexOf有很多不同版本,如图10-3所示:

图10-3 indexOf方法重载

这些相同名字的方法之所以能够在一个类中同时存在,是因为它们的方法参数列表,调用时根据参数列表调用相应重载方法。

提示 方法重载中参数列表不同的含义是:参数的个数不同或者是参数类型不同。另外,返回类型不能用来区分方法重载。

方法重载示例MethodOverloading.java代码如下:

// MethodOverloading.java文件

package com.a51work6;

class MethodOverloading {

void receive(int i) { ①

System.out.println("接收一个int参数");

System.out.println("i = " + i);

}

void receive(int x, int y) { ②

System.out.println("接收两个int参数");

System.out.printf("x = %d, y = %d \r", x, y);

}

int receive(double x, double y) { ③

System.out.println("接收两个double参数");

System.out.printf("x = %f, y = %f \r", x, y);

return 0;

}

}

// HelloWorld.java文件调用MethodOverloading

package com.a51work6;

public class HelloWorld {

public static void main(String[] args) {

MethodOverloading mo = new MethodOverloading();

//调用void receive(int i)

mo.receive(1); ④

//调用void receive(int x, int y)

mo.receive(2, 3); ⑤

//调用void receive(double x, double y)

mo.receive(2.0, 3.3); ⑥

}

}

MethodOverloading类中有三个相同名字的receive方法,在HelloWorld的main方法中调用MethodOverloading的receive方法。运行结果如下:

接收一个int参数

i = 1

接收两个int参数

x = 2, y = 3

接收两个double参数

x = 2.000000, y = 3.300000

调用哪一个receive方法是根据参数列表决定的。如果参数类型不一致,编译器会进行自动类型转换寻找适合版本的方法,如果没有适合方法,则会发生编译错误。假设删除代码第②行的void receive(int x, int y)方法,代码第⑤行的mo.receive(2, 3)语句调用的是void receive(double x, double y)方法,其中int类型参数(2和3)自动会转换为double类型(2.0和3.0)再调用。

配套视频

http://edu.51cto.com/topic/1246.html

配套源代码

http://www.zhijieketang.com/group/5

与本书免费版对应的还有一个收费版本:

  1. 进入百度阅读电子书

  2. 进入图灵社区电子书
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/101544.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • jquery面试题目_高并发面试题

    jquery面试题目_高并发面试题1.jQuery库中的$()是什么?(答案如下)$()函数是jQuery()函数的别称,乍一看这很怪异,还使jQuery代码晦涩难懂。一旦你适应了,你会爱上它的简洁。$()函数用于将任何对象包裹成jQuery对象,接着你就被允许调用定义在jQuery对象上的多个不同方法。你甚至可以将一个选择器字符串传入$()函数,它会返回一个包含所有匹配的DOM元素数组的jQ…

    2022年8月25日
    8
  • Linux上部署net6应用

    Linux上部署net6应用Python 微信订餐小程序课程视频 https edu csdn net course detail 36074Python 实战量化交易理财系统 https edu csdn net course detail 35475 前言 net6 都出来了 作为一名 net 搬砖工却一直都在 windows 下部署应用 还未尝试过 linux 环境下部署应用 参考福禄网络研发团队的相关博客 学习一下如何将应用部署到 linux 系统 NET5 都来了 你还不知道怎么部署到 linux 最全部署方案 总有一款适合你

    2025年12月16日
    3
  • 用户表的设计_角色和权限管理数据表设计

    用户表的设计_角色和权限管理数据表设计基于角色的访问控制:(javaWeb编程口诀)用户表角色表,用户角色中间表。角色表权限表,角色权限中间表。一个用户可有多个角色,一个角色又可有多个权限。这就是用户-角色-权限授权的模型。为何不直接让用户对应权限?角色=一定数量的权限集合将特定用户的权限封装到一个角色。封装,或者面向对象设计的体现。不足:此时,在用户之上加一个userGroup用户组的概念。可给单个用户授权或特定用户组授权。这样,一次授权,多个用户得到相同权限,此时用户所拥有的权限是用户个人权限+用户所在组权限用户组,用户与角色三者的关系

    2022年9月27日
    4
  • Linux防火墙命令大全「建议收藏」

    Linux防火墙命令大全「建议收藏」原:https://blog.csdn.net/zhang123456456/article/details/781492061、firewalld的基本使用启动:systemctlstartfirewalld查看状态:systemctlstatusfirewalld停止:systemctldisablefirewalld禁用:systemctlstop…

    2022年6月16日
    66
  • EmWin学习课堂_小白EmWin_EmWin快速入门_EmWin动态内存,显示和触摸屏_EmWin基础配置

    EmWin学习课堂_小白EmWin_EmWin快速入门_EmWin动态内存,显示和触摸屏_EmWin基础配置一、先说说什么是EmWin,它就是一款中间软件包,弄好了之后,我们的界面设计就会变得很简单,在电脑GUI_Builder上做一个界面,生成.c文件,复制到自己的工程里面,我们的显示屏就能得到一模一样的功能。二、在我们使用一个带触摸和显示器的系统的时候,首先就是驱动他们,做完了就应该是这样的:也就是说我们的系统首先得有一个带触摸(不带也行)的系统,接着就是把这两个东西和EmWin关联起来…

    2022年10月14日
    1
  • Java虚拟机(JVM)你只要看这一篇就够了![通俗易懂]

    1.Java内存区域与内存溢出异常1.1运行时数据区域根据《Java虚拟机规范(JavaSE7版)》规定,Java虚拟机所管理的内存如下图所示。1.1.1程序计数器内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成如果线程正…

    2022年4月17日
    44

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号