极*Java速成教程 - (3)
Java语言基础
访问权限控制
Java是一个面向对象的语言,当你不是它所设计的要面向的对象时,它就不会给你看你不该看到的东西,也就是“访问权限控制”。
亲疏有别,才能权限控制
包的概念
正如现实世界中有不同的一个个家族,家族中的每个成员都是由其先祖生育而来(仅考虑父系或者是母系一系),Java中的所有类也都是归属于其“家族”,或者用术语来说就是“包(package)”。
包就像Windows系统下的文件夹,一个套着一个,而包中的类就像文件夹中的文件(事实上类和包的物理储存的确是这么进行的,包就是文件夹,类就是文件)。那么就像文件在操作系统中的路径形如C:\Program Files\Common Files\System
一样一层一层地展开,Java的包和类的结构也是形如java.util.Vector
这样的层级形式。这样就起到了命名空间隔离的作用,不用太过担心起名的时候重名的问题了。
包的使用
在代码的第一行,可以使用package xxx.xxx.xxx
这样的形式声明自己属于哪个包。当在其他地方使用的时候,只需要使用import xxx.xxx.*
这样的形式,将包的整体或者是包中的一个类进行导入,就可以在代码中使用了。
在进行包和类的导入的时候,Java编译器会首先在Java安装目录中进行寻找,在安装目录中可以找到官方包,然后会去系统中设定的CLASSPATH
中寻找,CLASSPATH顾名思义,就是自己专门设置的用来放类的地方,最后会在开发路径下进行寻找。当每个地方都找不到的时候,编译器就会报错。
通过import
包和类,就可以起到方便开发的作用,在导入之前如果要使用一个类,就要使用它的全名,就像喊别人“张三的儿子张十三的儿子张二十二的儿子张二十七”一样繁琐。当导入了“张三的儿子张十三的儿子张二十二的儿子”这个命名空间以后,直接喊“张二十七”就可以直接喊到这个人了。
一些问题和麻烦
如果引用的两个包中的不同类重名的时候,就会出现冲突,就像“张三的儿子张十六的儿子张二十七”和“张壹的儿子张二十七”不是一个人一样,直接喊张二十七会带来困扰。Java中如果有同名的类,编译器就会报错,这时就必须使用全名才可以准确地定位到这个类。
如何控制权限
当前用包的方法区分开Java中类的组织结构以后,我们就可以来聊一聊Java的访问控制了
public
这是最为“开放”的权限,被public关键词修饰的成员,将对所有人开放,所有人都可以对其进行访问。
默认权限
当没有添加权限控制关键词是,成员就默认是这个访问权限,只有跟这个成员所属的类同属于同一个包的类,才可以访问到这个对象。相当于是包内的public,包外的不可访问。当类没有描述自己属于哪一个包时,与其同一文件夹下的类将视其为同一个包的类。
protected
被保护的成员,在包内所有其他类都可以访问,在包外只有这个类的子孙才可以访问,就像父亲继承给子女的东西子女都可以使用一样,但是如果没有继承,而是父类的对象的protected成员,那相当于是父亲的东西,子女是不可以使用的。
private
被保护的成员。对于面向对象来说,我们关注的是如何用对象构建程序,也就是对象的属性和行为。至于对象内部是如何运作的,我们是不需要去了解甚至是避免去触碰的,因为那是负责开发那个类的人(或者是精分出的另一个自己)所负责的,不恰当的访问可能会带来难以预料的问题甚至崩溃。而对于负责开发类的人来说,避免让外界的人触碰到自己的成员也是很重要的,所以就有了private关键词。
被这个关键词修饰的成员,将不能被外界所访问。
不给你看,只能我主动说
类的开发者将类内部具体的行为和对象通过权限管理隐藏起来,可以达到保护的作用,不让别人看到内部的实现,也方便了开发者后期对类的内容进行修改,不会给类的使用者带来重新修改代码的麻烦,这就是“封装”。
封装过后,大多数情况下,就只剩下了public关键词修饰的代码可供类的使用者进行访问,这就是类暴露给使用者的“接口”,就仿佛是一个小姑娘,你不能冒昧地直接从人家身上摸出来身份证看看人家多少岁,但是如果小姑娘说你可以问我多大了,那就可以问哪个小姑娘多少岁,虽然年龄这个数据在小姑娘那里是否经过了什么修饰和处理你是不知道的,但是你最后是可以拿到一个年龄的数据的(手斜)。
访问权限对于类也是有效的
- 类只能是public的或者是默认的。
- 对于一个文件来说,里面可以有好几个类,但是只能有一个类是public的,而且这个类必须和文件名同名。
- 如果文件中没有public的类,也就是说文件中所有的类都是默认的权限,那么文件和类的命名是随意的,但是同样的,这个类是只有包内可见的。
- 其他的类可以给这个类提供服务,但是不能是public的。
private的构造器
虽然一般来说,类的构造器得是public的,才能让别人正常创建类的对象,但是在一些特殊的时候,类的构造器是可以是private的。或许一个隐藏起来的构造器比较让人费解,但是有时候,这可以带来一些有趣的用法。
- 提供一个static的方法,在这个方法的内部new一个本类的对象,那么这个类所有的对象就都是通过这个static方法获得的,这可以带来一些比如统计对象数量之类的需求的一些便利。
- 搭配一个private的static的本类的属性变量,然后初始化这个类,并提供一个接口,这个接口返回一个本类的引用,使用者通过接口获取引用并调用其他public的方法,这个在设计模式中叫单例模式,可保证一个类只有一个对象。
复用,拼乐高的艺术
复用,就是一次定义多次使用,Java中的复用包括类的组合和继承。通过复用,可以减少开发的复杂性,在不破坏现有代码的前提下实现代码的重用,增加新的功能。
组合
类是Java的概念组成单元,对象是类的实体,从需求出发,将基本类型等多个对象拼合到一起,就像小块的积木拼成新的形状,构造成新的类,就是类的组合。
继承
继承(extend)就像是你现在有了一个积木变形金刚,但是你觉得这个变形金刚不够威武霸气,所以对它进行修改,扣下来它的外壳拼上新的外壳(重写方法,完全一样的方法名和参数列表,需要在方法名上面一行注明:@Override
),并给他增加新的武器(添加新成员,包括重载成员方法)。
继承同样也受访问控制关键限制,被继承来的父类成员属性和父类成员方法将自动添加到子类中。在子类中可以对继承来的方法和属性进行覆盖(final关键词修饰的除外),重新定义他们的属性,重新描述他们的行为。
如果想在子类继承来的方法中调用父类的方法,可以使用super
关键词,就像this
指的是本类,super
指的是父类。
用继承表达行为间的差异,并用字段表达状态上的变化
初始化
对于继承来说,子类会继承父类的所有接口,兴许还会带来新的属性和方法,而子类的对象,实际上是由一个父类的对象和子类新增的部分结构构成的。而构造器和初始化过程,也是由父类的和子类的两部分构成的。因此,开发者需要做一个新的工作,就是在子类构造时对父类进行构造,当父类使用默认构造器时,Java会自动调用父类的构造方法,但当开发者定义了父类构造器时,就要在子类构造器中使用super关键词调用父类的构造器,完成由深及浅,由父到子的构造过程。
类,是被惰性加载的,只有在初次使用(包括使用static方法)时,它才会被加载,而static对象和代码是在加载时按照定义顺序初始化的。因此,类的初始化的顺序可能是父类静态成员,子类静态成员,父类成员变量,父类构造器,子类成员变量,子类构造器。调用未完全初始化的对象容易出现问题。
对象的清理顺序与初始化顺序相反。
向上转型
这是个历史遗留的名称,有点拗口和令人费解,记住就好。
子类是父类的超集,子类是父类的特例。那么可以这么理解:子类满足父类的一切要求,子类就是一个父类。那么,父类类型的引用名自然可以指向子类,父类类型的参数列表也可以接受子类类型的参数,这些用父类的东西去控制子类的应用,这就是“向上转型”。
final
final表示最终,表示某种意义上的不可修改,因此是要被慎重使用的。
final在数据
被final修饰的数据不可被改变,对于一个基本类型的变量来说,就是这个变量的值不可以被改变,而对于一个对象的引用来说,则是这个对象不可以被改变,这个引用不可以引用到其他的对象,但是这个对象的内容是可以被改变的。
被final修饰的没有对象的空白变量名,必须在声明时或者构造器中被初始化。
在方法的参数列表中出现的final意味着在方法中不可以对这个引用进行修改,对于基本类型来说就是值,对于对象来说就是引用指向的对象。
final在方法
final用来修饰方法时,表示这个方法是最终版本,不能再重写覆盖了。同时final还有一个作用就是将函数嵌入到调用这个函数的地方,省去了调用函数的开销,然而现在的虚拟机已经足够高级学会自动优化了,所以这个用法基本上也不用了。
private方法是隐含final意味的。但在子类中定义一个与父类重名的private方法是被允许的,这样并非覆盖了父类的方法,因为对于子类来说,父类的private方法是不可见不存在的,定义一个同名的方法也是与父类方法毫无关系的。
final在类
用final修饰类,就表明这个类是不可以变动的,是不能有子类不能被继承的。当不希望别人对类的设计进行修改,或者处于安全等考虑时,才考虑将类修饰为final。
何时使用组合,何时使用继承,是一个需要认真思考的问题。
is-a和has-a是大有不同的。当一个类是另一个类的特例,并具有完全一样的方法时,就是is-a,就比如青砖红砖都是砖,那么继承可能是一个更合适的选择(但是绝大多数时候is-like-a是更常见的情况,长得像就可以,防火砖也是砖,虽然它增加了防火的属性和相关方法)。当一个类使用了另一个类的功能而非接口的时候,就是has-a,比如汽车都有方向盘,但是汽车并非是方向盘的继承和扩展,就该使用组合(这时候思考一下本文第一篇举的例子,是不是有一些不合适)。至于真实代码中具体结构的设计,就要根据实际情况进行判断和抉择了。
组合不可以向上转型,继承可以向上转型,在编写程序的时候,应该对此进行思考。
代理
如果说组合太过浅表,继承又太过深入,低层的类与上层的类并没有父子间的密切关系的话,那么还有一种叫“代理”的模式可以选择,其含义就是通过在类中创建低层类的对象,然后在高层类中包装低层类的方法提供调用。
极*Java速成教程 - (3)的更多相关文章
- 极*Java速成教程 - (1)
序言 众所周知,程序员需要快速学习新知识,所以就有了<21天精通C++>和<MySQL-从删库到跑路>这样的书籍,Java作为更"高级"的语言也不应该落后, ...
- 极*Java速成教程 - (2)
Java语言基础 Java的一切都是以对象为基础,对象是生是死的生命周期由虚拟机管理,但是在创生和消亡阶段,需要我们去管理这个类怎么生,怎么死.我们也以此为契机,慢慢接触Java的诸多细节和具体实现. ...
- 极*Java速成教程 - (8)
Java高级特性 注解 注解可以在代码之外添加更多的信息,更加完整地描述程序,帮助编译器进行工作,或者实现某些特定的Java代码之外的功能. 注解可以简化某些重复的流程,自动化那些过程. 注解的使用 ...
- 极*Java速成教程 - (7)
Java高级特性 数组 在Java中,数组是一串连续的,不可改变长度的,对象被固定的,类型固定的连续空间.数组中的随机访问非常迅速,但为了速度放弃了灵活性.而效率也是数组最大的优点. 在使用泛型的容器 ...
- 极*Java速成教程 - (6)
Java高级特性 String String是Java中的字符串类型,字符串类型在内存中是一个不可变的对象.如果要对字符串对象进行修改,如果是较少的修改可以使用+运算符,Java会自动进行优化,但如果 ...
- 极*Java速成教程 - (5)
Java语言基础 容器 这个世界是有序的,将Java对象零散地放到内存中是不符合世界常理的,特别是有一大组相似的甚至不知道有多少数据的时候.把Java对象装进盒子里可以有序收纳,这个盒子就叫容器. 初 ...
- 极*Java速成教程 - (4)
Java语言基础 多态 多态是面向对象的一大重要特性,如果说封装是隐藏一个类怎么做,继承是确定一系列的类做什么,那多态就是通过手段去分离做什么和怎么做. 向上转型与收窄 在开发者将一类事物封装成类以后 ...
- 极·Java速成教程 - (1)
序言 众所周知,程序员需要快速学习新知识,所以就有了<21天精通C++>和<MySQL-从删库到跑路>这样的书籍,Java作为更"高级"的语言也不应该落后, ...
- Java IO教程
1 Java IO 教程 2 Java IO 概述 3 Java IO: 文件 4 Java IO: 管道 5 Java IO: 网络 6 Java IO: 字节和字符数组 7 Java IO: S ...
随机推荐
- "Host 'onlyyou-bridal.jp' is blocked because of many connection errors; unblock with 'mysqladminlush-hosts'"
错误链接数太多 ,清理mysqladminlush-hosts 这个文件 直接 service mysqld restart 解决了~~~ ccess denied for user 'root'@ ...
- jQuery入门教程-CSS样式操作大全
1.获取样式 2.设置样式 3.追加样式 4.移除样式 5.重复切换anotherClass样式 6.判断是否含有某项样式 7.设置 CSS 属性 参数 描述 name 必需.规定 CSS 属性的名称 ...
- python-上传文件的几种方式
from requests_toolbelt import MultipartEncoder import requests # from_data上传文件,注意参数名propertyMessageX ...
- POJ 3261 Milk Patterns ( 后缀数组 && 出现k次最长可重叠子串长度 )
题意 : 给出一个长度为 N 的序列,再给出一个 K 要求求出出现了至少 K 次的最长可重叠子串的长度 分析 : 后缀数组套路题,思路是二分长度再对于每一个长度进行判断,判断过程就是对于 Height ...
- #433 Div2 Problem C Planning (贪心 && 优先队列)
链接 : http://codeforces.com/contest/854/problem/C 题意 : 有 n 架飞机需要分别在 1~n 秒后起飞,允许起飞的时间是从 k 秒后开始,给出每一架飞机 ...
- js解决手机键盘影响定位的问题
// 滑动其他地方隐藏软键盘document.body.addEventListener('touchend', function(evt) { document.activeElement.blur ...
- 前端HTTP缓存
Web 缓存大致可以分为:数据库缓存.服务器端缓存(代理服务器缓存.CDN 缓存).浏览器缓存.其中前端比较关心的是浏览器缓存,包括今天要说的HTTP缓存和前面说过的cookie.localStora ...
- uva live 7637 Balanced String (贪心)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- python3下multiprocessing、threading和gevent性能对比----暨进程池、线程池和协程池性能对比
python3下multiprocessing.threading和gevent性能对比----暨进程池.线程池和协程池性能对比 标签: python3 / 线程池 / multiprocessi ...
- Python编程:从入门到实践—列表
访问列表中的元素 >>> bicycles = ['trek','cannondale','redline','specialized']>>> print(bic ...