访问权限控制又称「隐藏具体实现」,也就是说,我们可以通过它来决定某个类或者类中的成员在程序中的可见范围。例如,被修饰为 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)
欢迎关注微信公众号:扑在代码上的高尔基,所有文章都将同步在公众号上。