访问控制符

在Java中,一般认为有4种访问控制符,从最严格的到最宽松为private、default、protected、public。这篇文章讨论这四个访问控制符可以用于修饰类(class)、域(field)、方法(method)、构造器(constructor)的情况。除了这四种类型外,接口、enum等也可以使用访问控制符,但是不是每个控制符都能使用。

(在下文中,如果不加说明,类一般指top-level class)

1、 private修饰符

无论是域、方法还是构造器被声明为private,意味着只能在本类中才能使用它们。所谓使用,对于域来说就是访问,方法就是调用,构造器就是新建一个对象。

1.1 private修饰类:

有些地方的文章会说类不能声明为private,理论上来说这是错的。private修饰一个类时,只能用于声明member class(成员类解释),【参考Java8语言规范的8.1.1】这时候只有成员类(member class)的外部类能够实例化这个类(如果这个类可以被实例化,也就是不是抽象类。)。看下面代码(已经通过编译验证):

/**
 * @author Brandon B. Lin
 *
 */
public class Test2 {
	
	public void test() {
		new PrivateClass();
		new PrivateStaticClass();
	}
	
	private class PrivateClass {
		private PrivateClass() {
			
		}
	}
	
	private static class PrivateStaticClass{
		private PrivateStaticClass() {
		}
	}

}

可以看到,成员类可以使用private来修饰,因此它只能在这个类中被实例化(如果可以被实例化)。注意到的是,尽管上面的两个成员类的构造器都是private,依然能够在外部类创建实例,这是嵌套类区别于非嵌套类的一个体现。如果我们在成员类价格abstract,则在其外部类也不能被实例化!有关内部类,一篇很好的英文文章: http://www.learn-java-tutorial.com/inner-classes.cfm


1.2 private修饰构造器:

如果构造器被声明为private,意味着除了本类以外,不能调用构造函数,也就是不能实例化这个类。(注意开头的声明,这里的类指的是top-level class,对于成员类,即使构造器为private,在其外部类一个可以实例化。

private构造器的一个典型应用场景就是单例模式,将构造器声明为private,使得外界不能对该类进行实例化。具体代码如下:

public class Singleton {
	private Singleton() {
		// do something
	}
	
	private static Singleton instance = null;
	
	public static Singleton getInstance() {
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}

}


1.3 private修饰域和方法:

一般情况下,域和方法情况十分类似,因此我们将两者和在一起讨论。private修饰域和方法的时候也很明确,就是这些域不能在类以外被使用,方法不能在类外被调用。域不能在类外被访问并不代表外界无法访问这些域,可以通过get方法对外界提供接口。


2. default修饰符

默认修饰符有时候也称为包访问控制符。

2.1 default修饰类

对于top-level class,不是被public修饰就是没有修饰符,也就是default修饰符。default修饰的top-level类,只能在同一个包中使用,例如被实例化(如果可以被实例化),当然也包括调用静态方法等等其他操作。对于member class,也可以不使用修饰符,也就是default修饰符。如果不使用修饰符,则在同一个包中,可以通过其外部类的实例对象来实例化member class。

2.2 default构造器

如果构造器没有访问控制符,说明在同一个包的范围内,可以使用该类,即实例化这个类。

2.3 default域和方法

没有使用访问控制符的域和方法,可以在包范围内被使用。


3. protected修饰符

3.1 protected class:

如果protected用于修饰类,那只能修饰member class,和private修饰类是一样的。如果一个member class被protected修饰,那么除了在其外部类可以使用这个member class外,外部类的子类也可以使用它(通过外部类的子类的实例)。例如,我们有下面一个类Pkg1Public:

/**
 * @author Brandon B. Lin
 *
 */
public class Pkg1Public {

	private class Pkg1Private {
		
	}
	
	
	protected class Pkg1Protected {
		
	}

}

我们定义了两个成员类,一个为private,一个protected,那么这两个成员类在其外部类,也就是Pkg1Public中都可以被使用。我们再定义一个Pkg1Public类的子类:ExtClass,如下:

/**
 * @author Brandon B. Lin
 *
 */
public class ExtClass extends Pkg1Public {

	public ExtClass() {
		//
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ExtClass ext = new ExtClass();
		Pkg1Protected p = ext.new Pkg1Protected();
		//Pkg1Private p1 = ext.new Pkg1Private();

	}

}

可以看到,被声明为protected的member class可以通过外部类的子类的实例进行使用,而private的成员类则不行(呗注释掉的一行是不合法的。)


3.2 protected修饰构造器

如果一个类的构造器被修饰为protected,那么这个类可以在同一个包或者其子类中被实例化。在同一个包中被实例化容易理解。在子类中被实例化到底什么玩意儿?如果其子类也在同一个包,那一回事。如果子类不在同一个包,那么这个被protected修饰的构造器一样可以被使用,一般通过super来调用。例如,父类代码如下:

/**
 * @author Brandon B. Lin
 *
 */
public class People {

	protected People() {
		
	}
	
}

子类跟父类在不同的package中,代码如下:

/**
 * @author Brandon B. Lin
 *
 */
public class Children extends People {


	public Children() {
		super();
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub


	}


}
在子类的构造器中,可以调用父类的构造器,及super();如果将父类中的构造器protected去掉,变为包访问,则调用super()是错误的,编译通不过。


3.3 protected修饰域和方法

这个相对简单了,被protected修饰的域和方法,除了包访问范围外,在子类也可以被访问,即使在不同的包。不多解释。


4.public修饰符

public意思是全世界都可以使用。

4.1 public修饰class:

没什么可说呀。top-level要么没有修饰符,要么public。而成员类可以被四种访问控制符任何一个修饰,即使使用public修饰member class不是个好的设计。

4.2 public构造器

简单明了,全世界都可以实例化这个类。能够使用构造器进行实例化的前提当然是这个类可以被使用,比如如果这个类使用默认修饰符,那么在其他包中跟你没办法引用这个类(也就是你根本import不进去),也就没办法使用构造器。

4.3 public修饰域和方法

一样简单,全世界都可以。但是需要注意的是,用public修饰一个实例域不是什么好主意,把static或者final static的域限定为public倒是个好想法。我们这里说导出都可以访问,其实不然,比如我们定义一个类,不是public,如下:

/**
 * @author Brandon B. Lin
 *
 */
class Car {

	public static final int wheel=4;
	private String color;
	public Car(String color) {
		this.color = color;
	}
	
	public String getColor() {
		return color;
	}

}

在其他包中,我们根本没办法访问这个Car类,更不用说访问域和方法了。所以也不是全世界都能访问。


初稿暂时这样,日后进一步修改完善,欢迎指错。


版权所有,转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值