【JAVA进化论】LV2-2:包的定义、类的基本组成、访问权限修饰符
一、包
包说白了就是一个个的文件夹,在java中,所有的类按照其特点,以包的形式进行做区分,包的目录层级命名规则一般是公司的网址倒过来,例如:
如上图所示,.java文件内就是存放的java代码,例如Cat.java文件里面放的就是上一节里那只猫的Cat类的代码,由于现在Cat类有了目录,所以它就需要在头部加上一句话:
1 | package com.bilibili.pet; //这句话位于代码首部,用于标识当前类的java文件在哪个目录下 |
因为Cat有了相对目录,这里就需要加上package
来标记自己所在的目录层级,否则报错。
再回到图1
中,我们看下分包的目的是什么,从图1
可以看到,基础包为com.bilibili(这里提一下,java代码里的包目录引用都是以“.”做分隔的,而不是斜杠),然后基础包下细分了俩包,一个是pet(宠物),一个是human(人类),这俩包下分别有两个java文件,pet下放的是Cat和Dog,而human下放的是Boy和Girl,所以其实包就是用来给类分类的(套娃警告),这里可能会晕,因为之前说过,类是用来描述一类事物的单元,那么既然这样,为啥还需要用目录再分割一层做分类呢?这其实是一个分类大小方向的划分,例如,粗略划分人类包下的类可以包含男生、女生、学生、老师,但是像猫狗明显和人类不是一回事,这时候就需要用一种更高层级的东西来做隔离,包就这样产生了,当然这个是没有绝对标准的,只要你喜欢,可以按照你的方式做分包,比如,你仍然可以认为,pet和human两个包可以合并为biology(生物),因为不管你是人类还是宠物,都是生物,所以对于包的划分,是个“哲学”问题,不过先不用担心,等写的多了,自然就会划分了,这一部分你只需要知道包是个什么东西,以及在存在包目录的情况下类要加package声明头即可。
二、如何使用代码定义一个类?
2.1:类的定义和java文件
上一节已经知道Cat类的代码了,只是没有细说一个类该如何定义,这次我们来讲下类是如何定义的,以及它和java文件是什么关系。
首先,新建一个叫Cat.java的文件,然后在这个文件里写入以下代码:
1 | public class Cat { |
保存,这样一个Cat类就就建好了,诶??就这?
是的,我们来拆解和分析一下这段代码:
public
是一种权限修饰符,可以控制被修饰内容的访问权限,在介绍完类的所有概念之前,不会涉及它的概念,这里只需要记住,一个java文件允许定义多个class,但只允许有一个public类,而且这个public的类名字一定要和这个java文件的命名一致,比如例子里的public的Cat类就定义在Cat.java里,我们还可以在一个java文件里加多个class,但是public的只能有一个。
代码块2
里只是定义了一个空类,通过上一节内容,我们可以知道一个类所包含的内容大概有两大类,一个是属性,一个是方法(也叫函数,我们后面统称方法),所有的类都符合这个结构,类可以不定义任何属性,也可以不定义任何方法,这个没有硬性要求。
2.2:类的属性和方法
上一节介绍过,这一节细分析下。
通过上一节的Cat我们会发现类的属性其实也是各种变量组成的,这种变量在类定义里叫做类的属性
(之前也说过,类本身是一种信息模板,而类产生的对象才是我们需要访问的实际数据),而在类产生的对象里叫做对象的成员变量
,成员变量在对象内部是可以在任意地方随意访问的,比如Cat类里所有方法都是可以直接访问到对象内的成员变量的。成员变量的作用域就是整个类对象,如果别的地方需要用到它们,则需要通过其对应的引用变量
进行访问。
我们现在再把Cat类改造下:
1 | //猫类的定义 |
我们改造了之前的旧方法,让猫的行为根据自己的年龄的不同再次发生改变,此外新增了intro方法用来返回出去自己的简介,plusAge用来增加猫的年龄,getCurrentAge用来返回猫当前的年龄,tooOld使用了private修饰,跟public一样属于访问权限,加了这个访问权限意味着在别的地方通过对象无法调用该方法,只能由对象内部触发调用,后面会着重介绍访问权限修饰符。此外,方法又分为两种,一种是有返回值的,比如getCurrentAge,一种是没有返回值的,比如plusAge,它们的区分方式在于访问权限修饰符public后面是void还是其它类型,如果是void则说明此方法没有返回值,否则就是返回值对应的类型(如int、long,返回结果为引用变量的话,则为对应的类,例如String、Cat等)。
现在拿着这个Cat类来做个试验,我们之前有说过,访问对象里面的方法或者属性时,需要通过引用变量来进行访问,引用变量又是通过初始化类对象来的,初始化类对象之前说过,通过new后面加上构造方法来进行构造一个类对象:
1 | public static void main(String[] args) { |
上方代码块打印:
1 | 我是一只名叫咲川有着白色皮毛的1岁母猫 |
通过这个例子我们会发现:
- 类在产生对象以后,可以利用引用变量来操纵它,具体引用变量可以调用对象的方法,甚至可以直接访问它的属性(能不能访问具体看访问权限修饰符,
public
或private
等,后面讲) - 类在产生对象后,每个对象都持有自己的属性和方法,互不干扰
- 对象内的方法可以访问对象内的任意成员变量以及其他方法(无视访问权限修饰符)
- 对象内某些方法可以改变成员变量的值,比如plusAge,它会重新给自己的成员变量赋值,而有些方法则不会,例如intro,它仅仅是拼接自己内部的成员变量
2.3:构造器
构造器是类里的一个特殊的方法,注意,它也是一个方法,构造器特殊的原因在于它有且仅被触发一次,就是在类构造类对象的时候,一般你定义了一个类如果不写构造器,那就会默认一个构造器,例如代码块2
里,虽然是个空类,但它有一个隐藏的构造器,即:
1 | public class Cat { |
而在代码块4
里的构造器没有省略,因为它是有实际意义的,它的意义在于给成员变量赋值:
1 | //构造方法,用于构造一个类对象 |
通过上面的代码我们可以发现构造器的特点,名称和类名一致,没有标记返回结果的修饰符(void关键词或其他返回类型),且在构造一个对象时必须要通过调用构造方法完成。
三、访问权限修饰符
3.1:访问权限符介绍
在前面所介绍的类定义、类属性定义、类方法的定义的最前端,都会有类似public
、private
这种修饰符,它们的意义和作用是什么呢?
首先我们来介绍一下它们,它们是用来控制访问权限的修饰符,是编译器做访问语法检查时所做的判断依据,一般放到代码首部,可以用来修饰类、类的属性变量、类的方法,用来约定它们的访问权限。
关于表里父子类相关内容需要了解过继承后再去看
ps:这个访问权限,仅仅是根据类定义的上下文来判定的。
单看表和描述是很难发现它们的区别的,现在我们来举个具体的例子,我们现在再来改造下Cat类(修改了一些内容的访问权限,顺带精简了下代码):
1 | public class Cat { |
3.2:举例说明:同一个类
ok,现在让我们基于改造好的Cat类,从第1列的内容试起:
我们在写代码的时候也发现了,同一个类内部的所有属性、方法无视其访问权限,直接获取&访问即可,现在再来试试这样:
由上图可以看到,同一个类定义内,如果存在另外一个相同类产生的对象,仍然可以通过其引用变量无视访问权限进行访问,因为它们属于同一个类,分析如下:
首先cry是Cat类的方法,接收的参数是Cat类产生的引用变量,因此在cry内可以无视访问权限,直接通过cat这个变量访问到所有的内容。
3.3:举例说明:同一个包
我们现在再在同一个包创建一个Test类,在其main方法里做实验:
这是符合预期的,Test和Cat不属于同一个类定义,但它们在同一个包内,因此除了private的内容,均可访问。
3.4:举例说明:同包/不同包的父子类
后面讲继承的时候会讲。
3.5:举例说明:不同包的类
跟3.3
相反,我们现在新建一个跟Cat不同包的Test类,然后用其main方法做实验:
这是符合预期的,Test和Cat不属于同一个类定义,且它们不在同一个包内,因此除了public的内容,均不可访问。