Java基础之--访问权限修饰符

文章出自:安卓进阶学习指南
作者:Alex_Zhao
审核者: 麦田哥
完稿日期: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

这三个修饰符控制的访问范围对照表如下:

修饰符当前类同一包内子孙类其他包
publicYYYY
protectedYYYN
defaultYYNN
privateYNNN

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

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

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

final

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

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

static

字面意思:静态的。既然有静态的,那么肯定也会有相应的动态的,这里的静态和动态其实是相对于内存的变化来说的。
一个类在被实例化的时候,JVM 会给它初始化一个内存地址,如果这个类有多个实例,它们的内存地址是不一样的,这即是动态。那么静态就可以理解为它的内存地址是不会变的,被 static 修饰的变量和方法在类被初始化的时候会被分配到一个单独的内存地址中,一旦分配好就不会再变了。这里是说的内存地址不会变,但是它里面的内容或值是可以变的,但是如果前面同时有 final 修饰的话,那么值也是不变的。
针对于这个特性,我们就可以直接用 类名.xxx 的形式来直接调用该类中定义的静态变量和方法,而不是先创建类的实例,再通过实例来访问变量和方法。

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

abstract

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

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

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

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

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

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

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

Samples

上面只是对权限修饰符做了一些基本的理论上的介绍,那么怎么把这些基础理论运用到实际开发中呢,下面用几个具体的例子来说明一下。

  1. 工具类
    在开发中,我们都会使用工具类,将一些经常需要用的,跟实际业务逻辑没什么关系的公共方法单独抽离出来放在一个工具类中,当需要用到其中的某个方法或变量的时候直接调用一下就行了,非常的方便。先来看一段代码:
public final class BarUtils {
    private static final int    DEFAULT_ALPHA = 112;
    private static final String TAG_COLOR     = "TAG_COLOR";
    private static final String TAG_ALPHA     = "TAG_ALPHA";
    private static final int    TAG_OFFSET    = -123;

    /**
     * 获取状态栏高度(px)
     *
     * @return 状态栏高度px
     */
    public static int getStatusBarHeight() {
        Resources resources = Utils.getApp().getResources();
        int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
        return resources.getDimensionPixelSize(resourceId);
    }

//省略若干代码
}

上面的代码是一个状态栏的工具类,类名前有二个修饰符,public 和 final,那么为什么要用这二个修饰符呢?下面来分析下。

首先考虑一个问题,这个类的作用是什么,需要在哪里用?
前面已经说过,这是一个工具类,将一些在开发中需要用到的公共方法抽取出来放在里面,方便调用。所以这个类的作用就是提供一些公共的方法方便开发时调用,哪里会需要用到呢?很多地方都有可能,针对于这二个特性,再结合上面的访问范围表,我们发现,只能使用 public 修饰才合适,其他的都不能满足我们的要求。
那为什么还要加上 final 呢?加了 final 后就不能被继承,类里面的方法也不能被重写。其实不加 final 也是可以的,因为这只是一个工具类,继承它然后去重写它里面的方法其实是没有什么意义的,所以不加也行。只是 JVM 会对被 final 修饰发类,方法和变量进行优化,可以提高性能。(这点我也不是很清楚,,,)

总结

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

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然,我可以为您介绍一些Java基础知识点面试题。以下是一些常见的Java基础知识点面试题及其答案: 1. 什么是JavaJava是一种面向对象的编程语言,具有跨平台特性,可以在不同的操作系统上运行。 2. Java的特点有哪些? Java具有以下特点: - 简单易学:Java语法相对简单,与C++相比更易于学习和使用。 - 面向对象:Java支持面向对象的编程范式,具有封装、继承和多态等特性。 - 跨平台性:Java通过虚拟机(JVM)实现跨平台,一次编写,到处运行。 - 安全性:Java提供了安全机制,如内存管理、异常处理和安全检查等。 - 多线程:Java支持多线程编程,可以实现并发操作。 3. 什么是面向对象编程? 面向对象编程(OOP)是一种编程范式,将数据和操作数据的方法封装在一起,形成对象。对象可以通过定义来创建,定义了对象的属性和行为。 4. Java中的基本数据型有哪些? Java中的基本数据型包括: - 整数型:byte、short、int、long - 浮点数型:float、double - 字符型:char - 布尔型:boolean 5. Java中的包是什么? 包(Package)是Java中用于组织和接口的一种机制。它可以将相关的和接口放在同一个包中,方便管理和使用。 6. 什么是Java访问修饰符? Java访问修饰符用于控制、方法和变量的访问权限。常用的访问修饰符有public、protected、private和默认(没有修饰符)。 7. Java中的异常处理机制是什么? Java中的异常处理机制通过try-catch-finally语句块来实现。当代码可能抛出异常时,可以使用try块来捕获异常,并在catch块中处理异常。finally块中的代码无论是否发生异常都会执行。 8. 什么是Java的多线程? 多线程是指在一个程序中同时执行多个线程,每个线程都是独立的执行流。Java通过Thread和Runnable接口来实现多线程编程。 9. Java中的垃圾回收是什么? Java中的垃圾回收是自动内存管理的一种机制,通过垃圾回收器自动释放不再使用的内存。开发人员无需手动释放内存,可以专注于业务逻辑的实现。 10. 什么是Java的反射机制? Java的反射机制是指在运行时动态地获取的信息并操作的属性和方法。通过反射机制,可以在运行时创建对象、调用方法和访问属性等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值