《Java 编程的逻辑》笔记——第3章 类的基础

本文是《Java 编程的逻辑》第三章的读书笔记,重点介绍了类的基本概念,包括类作为数据类型的角色,以及如何定义和使用类。详细探讨了类变量、实例变量、构造方法、生命周期以及包的概念。通过示例展示了如何通过类来表示自定义数据类型,以及如何通过类的组合来表达复杂概念,如图形、电商系统和血缘关系。此外,还讨论了包的作用,如避免命名冲突和代码组织。
摘要由CSDN通过智能技术生成

声明:

本博客是本人在学习《Java 编程的逻辑》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。

本博客已标明出处,如有侵权请告知,马上删除。

开头语

程序主要就是数据以及对数据的操作,为方便理解和操作,高级语言使用数据类型这个概念,不同的数据类型有不同的特征和操作。

Java 定义了八种基本数据类型,四种整型 byte/short/int/long,两种浮点类型 float/double,一种真假类型 boolean,一种字符类型 char,其他类型的数据都用这个概念表达。

3.1 类的基本概念

在第1章,我们暂时将类看做函数的容器,在某些情况下,类也确实基本上只是函数的容器,但类更多表示的是自定义数据类型。我们先从容器的角度,然后从自定义数据类型的角度谈谈类。

3.1.1 函数容器

我们看个例子,Java API 中的类 Math,它里面主要就包含了若干数学函数,表 3-1 列出了其中一些。

在这里插入图片描述

使用这些函数,直接在前面加 Math. 即可,例如 Math.abs(-1) 返回 1。

这些函数都有相同的修饰符,public static。

static 表示类方法,也叫静态方法,与类方法相对的是实例方法。实例方法没有 static 修饰符,必须通过实例或者叫对象(待会介绍)调用,而类方法可以直接通过类名进行调用的,不需要创建实例。

public 表示这些函数是公开的,可以在任何地方被外部调用。与 public 相对的有 private, 如果是 private,表示私有,这个函数只能在同一个类内被别的函数调用,而不能被外部的类调用。在 Math 类中,有一个函数 Random initRNG() 就是 private 的,这个函数被 public 的方法 random() 调用以生成随机数,但不能在 Math 类以外的地方被调用。

将函数声明为 private 可以避免该函数被外部类误用,调用者可以清楚的知道哪些函数是可以调用的,哪些是不可以调用的。类实现者通过 private 函数封装和隐藏内部实现细节,而调用者只需要关心 public 的就可以了。可以说,通过 private 封装和隐藏内部实现细节,避免被误操作,是计算机程序的一种基本思维方式。

除了 Math 类,我们再来看一个例子 Arrays,Arrays 里面包含很多与数组操作相关的函数,表 3-2 列出了其中一些。

在这里插入图片描述

这里将类看做函数的容器,更多的是从语言实现的角度看,从概念的角度看,Math 和 Arrays 也可以看做是自定义数据类型,分别表示数学和数组类型,其中的 public static 函数可以看做是类型能进行的操作。接下来让我们更为详细的讨论自定义数据类型。

3.1.2 自定义数据类型

我们将类看做自定义数据类型,所谓自定义数据类型就是除了八种基本类型以外的其他类型,用于表示和处理基本类型以外的其他数据。

一个数据类型由其包含的属性以及该类型可以进行的操作组成,属性又可以分为是类型本身具有的属性,还是一个具体数据具有的属性,同样,操作也可以分为是类型本身可以进行的操作,还是一个具体数据可以进行的操作。

这样,一个数据类型就主要由四部分组成

  • 类型本身具有的属性,通过类变量体现
  • 类型本身可以进行的操作,通过类方法体现
  • 类型实例具有的属性,通过实例变量体现
  • 类型实例可以进行的操作,通过实例方法体现

不过,对于一个具体类型,每一个部分不一定都有,Arrays 类就只有类方法。

类变量和实例变量都叫成员变量,也就是类的成员,类变量也叫静态变量或静态成员变量。类方法和实例方法都叫成员方法,也都是类的成员,类方法也叫静态方法

类方法我们上面已经看过了,Math 和 Arrays 类中定义的方法就是类方法,这些方法的修饰符必须有 static。下面解释下类变量,实例变量和实例方法。

3.1.2.1 类变量

类型本身具有的属性通过类变量体现,经常用于表示一个类型中的常量。比如 Math 类,定义了两个数学中常用的常量,如下所示:

public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;

E 表示数学中自然对数的底数,自然对数在很多学科中有重要的意义,PI 表示数学中的圆周率 π。与类方法一样,类变量可以直接通过类名访问,如 Math.PI。

这两个变量的修饰符也都有 public static,public 表示外部可以访问,static 表示是类变量。与 public 相对的主要也是 private,表示变量只能在类内被访问。与 static 相对的是实例变量,没有 static 修饰符。

这里多了一个修饰符 final,final 在修饰变量的时候表示常量,即变量赋值后就不能再修改了。使用 final 可以避免误操作,比如说,如果有人不小心将 Math.PI 的值改了,那么很多相关的计算就会出错。另外,Java 编译器可以对 final 变量进行一些特别的优化。所以,如果数据赋值后就不应该再变了,就加 final 修饰符吧。

表示类变量的时候,static 修饰符是必需的,但 public 和 final 都不是必需的

3.1.2.2 实例变量和实例方法

所谓实例,字面意思就是一个实际的例子。实例变量表示具体的实例所具有的属性,实例方法表示具体的实例可以进行的操作。如果将微信订阅号看做一个类型,那"老马说编程"订阅号就是一个实例,订阅号的头像、功能介绍、发布的文章可以看做实例变量,而修改头像、修改功能介绍、发布新文章可以看做实例方法。与基本类型对比,“int a;” 这个语句,int 就是类型,而 a 就是实例。

接下来,我们通过定义和使用类,来进一步理解自定义数据类型。

3.1.3 定义第一个类

我们定义一个简单的类,表示在平面坐标轴中的一个点,代码如下:

class Point {
   
    public int x;
    public int y;
    
    public double distance(){
   
        return Math.sqrt(x*x+y*y);
    }
}

我们来解释一下:

public class Point

表示类型的名字是 Point,是可以被外部公开访问的。这个 public 修饰似乎是多余的,不能被外部访问还能有什么用?在这里,确实不能用 private 修饰 Point。但修饰符可以没有(即留空),表示一种包级别的可见性,我们后续章节介绍,另外,类可以定义在一个类的内部,这时可以使用 private 修饰符,我们也在后续章节介绍。

public int x;
public int y;

定义了两个实例变量,x 和 y,分别表示 x 坐标和 y 坐标,与类变量类似,修饰符也有 public 或 private 修饰符,表示含义类似,public 表示可被外部访问,而 private 表示私有,不能直接被外部访问,实例变量不能有 static 修饰符。

public double distance(){
   
    return Math.sqrt(x*x+y*y);
}

定义了实例方法 distance,表示该点到坐标原点的距离。该方法可以直接访问实例变量 x 和 y,这是实例方法和类方法的最大区别。实例方法直接访问实例变量,到底是什么意思呢?其实,在实例方法中,有一个隐含的参数,这个参数就是当前操作的实例自己,直接操作实例变量,实际也需要通过参数进行。

实例方法和类方法更多的区别如下所示:

  • 类方法只能访问类变量,但不能访问实例变量,可以调用其他的类方法,但不能调用实例方法
  • 实例方法既能访问实例变量,也可以访问类变量,既可以调用实例方法,也可以调用类方法

关于实例方法和类方法更多的细节,后续会进一步介绍。

3.1.4 使用第一个类

定义了类本身和定义了一个函数类似,本身不会做什么事情,不会分配内存,也不会执行代码。方法要执行需要被调用,而实例方法被调用,首先需要一个实例。实例也称为对象,我们可能会交替使用

下面的代码演示了如何使用:

public static void main(String[] args) {
   
    Point p = new Point();
    p.x = 2;
    p.y = 3;
    System.out.println(p.distance());
}

我们解释一下:

Point p = new Point();

这个语句包含了 Point 类型的变量声明和赋值,它可以分为两部分:

Point p;
p = new Point();

Point p 声明了一个变量,这个变量叫 p,是 Point 类型的。这个变量和数组变量是类似的,都有两块内存,一块存放实际内容,一块存放实际内容的位置。声明变量本身只会分配存放位置的内存空间,这块空间还没有指向任何实际内容。因为这种变量和数组变量本身不存储数据,而只是存储实际内容的位置,它们也都称为引用类型的变量。

p = new Point(); 创建了一个实例或对象,然后赋值给了 Point 类型的变量 p,它至少做了两件事

  1. 分配内存,以存储新对象的数据,对象数据包括这个对象的属性,具体包括其实例变量 x 和 y。
  2. 给实例变量设置默认值,int 类型默认值为 0。

与方法内定义的局部变量不同,在创建对象的时候,所有的实例变量都会分配一个默认值,这与在创建数组的时候是类似的,数值类型变量的默认值是 0,boolean 是 false, char 是 ‘\u0000’,引用类型变量都是 null,null 是一个特殊的值,表示不指向任何对象。这些默认值可以修改,我们待会介绍。

p.x = 2;
p.y = 3;

给对象的变量赋值,语法形式是:<对象变量名>.<成员名>

System.out.println(p.distance());

调用实例方法 distance,并输出结果,语法形式是:<对象变量名>.<方法名>。实例方法内对实例变量的操作,实际操作的就是 p 这个对象的数据。

我们在介绍基本类型的时候,是先定义数据,然后赋值,最后是操作,自定义类型与此类似:

  • Point p = new Point(); 是定义数据并设置默认值
  • p.x = 2; p.y = 3; 是赋值
  • p.distance() 是数据的操作

可以看出,对实例变量和实例方法的访问都通过对象进行,通过对象来访问和操作其内部的数据是一种基本的面向对象思维。本例中,我们通过对象直接操作了其内部数据 x 和 y,这是一个不好的习惯,一般而言,不应该将实例变量声明为 public,而只应该通过对象的方法对实例变量进行操作。原因也是为了减少误操作,直接访问变量没有办法进行参数检查和控制,而通过方法修改,可以在方法中进行检查。

3.1.5 变量默认值

之前我们说,实例变量都有一个默认值,如果希望修改这个默认值,可以在定义变量的同时就赋值,或者将代码放入初始化代码块中,代码块用 {} 包围,如下面代码所示:

int x = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bm1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值