上几篇文章我们讨论了类、成员变量、成员方法、构造方法,对于成员变量来说,它还分为实例变量和静态变量,成员方法也分普通方法和静态方法。声明方法的格式里有个东西叫“访问修饰符”,当时没细讲,这篇我们就详细聊聊它。
之前我们写的程序都有这么一个特点:变量前什么都不写,方法前写个public。那这个public是什么意思呢?从字面上理解,public英文是“公有的”,是一种访问修饰符。其实在java里,访问修饰符除了公有public, 还有另外三类,分别是受保护,英文protected; 默认,不写任何修饰符就代表默认; 以及私有,英文private。怎么理解这些东西呢?大家都知道,每个国家都有机密文件,这些机密文件被妥善的保护,看这些文件的人同样得是身份很特别的人,甭说外国人了,本国人都不能随意浏览。而且文件上会贴有类似“绝密”“无保密”“内部”等标签。访问修饰符就可以想象成这种给予文件权限的标签:
下面我就带着大家一个一个总结它们的特点。先说public。创建一个叫Test.java的文件,然后复制粘贴以下代码:
假设我现在有一个国家机密文件,里面写着国家目标和国家计划。我创建了一个叫Test的类代表该文件,目标用变量countryGoal表示,计划用countryPlan方法表示。修饰符其实不光可以修饰方法,还可以修饰变量,甚至是类。我现在只给变量和方法前面都加上了public,对类暂时用不着,因为只有几个类不在同一文件里时类修饰符才有用。然后我在main函数里声明出了一个对象p1,虽然它只是Test的一个对象,但为了便于理解大家可以把它暂时当成一个人。p1尝试访问国家目标和国家计划,看他/她是否能成功:
最后一行原来是“100年内我大天朝牛b哄哄”改成了“100年内我大中华四夷宾服”,因为觉得把b这个字形容自己的祖国再怎么样听起来也不雅,后面的截图我懒得改了,大家知道就行了。没问题,这个人既可以访问countryGoal,又可以访问countryPlan。所以,我们第一个结论就是:当成员变量或成员方法是public的时候,对象又和它们在同类中,是可以随意被访问的。就好像是权限很低的文件,可以随便看。那不同类中呢?
我把代表文件的那部分代码挪到了Document类中,在Test里声明出了一个Document对象p1。这次p1再次尝试访问国家目标和国家计划,看是否能成功:
没问题,p1还可以访问。如果这两个类在不同文件里呢?之前我们在类、成员变量、成员方法(3)那篇里曾演示过多个类在不同文件中的执行,我也说过好多时候其实都是一个类一个文件,只不过为了方便演示,咱们都放到了一起,仅仅如此。现在咱们就演示一下,如果放在不同的文件中,pulic修饰符会有什么效果。演示之前升级一下我们的开发工具。由于我们的例子比较简单,只需要两个文件就够了,一个放Document类,另一个放Test类。可如果这个项目很大呢?开发目录下是不是会产生好多个.java文件?用记事本就不好管理了。所以从现在开始,我们不再用记事本了,开始用咱们第一篇最后说到的那个工具-Eclipse。有时候我们听别人说IDE这个词,IDE就是integrated development environment,翻译过来就是集成开发工具。Eclipse既帮助我们写代码,也帮助我们维护代码,功能很强大。而且这个工具是开源的,咱们可以直接下载使用。当然,市面上还有别的类似软件,大家可以自行下载试试。
去官网下载最新版eclipse,安装过程比较简单,我就不细说了。双击执行文件打开,一开始需要你填workspace,也就是工作区,意思就是你以后要把项目存到哪个文件夹下。如果一个工作区里还没有任何项目,它会提示个Eclipse的欢迎界面,叉掉之后就是你的工作台:
默认情况下左边是你的项目列表,右边是代码区,下面是运行结果。当然,你如果不喜欢这种布局可以修改。现在我们先新建个项目试试。因为我是英文版,就按英文版的指令走:点击左上角File -> New -> Project打开项目对话框,选择Java Project后点击下一步:
项目名称就输入Documents吧,国家密档嘛。
然后一直下一步到最后,项目就建完了,在这个过程中你能看到Eclipse会把jdk和jre加进去。新建的项目比较空,只有src文件夹和jre library。
现在把Test和Document这两个类加进去,每个类单独占一个文件,所以我们要新建两个.java文件。右键点击src -> new ->class打开类对话框,类名是Document:
看见上图名称下面还有个修饰符那一栏吗?默认它是public的,点击确定会创建一个叫Document.java的文件,并且类名为Document,修饰符是public:
刚才说了,如果几个类都在同一个文件里那没必要用类修饰符。但现在Document和Test不在同一个文件里了,那么它也要受到修饰符的控制。同样步骤创建Test.java,不过勾选上main函数,代表它是主类:
现在的项目是这个样子:
我们发现在项目和java文件中间多了一层,上面写着(default package)这一层是什么呢?我并没有建这么个东西呀?这就引来了我们这篇文章的第二个概念–包,英文叫package。在实际的自动化测试项目里,有些文件是为了储存网页上的控件,有些文件是为了处理逻辑需求,有些文件是为了连接数据库,功能各不相同,所以即便你把各种类区分开写了很多文件,那也得需要根据不同的职责来管理这些文件。咱们的操作系统里都用文件夹来管理文件,而包就相当于java里的文件夹。所以,java使用包的概念来管理类、文件、模块或功能。之前说java其中一个重要部分叫做类库,本质上就是包的一种应用。
如果在创建文件前没创建包,eclipse会自动补上一个默认的包,名字就叫default。包也有自己的命名规则,一般是按照“所在公司的互联网域名.公司名.项目名.模块名”这种格式,每个字段首字母为小写,字段之间用点隔开。比如我要为阿里巴巴的淘宝做项目,我可以把负责测试的模块写到一个包里,包名就是com.alibaba.taobao.tests。
和类名首字母大写或是变量方法首字母小写一样,包的命名规则也是个约定俗成的东西,你说我偏不遵守,也没什么,只不过显得有点不专业,但程序执行上没问题。关于包还有些东西要说,下篇文章我会用字符串举例说说类库,到时大家更能体会到包的作用。
来,咱们把包名改一下,我也不想写得特别复杂,就用com.test吧,意思到了就行,最后做项目实战时我会写得规范点。右键点击src -> New -> Package打开包对话框,输入com.test,点击确定。
之后我们会发现com.test并没有把(default package)取代,没关系,手动把Document.java和Test.java拖拽进去。拖完会惊奇地发现(default package)不见了:
现在把刚才用记事本写的程序复制粘贴进去:
这两个文件都在com.tests包下,现在右键点击Test.java -> Run As -> Java Application执行程序,注意一定要在主类上执行,否则找不到main函数:
运行结果显示正确,没有报错,证明同包下public修饰的变量和方法也可以被访问。那现在就能得出一个结论了:不管在同类还是同包不同类,public修饰的变量和方法都是可以被访问的。
第二个说protected。现在把Document.java里的countryGoal变量和countryPlan方法都改成protected,Test.java不变,然后运行程序,发现还是通过的:
既然在不同文件都可以通过,那相同文件相同类肯定也没问题。所以我又得出一个结论:不管在同类,还是同包不同类,protected修饰的变量和方法也都是可以被访问的。暂时还没看出来public和protected的区别,不过别着急,咱们继续看。
Protected试完咱们试试默认的。把Document.java里的protected移走,什么都不加,就是默认的。Test.java保持原样。运行,还是通过:
这结论不用我说也知道吧?不管在同类,还是同包不同类,默认修饰的变量和方法也都是可以被访问的。有人开始不耐烦了,你tm这是在逗我吧?息怒,一会儿就不同了。
最后用private:
看到了么?Test.java已经提示错误了: countryPlan方法和countryGoal变量都是invisible。什么意思?主函数看不到它们!用对象调用的时候双双不可访问,这就是private私有的意思,屏蔽了,修饰符终于开始发威了。顺便说一句,即使报错也是Eclipse胜过记事本的地方。记事本不会有什么红波浪线提示代码有误,所以一段复杂的程序出了问题用记事本有时很难排错。
这是同包不同类的情况。那我回退一步,试试同类。咱不嫌麻烦,我带着大家一个一个地验证,通过程序的变化大家体验不同修饰符的区别。把Document.java文件里内容再挪到Test.java里,现在Test.java就是这个样子:
这回不报错了,而且执行通过。看来如果在同类中,这个private也没什么威力了。那咱们第四个结论就出来了,用private的时候,同类可访问,同包但不同类的情况下不能访问。
刚才演示的都是同类或同包不同类,那如果不同包呢?不同包时public, private, protected和默认会怎样处理呢?还是从public开始。我们再创建一个包叫com.document,然后把Document.java拖拽进去。此时两个文件的内容修改成下面的样子:
主类Test.java: 创建Document对象用来访问变量和方法
第二个类Document.java: 声明变量和方法用于被访问
这时Eclipse又提示Test.java出错了,问咱们是不是需要import document:
Import的意思是导入,这里面是导入另一个包的信息。为什么需要导入呢?这就是这篇文章的第三个概念:如果java程序分散在不同包中,一个包中的类想要访问另一个包中类的内容则必须导入。导入其实就是把别的包的程序导到我这里来,导进来了不就相当于在同一个包里了嘛。选择导入,这时会在Test.java文件头部多加了import com.document.Document这么一行,同时错误信息也不见了,表明导入成功。现在再运行一下,看看public修饰符还允许不允许通过。告诉大家吧,还是通过,public等级非常低。所以对于public来说,同类,同包不同类,不同包,都可以访问。其实这也是public本身的涵义。公有嘛,谁都可以访问。
现在把public改成protected。我们发现这次不行了,即便包都倒进去了还是提示不可见。试试默认呢?也不行,封得死死的。我们感觉访问修饰符在不同包的情况下威力非常大,各种不可见:
至于private,其实压根不用试,肯定不行,同包不同类都不行,不同包肯定更不行了。所以,再把不同包的情况包括进去,咱们的结论就变成这张表:
变量和方法都遵循这个表上的规则,那类本身呢?也遵守,大家可以课后去实践一下。这个结论不用死记,忘了的话就用我这个方法验证一下就行了。
刚才的所有例子中countryGoal和countryPlan都是同时拥有相同的修饰符的,要么都是public,要么都是private。如果我让它们不一样呢?比如变量countryGoal是private的,countryPlan方法是public的。很明显前者在不同包情况下不可见,后者各种可见。如果我非要在不同包的情况下访问变量countryGoal呢?有没有办法?现在我把这两个文件写成下面这样:
我把countryPlan方法里面加了个字符串返回值,而且返回的正是countryGoal变量。现在执行程序,我们惊奇地发现用private修饰的countryGoal的结果被打印出来了,它竟然可以被访问:
等等,仔细再看看程序,countryGoal现在是在哪儿被访问的?是不是countryPlan方法里边?这么做意味着它不再被Test.java中的Document对象直接访问了,而是间接通过countryPlan方法。countryPlan方法和countryGoal变量在同一个类中,因为同类中private是可见的,所以程序没问题。“方法公有但变量私有,然后通过方法访问变量”这种做法非常普遍,咱们一定要记住。不过现在记不住也没关系,到时候我教大家写项目的时候会经常用这种写法。所以,对于访问修饰符,我们一定要看这个变量或是方法到底在哪儿被访问的,是同类?还是同包?还是不同包?
那有人说你讲这个访问修饰符是干什么的?有什么意义?这就引出了我们这篇文章最后一个知识点 – 封装。前几篇我说得最多的词就是类,对象,还是对象。不管用王思聪咪蒙举例也好,还是自动化的信息配置也好,它们都是对象,对不对?所以,java是一种面向对象的语言,一切都是围绕对象展开。以前我学java的时候老师刚讲类就直接把面向对象这个概念抛出来,又加上是英文授课,一开始一头雾水,后来因为老师毕竟水平高,我才慢慢搞懂。所以我讲的时候就先带大家写几个程序,由浅入深慢慢理解对象这个概念,这时再抛出面向对象大家理解起来就应该容易多了。我不知道你们学没学过别的语言,尤其是C语言,它被称为面向过程语言,没有类和对象这个概念的,没有java方便,这里咱们就不讨论了。
面向对象语言有三大特征,而封装就是第一个特征。你看,这几种访问修饰符,是不是感觉像塑料袋一样把里面的内容封住,或是像墙一样把访问者拒之门外?拒之门外的目的就是为了保证代码的安全性,因为做项目的时候不是所有人都可以对一些特定文件里的类,方法,或是变量随意进行访问。封装就是通过不同的访问修饰符来控制类,变量,方法的可见性,以达到保护代码的目的。
这篇文章的源代码是有10个小项目,分别在DocumentsForDefaultDiffPkgs,DocumentsForDefaultSamePkgDiffClasses,DocumentsForPrivateSameClass,DocumentsForPrivateSamePkgDiffClasses,DocumentsForPrivateValPublicMeth,DocumentsForProtectedDiffPkgs,DocumentsForProtectedSamePkgDiffClasses,DocumentsForPublicDiffPkgs,DocumentsForPublicSameClass,DocumentsForPublicSamePkgDiffClasses)
本篇知识点及注意事项:
1. 访问修饰符结论: 1)不管在同类、同包不同类、不同包,public修饰的变量和方法都是可以被访问的;2)protected和default只可以在同类以及同包不同类之间访问,两者区别讲继承时说;3)private只可以在同类间访问。
2. java使用包的概念来管理类、文件、模块或功能。
3. 如果java程序分散在不同包中,一个包中的类想要访问另一个包中类的内容则必须导入,关键字是import。
4. “方法公有但变量私有,然后通过方法访问变量”这种做法非常普遍,对于访问修饰符,我们一定要看这个变量或是方法到底在哪儿被访问的,是同类?还是同包?还是不同包?