A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 Silent_memory 于 2014-4-17 17:00 编辑

上一篇讲到关于继承的一些基本东西,下面介绍和继承紧密相关的三个东西:构造器、protected关键字、向上转型。

  构造器

  通过前面我们知道子类可以继承父类的属性和方法,除了那些private的外还有一样是子类继承不了的---构造器。对于构造器而言,它只能够被调用,而不能被继承。 调用父类的构造方法我们使用super()即可。

  对于子类而已,其构造器的正确初始化是非常重要的,而且当且仅当只有一个方法可以保证这点:在构造器中调用父类构造器来完成初始化,而父类构造器具有执行父类初始化所需要的所有知识和能力。

  1. <font color="#00ff">public</font><font color="#000"> class Person {
  2.     protected </font><font color="#00ff">String</font><font color="#000"> name;
  3.     protected </font><font color="#00ff">int</font><font color="#000"> age;
  4.     protected </font><font color="#00ff">String</font><font color="#000"> sex;
  5.    
  6.     Person(){
  7.         System.out.println(</font><font color="#8000">"</font><font color="#8000">Person Constrctor...</font><font color="#8000">"</font><font color="#000">);
  8.     }
  9. }

  10. </font><font color="#00ff">public</font><font color="#000"> class Husband extends Person{
  11.     </font><font color="#00ff">private</font><font color="#000"> Wife wife;

  12.     Husband(){
  13.         System.out.println(</font><font color="#8000">"</font><font color="#8000">Husband Constructor...</font><font color="#8000">"</font><font color="#000">);
  14.     }
  15.    
  16.     </font><font color="#00ff">public</font><font color="#000"> static void main(</font><font color="#00ff">String</font><font color="#000">[] args) {
  17.         Husband husband  </font><font color="#000">=</font><font color="#000"> </font><font color="#00ff">new</font><font color="#000"> Husband();
  18.     }
  19. }

  20. Output:
  21. Person Constrctor...
  22. Husband Constructor...</font>
复制代码


  通过这个示例可以看出,构建过程是从父类“向外”扩散的,也就是从父类开始向子类一级一级地完成构建。而且我们并没有显示的引用父类的构造器,这就是java的聪明之处:编译器会默认给子类调用父类的构造器。

但是,这个默认调用父类的构造器是有前提的:父类有默认构造器。如果父类没有默认构造器,我们就要必须显示的使用super()来调用父类构造器,否则编译器会报错:无法找到符合父类形式的构造器。

  1. <font color="#00ff">public</font><font color="#000"> class Person {
  2.     protected </font><font color="#00ff">String</font><font color="#000"> name;
  3.     protected </font><font color="#00ff">int</font><font color="#000"> age;
  4.     protected </font><font color="#00ff">String</font><font color="#000"> sex;
  5.    
  6.     Person(</font><font color="#00ff">String</font><font color="#000"> name){
  7.         System.out.println(</font><font color="#8000">"</font><font color="#8000">Person Constrctor-----</font><font color="#8000">"</font><font color="#000"> </font><font color="#000">+</font><font color="#000"> name);
  8.     }
  9. }

  10. </font><font color="#00ff">public</font><font color="#000"> class Husband extends Person{
  11.     </font><font color="#00ff">private</font><font color="#000"> Wife wife;

  12.     Husband(){
  13.         super(</font><font color="#8000">"</font><font color="#8000">chenssy</font><font color="#8000">"</font><font color="#000">);
  14.         System.out.println(</font><font color="#8000">"</font><font color="#8000">Husband Constructor...</font><font color="#8000">"</font><font color="#000">);
  15.     }
  16.    
  17.     </font><font color="#00ff">public</font><font color="#000"> static void main(</font><font color="#00ff">String</font><font color="#000">[] args) {
  18.         Husband husband  </font><font color="#000">=</font><font color="#000"> </font><font color="#00ff">new</font><font color="#000"> Husband();
  19.     }
  20. }

  21. Output:
  22. Person Constrctor</font><font color="#000">-----</font><font color="#000">chenssy
  23. Husband Constructor...</font>
复制代码


  所以综上所述:对于继承而已,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要显示的指定父类的构造器,而且必须是在子类构造器中做的第一件事(第一行代码)。

  protected关键字
  private访问修饰符,对于封装而言,是最好的选择,但这个只是基于理想的世界,有时候我们需要这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到protected。
  对于protected而言,它指明就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他却是可以访问的。
  1. public class Person {
  2.     private String name;
  3.     private int age;
  4.     private String sex;

  5.     protected String getName() {
  6.         return name;
  7.     }

  8.     protected void setName(String name) {
  9.         this.name = name;
  10.     }

  11.     public String toString(){
  12.         return "this name is " + name;
  13.     }
  14.    
  15.     /** 省略其他setter、getter方法 **/
  16. }

  17. public class Husband extends Person{
  18.     private Wife wife;

  19.     public  String toString(){
  20.         setName("chenssy");    //调用父类的setName();
  21.         return  super.toString();    //调用父类的toString()方法
  22.     }

  23.     public static void main(String[] args) {
  24.         Husband husband = new Husband();
  25.         
  26.         System.out.println(husband.toString());
  27.     }
  28. }

  29. Output:
  30. this name is chenssy
复制代码


  从上面示例可以看书子类Husband可以明显地调用父类Person的setName()。
  诚然尽管可以使用protected访问修饰符来限制父类属性和方法的访问权限,但是最好的方式还是将属性保持为private(我们应当一致保留更改底层实现),通过protected方法来控制类的继承者的访问权限。
  向上转型
  在上面的继承中我们谈到继承是is-a的相互关系,猫继承与动物,所以我们可以说猫是动物,或者说猫是动物的一种。这样将猫看做动物就是向上转型。如下:
  1. public class Person {
  2.     public void display(){
  3.         System.out.println("Play Person...");
  4.     }
  5.    
  6.     static void display(Person person){
  7.         person.display();
  8.     }
  9. }

  10. public class Husband extends Person{
  11.     public static void main(String[] args) {
  12.         Husband husband = new Husband();
  13.         Person.display(husband);      //向上转型
  14.     }
  15. }
复制代码


  在这我们通过Person.display(husband)。这句话可以看出husband是person类型。
  将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。由于向上转型是从一个叫专用类型向较通用类型转换,所以它总是安全的,唯一发生变化的可能就是属性和方法的丢失。这就是为什么编译器在“未曾明确表示转型”活“未曾指定特殊标记”的情况下,仍然允许向上转型的原因。
  谨慎继承
  上面讲了继承所带来的诸多好处,那我们是不是就可以大肆地使用继承呢?送你一句话:慎用继承。
  首先我们需要明确,继承存在如下缺陷:
  1、父类变,子类就必须变。
  2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。
  3、继承是一种强耦合关系。
  所以说当我们使用继承的时候,我们需要确信使用继承确实是有效可行的办法。那么到底要不要使用继承呢?《Think in java》中提供了解决办法:问一问自己是否需要从子类向父类进行向上转型。如果必须向上转型,则继承是必要的,但是如果不需要,则应当好好考虑自己是否需要继承。

2 个回复

倒序浏览
值得学习ing!
回复 使用道具 举报
路过学习学习~
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马