详解Java中的访问控制修饰符
tun(public,protected,default,private)
Java中的访问控制修饰符已经困惑笔者多时,其中较复杂的情况⼀直不能理解透彻。今天下定决⼼,系统、全⾯地研究Java中的访问控制修饰符的所有⽅⾯,并整理成这篇⽂章,希望有同样疑惑的读者读完后能有所收获。如果⽂章中出现错误,欢迎评论指出,共同交流~
说在前⾯:这篇⽂章只研究Java中访问控制修饰符声明类的变量/⽅法的情况。
先抛出结论:
* 成员变量/⽅法的访问权限
* private default protected public
* ⾃⼰包⾃⼰类 √ √ √ √
* ⾃⼰包别的类 √ √ √
* 别的包别的类有继承关系②① √
* 别的包别的类⽆继承关系 √
①:⼦类可以继承,但是不能访问⽗类的成员变量/⽅法(⼀般来说,可以访问就可以继承)。
②:有继承关系说明访问对象所在的类是⽗类。
1. 让我们来看⼀下Java中访问控制修饰符的定义。
Java中,可以使⽤访问控制符来保护对类、变量、⽅法和构造⽅法的访问。
访问的形式有以下四种:
· 某个类的成员变量访问某个类的成员变量
· 某个类的成员变量访问某个类的成员⽅法
harmony是什么意思· 某个类的成员⽅法访问某个类的成员变量
· 某个类的成员⽅法访问某个类的成员⽅法
ps:以下代码均以第三种形式为例,其他形式基本⼀致。
根据访问对象的不同,访问的⽅式⼜可划分为两⼤类:
· 访问对象在同⼀个类,此时可以通过[成员变量/⽅法的名字]直接访问。
class A {
int a = 10;
void printA() {
System.out.println(a);
}
}
printA()要访问a,因为它们在同⼀个类,所以可以通过a直接访问。
· 访问对象在不同类(假设访问对象在类B),此时可以通过声明、初始化B的⼀个对象,通过[对象名.成员变量/⽅法的名字]进⾏访问。ps:这种情况仅限于成员⽅法访问成员变量/⽅法。
class A {
void printB() {
B ob = new B();
System.out.println(ob.b);
}
}
class B {
int b = 10;
}
A中的printB()要访问B中的b,因为它们不在同⼀个类,所以可以在printB()中声明、初始化B的⼀个对象ob,通过ob.b进⾏访问。
此外,当访问对象为静态变量/⽅法时,可以通过[访问对象所在类的类名.成员变量/⽅法的名字]进⾏访问。
class A {
static int a = 10;
int doubleA = A.a * 2;
void printB() {
System.out.println(B.b);
}
}
class B {
static int b = 10;
}
doubleA要访问a,由于a为静态变量,因此可以通过A.a进⾏访问。
A中的printB()要访问B中的b,由于b为静态变量,因此可以通过B.b进⾏访问。
2.结论中提到了包,我们来看⼀下Java中包的定义和作⽤。
为了更好地组织类,Java提供了包机制,⽤于区别类名的命名空间。
包的作⽤
1 把功能相似或相关的类或接⼝组织在同⼀个包中,⽅便类的查找和使⽤。
2 如同⽂件夹⼀样,包也采⽤了树形⽬录的存储⽅式。同⼀个包中的类名字是不同的,不同的包中的类的名字是可以相同
的,当同时调⽤两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
3 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
Java使⽤包(package)这种机制是为了防⽌命名冲突,访问控制,提供搜索和定位类(class)、接⼝、枚举
(enumerations)和注释(annotation)等。
关于包的使⽤⽅法,请参考,在此不详细赘述。
值得注意的是,import关键字引⼊的是class⽂件,⽽⾮java⽂件。
3.结论中还提到了继承,我们来看⼀下Java中继承的定义。
继承是java⾯向对象编程技术的⼀块基⽯,因为它允许创建分等级层次的类。继承可以理解为⼀个对象从另⼀个对象获取属性的过程。
关于继承的细节,请参照,在此不详细赘述。
需要理解的是,⼦类继承⽗类的成员变量/⽅法时,是先访问再继承。因此上⾯访问权限的规则同样适⽤于继承。
在同⼀个包⾥,如果⽗类的某个成员变量/⽅法可以被访问,则该成员变量/⽅法可以被继承。即如果在⼦类成员⽅法中,声明、初始化⽗类的⼀个对象后,可以通过[对象名.成员变量/⽅法a]访问a,则声明、初始化⼦类的⼀个对象后,也⼀定可以通过[对象名.成员变量/⽅法a]访问a。
class A extends B {
void printB() {how r u
B ob = new B();
goawaySystem.out.println(ob.b);
A ob2 = new A();
System.out.println(ob2.b);
}
}
class B {
int b = 10;
}
A继承B,因此A继承B的成员变量b。由于A在printB()中,声明、初始化B的⼀个对象ob后,可以通过ob.b访问b,则声明、初始化A的⼀个对象ob2后,可能通过ob2.b访问b。(可以访问则可以继承)。
然⽽,在不同包⾥,⼦类继承⽗类时,⼦类只能访问⽗类的public型成员变量/⽅法,却能继承⽗类的protected和public型成员变量/⽅
usually的音标
南京大学教务处法。(请看下⾯的例⼦)
值得注意的是,⼦类继承⽗类的成员变量/⽅法,并不意味着这些成员变量/⽅法存在于⼦类,因此不能通过[成员变量/⽅法的名字]直接访问。可以理解为继承⽽来的成员变量/⽅法进⼊了⼦类的异次元(雾)。
当然,如果继承⽽来的成员变量/⽅法被重写,这些成员变量/⽅法就存在于⼦类了,此时可以通过[成员变量/⽅法的名字]直接访问。
此处不讨论多态的情况,请参照。
回到结论,让我们来⼀层层地验证Java中的访问控制修饰符。
/* Stark.java */
package ing;
public class Stark {
private boolean ned;
boolean robb;
感恩的演讲稿protected boolean sansa;
public boolean arya;
void howIsNed() {
System.out.println(ned);
}
}
class Snow {
void whoBastard() {
Stark stark = new Stark();
/
/ System.out.d); 不可访问
System.out.bb);
}
gear motor}
/* Greyjoy.java */
import ing.Stark;复古风英文
public class Greyjoy extends Stark {
void betray() {a of shoes
Stark stark = new Stark();
// System.out.bb); 不可访问
// System.out.println(stark.sansa); 不可访问
Greyjoy greyjoy = new Greyjoy();
// System.out.bb); 不可访问
System.out.println(greyjoy.sansa);
}
}
/* Bolton.java */
import ing.Stark;
public class Bolton {
void flay() {
Stark stark = new Stark();
System.out.println(stark.arya);
}
}
①⾃⼰包⾃⼰类 -- private可访问
Stark中的howIsNed()可以访问Stark中private型的ned。
②⾃⼰包别的类 -- default可访问
Snow中的whoBastard()可以访问Stark中default型的robb,不可以访问Stark中private型的ned。
③别的包别的类有继承关系 -- protected可继承,不可访问
Greyjoy中的betray()可以继承Stark中protected型的sansa,不可以访问Stark中protected型的sansa,也不可以继承和访问Stark中default型的robb。
④别的包别的类⽆继承关系 -- public可访问
Bolton中的flay()可以访问Stark中public型的arya。