前面介绍子类继承父类的时候,提到了public(公共)和private(私有)两个修饰符,其中public表示它所修饰的实体是允许外部访问的;而private表示它所修饰的实体不允许外部访问,只能在当前类内部访问private成员,即便是子类也不能访问父类的私有成员。这种情况就令人产生了困惑,私人财产当然不会给外人,可是为啥连儿子都无法动用老子的财物呢?看起来public与private的规则不甚合理,毕竟儿子同外人还是有区别的呀,所谓亲疏有别、一家人不说两家话。为此Java设计了新的修饰符名叫protected,意思是受保护的,其实就是给子类们网开一面,凡是被protected修饰的成员,外部仍然不可访问,唯有从当前类派生而来的子类可以访问。那么对于受保护的成员来说,它对外部而言如同私有成员一样不能访问,它对子类而言如同公共成员一样能够访问。
当然,引入protected不仅仅是面子上好看,还带来了实实在在的好处。比如之前编写鸭子类继承鸟类的时候,发现性别名称字段需要由“雄/雌”改为家禽通用的“公/母”,当时尝试了下列的两种写法:
1、在Duck类里面重新定义与父类同名的属性字段sexName,这样没有变更外部对sexName的访问权限,但是需要重写与该字段有关的所有方法。
2、把Bird类的sexName改为使用public修饰,此时新的鸭子类DuckPublic无需全部重写相关方法,但同时外部变得能够直接读写sexName字段,从而破坏了原来Bird类对该字段的良好封装。
既要保持外部的访问权限不变,又要避免子类冗余的方法重载,这两个愿景看似鱼与熊掌不可兼得。现在有了修饰符protected,原本自相矛盾的问题立马迎刃而解,具体的解决步骤说明如下:
首先给Bird类的sexName属性添加protected修饰,表示该字段是受保护的成员属性,只可在本家族内部使用,不可对外部开放。于是改写后的Bird类代码片段如下所示:
//定义一个名叫Bird的鸟类(作为可被其它类继承的基类)
public class Bird {
// 此处省略其它成员的定义……
// 定义鸟的性别名称
//private String sexName; // 与Duck搭配使用
//public String sexName; // 与DuckPublic搭配使用
protected String sexName; // 与DuckProtected搭配使用
// 此处省略其它成员的定义……
}
接着编写与之配套的鸭子类代码DuckProtected,并重载setSexType方法,将sexName字段的取值改为“公”或者“母”。详细的DuckProtected类定义代码示例如下:
// 演示关键字protected的用法
public class DuckProtected extends Bird {
public DuckProtected(String name, int sex) {
super(name, sex, "嘎嘎");
}
public void setSexType(int sexType) {
super.setSexType(sexType);
// 若想对父类的属性直接赋值,又不想对外开放该属性,则可将父类的属性从private改为protected
// 被protected修饰的成员,表示受保护,它允许子类访问,但不允许外部访问。
// 倘若父类的属性被protected修饰,则子类可以直接读写该属性;
// 倘若父类的方法被protected修饰,则子类可以直接读写该方法;
// 所谓读方法,就是方法的调用操作;所谓写方法,就是方法的重载操作。
sexName = (sexType==0) ? "公" : "母";
//super.sexName = (sexType==0) ? "公" : "母";
}
}
注意,被protected修饰的成员属性,对于子类来说可读可写,既能把原值读出来也能把新值写进去。然而被protected修饰的成员方法,又何来所谓的读写操作?确实,方法不像字段,它没有读方法和写方法的概念,只有方法调用和方法重载的说法。那么对于方法而言,方法调用可看作是一种读操作,而方法重载可看作是一种写操作,瞅瞅“重写”二字带着一个“写”字嘛。
从公共的public,到私有的private,再到受保护的protected,正好三个单词都以字母p开头,3p系列这下总算凑齐了吧?可是还有一种情况,就是某个实体不加任何的开放性修饰符。嗯哼,Java居然允许某个东西既非公共又非私有也非受保护,那这东东究竟要给谁使用?不加修饰符的话,其实Java也给它分配了一个默认的开放性,譬如某人在美国出生,他便自动获得了美国国籍;某人在北京出生,理应要获得北京户口,这个国籍或户口即可看成是默认的归属地。拥有北京户口的人,可以优先享受当地的教育、医疗等资源,为的就是他/她是北京人,所以当地资源对他/她够友好。在Java的编程世界之中,“当地”指的是同一个package(代码包),既然大家生活在同一个package的屋檐下面,就应当互相帮助互相爱护。因而未加3p修饰符的实体,表示它属于当地资源,对当地人很友好,凡是有当地户口的都允许访问它。
如此算来,Java实际上存在四种开放性,根据开放程度的大小排序,依次分别为:
public:公共的,允许所有人访问;
无修饰符:友好的,允许当地人访问;
protected:受保护的,允许本家族访问,包括自身及其子类;
private:私有的,只有自身可以访问。