Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java 基础之权限修饰符初稿完工 #9

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions java/modifier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
> 文章出自:[安卓进阶学习指南](https://github.com/iwannabetop/Awesome-Android-Learning-Guide)
> 作者:[Alex_Zhao](http://blog.csdn.net/zgh0711)
> 审核者: [麦田哥](https://github.com/wheat7)
> 完稿日期:2017.10.24

在我们每天写的代码中,无论是类还是变量,都少不了修饰符这个东西,所有的修饰符都是 Java 语言规定的关键字。
那么我们每天在使用它们的时候有没有想过以下的几个问题:

- 这个修饰符到底是做什么用的?
- 为什么要使用它?

如果你在使用这些修饰符的时候也考虑过这些问题,或者是对这些修饰符不是很了解,想对它们有一些深入的了解,那么这篇文章或许正式你需要的。如有写的不好或不对的地方,欢迎指正。

## 为何会有访问权限修饰符

我们平时在写代码的时候都会用到一些类库,比如 Java JDK 中自带的公共类库,或者一些第三方的库。使用这些库都可以极大的方便我们的开发,少写很多代码。
类库的开发者将类库提供给其他开发者使用的时候,肯定都不希望自己库的代码可以被人随意的调用(特别是第三方的商业SDK),这些类库一般都只会向外提供一些少量的方法供使用者去调用,而把自己的核心代码藏起来,不让使用者看到和调用。
同时,类库也会面临不断修改升级的问题,如果不加以控制,类库方做任何修改都会直接影响到使用者的程序,这样的话,类库要想修改的话就会非常麻烦。
鉴于以上的问题,Java 在设计的时候就提供了访问权限修饰符这个东西,通过权限来控制类,方法,变量是否能被访问。

## 修饰符都有哪些

### 类修饰符:

**public** :(访问控制符)将一个类声明为公共类,它可以被任何对象访问,一个程序的主类必须是公共类。
**abstract** :将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现。
**final** :将一个类声明为最终类(即非继承类),表示它不能被其他类继承。
**static** :将一个类声明为静态的,仅内部类可以使用此修饰符。

### 成员变量修饰符
**public** :(公共访问控制符)指定该变量为公共的,它可以被任何对象的方法访问。
**protected** :(保护访问控制符)指定该变量可以只被自己的类和子类访问。在子类中可以覆盖此变量。
**private** :(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。
**final** :最终修饰符,指定此变量的值不能变。
**static** :(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类。

### 方法修饰符
**public** :(公共控制符)指定该方法为公共的,它可以被任何对象的方法访问。
**protected** :(保护访问控制符)指定该方法可以被它的类和子类进行访问。
**private** :(私有控制符)指定此方法只能有自己类等方法访问,其他的类不能访问(包括子类)。
**final** :指定该方法不能被重载。
**static**:指定不需要实例化就可以激活的一个方法。

在以上所罗列出的修饰符中,方法和成员变量的修饰符是一样的,都是 public,private,protected,final,static 这五个。所以可以把方法看成是一个特殊的变量。其中 public,private,protected 这三个都是直接限定访问权限的,final,static 则是规定了变量和方法类型。

## public,private,protected
这三个修饰符控制的访问范围对照表如下:

| 修饰符 | 当前类 | 同一包内 | 子孙类 | 其他包 |
| --------- | ---- | ---- | ---- | ---- |
| public | Y | Y | Y | Y |
| protected | Y | Y | Y | N |
| default | Y | Y | N | N |
| private | Y | N | N | N |

看完上面的表格后,相信对于访问权限和修饰符应该有了一个直观的认识。再啰嗦一点,说的直白点就是:

- 如果你想让这个类,方法或变量能够被其他的任何类访问到,那么就给它加上 public 修饰符。
- protected 修饰符,只能用来修饰变量和方法。如果你不想这个变量或方法被其他包里面的类访问到,同时又需要被继承此类的子孙类访问,那么你应该使用 protected 修饰符。
- 而如果不使用任何修饰符的话,也就是默认状态,那么它的访问范围就进一步缩小了,只能是当前类和相同包名下面的类才能访问了,子孙类都是访问不到的。
- 最后一个 private ,它的范围最小,同样是只适用于变量和方法。被它修饰了的话,就只能是同一个类下面的才能访问了,其他任何地方都是没法访问的。

上面把访问权限部分说完了,接着再来说说 final,static 这二个。

## final
首先从字面意思上来理解,最终的。既然是最终的了,那么就是已经定型了,不能再修改了。所以被它所修饰的类,方法和变量都有了相对的特性:

- 被 final 修饰的类是不可以被继承的,因为继承的初衷就是为了能够部分修改,扩展父类的内容,如果父类被 final 定义为了最终版本,那么当然是不能再被修改的了,自然也就不能被继承。
- 被 final 修饰的方法是不可以被重写的,原理同上。
- 被 final 修饰的变量的值是不可以再被改变了的,既然是不可变的,那么就有了另外一个称呼 -- 常量。

## static
字面意思:静态的。既然有静态的,那么肯定也会有相应的动态的,这里的静态和动态其实是相对于内存的变化来说的。
一个类在被实例化的时候,JVM 会给它初始化一个内存地址,如果这个类有多个实例,它们的内存地址是不一样的,这即是动态。那么静态就可以理解为它的内存地址是不会变的,被 static 修饰的变量和方法在类被初始化的时候会被分配到一个单独的内存地址中,一旦分配好就不会再变了。**这里是说的内存地址不会变,但是它里面的内容或值是可以变的,但是如果前面同时有 final 修饰的话,那么值也是不变的。**
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉可以具体说明下 static 和 final 修饰的变量放在哪个内存区

针对于这个特性,我们就可以直接用 类名.xxx 的形式来直接调用该类中定义的静态变量和方法,而不是先创建类的实例,再通过实例来访问变量和方法。

上面是我关于 static 这个修饰符的一个简单的理解,要详细的解释 static 其实涉及到了很多更底层的知识,比如 JVM 初始化一个类的过程,内存中堆,栈的变化等等,限于篇幅这里就不展开了,感兴趣的朋友可以去找下相关的文章学习下。


## abstract
下面来说下最后一个修饰符 abstract,字面意思:抽象的。只能用来修饰类和方法,
被修饰的类里可以有若干抽象方法,也可以没有。抽象类不可以直接实例化,它需要被继承,用它的子类来实例化。
被修饰的方法为抽象方法,抽象方法里面没有具体的实现内容,具体实现内容需要由子类来实现。

在我开始学 Java 的时候,老师说过,**写程序要先从具体到抽象,再从抽象到具体**。这话好深奥,那么到底什么意思呢?举个比较经典的例子:

我们要为学校编写一套程序,来管理全体师生的学习和生活,我们接到任务开始干。首先是老师,老师有各种属性,姓名,年龄等等,然后需要上课,备课等方法;然后是学生,学生也有姓名,年龄等属性,还需要有上课,做作业等方法。
如果是这样按照具体需求来一个个写,没问题,程序可以做出来。但是有没有想过,如果真这么做了,这里面是不是有很多重复的东西,比如老师和学生都有姓名,年龄等属性,也都需要上课。这些属性和方法是一样或者差不多的,如果全部分开写,是不是要写很多个,后面如果要改需求的话,是不是所有地方都要改,这是不是无形中增加了很多工作量,而且容易漏掉和出错。

所以为了程序以后的可维护和可扩展,我们就需要把一些相同或者相似的东西给提取出来(其实也是为了偷懒,所以懒是第一生产力啊,,,),为了达到这个目的,就有了抽象。

那么接着上面的例子,我们先找出老师和学生的共同点,把这些共同点抽取出来。老师和学生都是人吧,人都有姓名,年龄吧,在这个类中,我们可以设置几个抽象方法,分别为设置姓名,年龄,然后还有上课这个行为。这样就抽象出了一个公共类:人。这样就完成了从具体到抽象的过程。

然后在具体使用的时候就需要再从抽象到具体了,就是老师和学生都继承人这个抽象类,继承抽象类之后就需要实现其中的抽象方法(因为抽象类中的方法都没有具体的实现内容,需要由它的子类去具体实现),根据老师和学生不同的特性去实现在抽象类中定义的抽象方法,这也就是从抽象到具体的过程。

从上面例子的整个过程应该就能理解抽象是什么,以及为什么会有抽象这个修饰符了。

## 总结
在这篇文章中,我尽量用浅显易懂的语言来描述了 Java 中的几个非常常用的修饰符的作用,以及他们产生的原因。希望以上的内容能够帮助大家更好的理解权限修饰符这个知识点。

限于篇幅,有些知识点并没有展开。再有就是因为这篇文章其实是偏理论和概念,所以并没有贴出示例代码。有兴趣的可以自己去敲下相应的代码,结合上面的理论知识去验证下是否正确。有什么写的不对的地方欢迎探讨和指正。

最近我和几位小伙伴一同建立了一个项目,[Awesome-Android-Learning-Guide](https://github.com/iwannabetop/Awesome-Android-Learning-Guide) 旨在帮助大家巩固 Java 基础以及 Android 方面的提高和进阶。欢迎大家 star 和 issues,共同成长和进步。