访问权限控制

访问权限控制又称「隐藏具体实现」,也就是说,我们可以通过它来决定某个类或者类中的成员在程序中的可见范围。例如,被修饰为 public 的元素在全局范围可见,而被修饰为 private 的元素只能可见于类的内部。

Java 的访问权限控制提供了四种不同的访问权限限定词,用于描述元素在程序中的可见范围。下面我们具体来看一看:

包的概念

Java 中最基本的文件单位就是类,每个类文件的文件名不允许重复,以保证类的唯一确定性,但是 Java 中有着成千上万的类,每新建一个类就需要定义一个与之前所有类不同的类名,想必光是找到一个不重复并且有点象征意义的名称就已经弹尽援绝了。

Java 引入包管理机制以解决这个问题,将一部分类圈到一起放入一个「文件夹」中,于是即便不同的文件夹下有着相同类名的类也不会构成冲突,大大降低了类的命名冲突概率。而这里所谓的「文件夹」官方点说,就是包。

而每个类都应该位于一个包下,每当新建一个类的时候,系统就将检索当前包下是否具有重名的类,而不再检索整个类路径。

有了包之后,对于类的定位与引用也发生了变化,一般需要使用「全限定类名」进行唯一确定。例如:java.lang.String,java.util.Date 等

其实对于包的命名并没有明确的约束,只是有一个不成文的惯例:包名称一般由一个域名的逆向顺序构成。例如:com.baidu.Test,net.csdn.Date 等。因为一般域名是唯一不重复的,所以利用域名来命名包的确实一个很好的策略。

所以 import 的作用很简单,就是省略包名,减少不必要的重复。不过它不是万能的,如果你要在一个 Java 文件中同时使用 java.util.Date 和 java.sql.Date 的话,那么 import 就只能适用其中的一个,另一个你还得用完整的类名。

类的访问修饰符

对于类而言,Java 只允许使用两种访问权限限定符进行修饰。(内部类除外)

  • public:被 public 修饰的类,于全局任何位置都是可见的
  • 默认修饰符:默认修饰符是没有具体的关键字对应的,只要你 Class 之前没有修饰符,就使用默认的修饰符,该修饰符指定类于包范围内可见

例如:

//创建一个类,位于包 Class_AccessModefier 下
package Class_AccessModefier;

public class PublicClass {

}
//相同包的其他位置是可以访问的
package Class_AccessModefier;

public class Test {
    public static void main(String[] args){
        PublicClass publicClass = new PublicClass();
    }
}
//不同包下的其他位置也是可以访问的
package Others;

import Class_AccessModefier.PublicClass;

public class Test {
    public static void main(String[] args){
        PublicClass publicClass = new PublicClass();
    }
}

显然,一旦将一个类声明为 public,那么该类将在整个 Java 程序的任何位置可见。

再看一段代码:

package Class_AccessModefier;

class DefaultClass {
    
}
//同包下的其他位置对于该类是可见的
package Class_AccessModefier;

public class Test {
    public static void main(String[] args){
        DefaultClass defaultClass = new DefaultClass();
    }
}
//不同包下无法访问类
package Others;

public class Test {
    public static void main(String[] args){
        //编译器找不到该类
        DefaultClass defaultClass = new DefaultClass();
    }
}

这里我们讨论的都是外部类,并不包含内部类,外部类只允许使用 public 和默认修饰符对类进行访问限定,而内部类会宽泛很多,我们以后再做详细描述。

类成员的访问修饰符

类成员包括类的字段属性和方法,针对它们,Java 中提供了四种不同的限定符限制可见范围。

  • public:被 public 修饰的方法或属性,可见性最高,于任何地方可访问
  • protected:被 protected 修饰的方法或属性,首先是包范围内可见,并且还允许不在同一个包的子类访问,也就是可以被子类继承过去
  • 默认:默认修饰符修饰的方法或属性对于同包下的任何位置是可见的
  • private:外部不可访问,但是该类的内部是可以访问的

我们看一些代码:

//我们定义了四个成员属性,并且具有不同的可见性
public class PublicClass {
    public String name = "hello world";
    protected String sex = "man";
    int age = 23;
    private String tel = "3234234234";
}
//相同包下的访问情况
package Member_AccessModefier;

public class Test {
    public static void main(String[] args){
        PublicClass publicClass = new PublicClass();
        System.out.println(publicClass.name);
        System.out.println(publicClass.age);
        System.out.println(publicClass.sex);
        //编译器报错,不可访问的 tel 属性
        System.out.println(publicClass.tel);
    }
}

public 修饰的属性于任何位置都是可见的,这不用多说。

protected 修饰的 sex 也是可以访问的,原因是我们的 main 函数的 PublicClass 类位于同一个包下,所以自然是可访问的

未加修饰符的 age 属性也是能够被访问的,也是因为 main 函数的 PublicClass 类位于同一个包下

而 private 修饰的 tel 属性则不可见,说明 private 不允许外部的任何位置访问该属性,即便你是我的子类也不行

而同样的代码,我们置放于另一个包中,结果就是不同的:

package Others;

import Member_AccessModefier.PublicClass;

public class Test {
    public static void main(String[] args){
        PublicClass publicClass = new PublicClass();
        System.out.println(publicClass.name);
        //编译器报错,不可访问的 age 属性
        System.out.println(publicClass.age);
        //编译器报错,不可访问的 sex 属性
        System.out.println(publicClass.sex);
        //编译器报错,不可访问的 tel 属性
        System.out.println(publicClass.tel);
    }
}

只有被修饰为 public 的 name 属性是可见的,其他都不可访问。

age 是默认修饰符修饰的,包可见范围,出了包范围即刻不可访问。

sex 是 protected 修饰的,既超出了包的范围,又没有继承目标类,所以不可见。

private 不用说,任何外部位置都不可见。

这里,一旦我们 Test 类继承了 PublicClass ,那么 sex 属性即刻变为可以访问,大家可以试试看。


文章中的所有代码、图片、文件都云存储在我的 GitHub 上:

(https://github.com/SingleYam/overview_java)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

Java字符串之性能优化

在程序中你可能时常会需要将别的类型转化成String,有时候可能是一些基础类型的值。在拼接字符串的时候,如果你有两个或者多个基础类型的值需要放到前面,你需要显式...

10920
来自专栏前端儿

理解运用JS的闭包、高阶函数、柯里化

JS的闭包,是一个谈论得比较多的话题了,不过细细想来,有些人还是理不清闭包的概念定义以及相关的特性。

35430
来自专栏java一日一条

Java字符串之性能优化

在程序中你可能时常会需要将别的类型转化成String,有时候可能是一些基础类型的值。在拼接字符串的时候,如果你有两个或者多个基础类型的值需要放到前面,你需要显式...

13220
来自专栏全沾开发(huā)

一个有味道的函数

一个有味道的函数 最近想到了一个自认为很有意思的面试题 如何实现一个compose函数。 函数接收数个参数,参数均为Function...

383120
来自专栏python3

python While 循环语句

python 编程中 while 语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务。

21310
来自专栏hrscy

Swift2.1-下标脚本下标脚本

类,结构体和枚举可以定义下标脚本,下标脚本可以认为是访问集合(collection),列表或序列的成员元素。你可是使用下标脚本来设置或通过索引检索值,而不需要调...

9230
来自专栏大前端_Web

详解javascript作用域和闭包

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/deta...

13440
来自专栏java一日一条

(转)Java中的System类

System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。

11420
来自专栏ShaoYL

深刻理解----修饰变量----关键字

368110
来自专栏Java开发者杂谈

Ruby(1):入门

安装:   一般来说linux会自动装ruby,可以通过:   ruby -v 来查看ruby版本   直接使用ruby命令的话,是用来执行ruby文件的。如果...

37080

扫码关注云+社区

领取腾讯云代金券