小豪先生吧 关注:56贴子:96,095

【神经病研究所】Java oop

只看楼主收藏回复

RT


IP属地:广东1楼2013-04-25 10:35回复
    本节学习明细
    第1章:面向对象的Java实现——封装
    1.1 封装
    1.1.1 为什么需要封装
    1.1.2 什么是封装
    1.1.3 如何实现封装
    1.2 构造方法
    1.2.1 为什么需要构造方法
    1.2.2 什么是构造方法
    1.2.3 带参数的构造方法
    1.3 方法重载
    1.3.1 生活中的方法重载
    1.3.2 方法重载的代码示例
    1.3.3 构造方法重载


    IP属地:广东2楼2013-04-25 10:36
    回复
      1.1 封装
      1.1.1 为什么需要封装
      为什么需要封装(encapsulation)呢?我们通过一个示例来分析一下。
      现在需要编写一个类,代表ACCP5.0教员,要求如下:
      (1)ACCP5.0教员具有属性:姓名、年龄。
      (2)ACCP5.0教员具有行为:introduction(介绍)。
      (3)ACCP5.0教员有一个最小年龄要求:22岁。
      如果不用面向对象(OOP)的知识,应该这样写,代码如下:
      【例1】
      ****************************************
            AccpTeacher1类
      ****************************************
      01 package s2Java.sg.ch01;
      02 public class AccpTeacher1 {
      03   public String name; // 教员姓名
      04   public int age; // 年龄
      05
      06   /**
      07    * 返回自我介绍的内容
      08    */
      09   public String introduction() {
      10    return "大家好!我是" + name + ",我今年" + age + "岁。";
      11   }
      12 }
      上面的AccpTeacher1类中显然具有属性“姓名”、“年龄”,以及行为“自我介绍”。
      那么它是否满足最小年龄要求呢?通过编写一个测试类测试一下。
      ****************************************
           AccpTeacher1Test类
      ****************************************
      01 package s2Java.sg.ch01;
      02 public class AccpTeacher1Test {
      03   public static void main(String[] args) {
      04     /* 对教员进行初始化 */
      05     AccpTeacher1 teacher = new AccpTeacher1();
      06     teacher.name = "李芳";
      07     teacher.age = 10; // 显然年龄不符合要求
      08     /* 输出自我介绍的内容 */
      09     System.out.println(teacher.introduction());
      10   }
      11 }
      运行结果:
      大家好!我是李芳,今年10岁。
      【分析】
      结果不符合ACCP5.0教员的最小年龄要求。那是什么原因造成的呢?又该如何解决?
      AccpTeacher1类的两个属性都是public的,因此可以被任何其他的类访问。
      这样做的后果是我们无法控制各属性的值,因此一般情况下不应该这样做。
      正确的做法:把这些属性封装起来,增加一些方法来访问这些属性。


      IP属地:广东3楼2013-04-25 10:36
      回复
        1.1.2 什么是封装
        封装就是将属性私有化,提供共有的方法访问私有属性。
        做法:
        (1)修改属性的可见性来限制对属性的访问.
        (2)为每个属性创建一对取值get()方法和赋值set()方法,用于对这些属性的访问。
        如下面示例所示:
        【例2】
        ****************************************
              AccpTeacher2类
        ****************************************
        01 package s2Java.sg.ch01;
        02 public class AccpTeacher2 {
        03   private String name; // 教员姓名
        04   private int age; // 教员年龄
        05
        06   public String getName() {
        07     return name;
        08   }
        09
        10   public void setName(String name) {
        11     this.name = name;
        12   }
        13
        14   public int getAge() {
        15     return age;
        16   }
        17
        18   public void setAge(int age) {
        19     this.age = age;
        20   }
        21
        22   /**
        23    * 返回自我介绍的内容
        24    */
        25   public String introduction() {
        26     return "大家好!我是" + name + ",我今年" + age + "岁。";
        27   }
        28 }
        【注意】
        this关键字的含义:在对象内部指代自身的引用。
        因为this可以使你直接引用对象,你能用它来解决可能在实例变量和局部变量之间发生的任何同名
        的冲突。如上面的代码中使用了this关键字,有效的解决了实例变量name与局部变量name之间发生
        的同名冲突。
        【提问】
        使用private关键字修饰某个成员变量后,这个成员变量可以被同一包中的其它类访问吗?
        【答案】
        否。
        上面的AccpTeacher2类中,使用了private关键字修饰属性,就意味着:除了AccpTeacher类本身,
        其他所有类都不可以访问这些属性。但是,可以通过这些属性的取值get()方法、赋值set()方法
        来访问这些属性。
        ****************************************
             AccpTeacher2Test类
        ****************************************
        01 package s2Java.sg.ch01;
        02 public class AccpTeacher2Test {
        03   public static void main(String[] args) {
        04     /* 对教员进行初始化 */
        05     AccpTeacher2 teacher = new AccpTeacher2();
        06     teacher.setName("李芳");
        07     teacher.setAge(10); // 显然年龄不符合要求
        08     /* 输出自我介绍的内容 */
        09     System.out.println(teacher.introduction());
        10   }
        11 }
        运行结果:
        大家好!我是李芳,今年10岁。
        【分析】
        此时,运行结果仍然不符合ACCP5.0教员的最小年龄限制,但是,只要在上述代码的基础上稍加改造,
        就可以达到目的了。


        IP属地:广东4楼2013-04-25 10:36
        回复
          封装属性、自动生成代码


          IP属地:广东通过百度相册上传5楼2013-04-25 10:37
          回复


            IP属地:广东通过百度相册上传6楼2013-04-25 10:38
            回复
              1.1.3 如何实现封装
              实际做法很简单,只需要在上述代码的基础上改造,即赋值方法中加入对属性访问限制的代码,就能够
              实现ACCP5.0教员的最小年龄要求限制。代码如下:
              【例3】
              ****************************************
                    AccpTeacher3类
              ****************************************
              01 package s2Java.sg.ch01;
              02 public class AccpTeacher3 {
              03   private String name; // 教员姓名
              04   private int age; // 教员年龄
              05
              06   public String getName() {
              07     return name;
              08   }
              09
              10   public void setName(String name) {
              11     this.name = name;
              12   }
              13
              14   public int getAge() {
              15     return age;
              16   }
              17
              18   public void setAge(int age) {
              19     if (age < 22) {
              20       System.out.println("错误!最小年龄应为22岁!");
              21       this.age = 22;
              22     } else {
              23       this.age = age;
              24     }
              25   }
              26
              27   /**
              28    * 返回自我介绍的内容
              29    */
              30   public String introduction() {
              31     return "大家好!我是" + name + ",我今年" + age + "岁。";
              32   }
              33 }
              在setAge()中,如果欲设置的年龄小于22岁,就打印错误信息,并把年龄设置为22岁。
              现在,代码已满足了要求,测试类如下:
              ****************************************
                   AccpTeacher3Test类
              ****************************************
              01 package s2Java.sg.ch01;
              02 public class AccpTeacher3Test {
              03   public static void main(String[] args) {
              04     /* 对教员进行初始化 */
              05     AccpTeacher3 teacher = new AccpTeacher3();
              06     teacher.setName("李芳");
              07     teacher.setAge(10); // 显然年龄不符合要求
              08     /* 输出自我介绍的内容 */
              09     System.out.println(teacher.introduction());
              10   }
              11 }
              运行结果:
              错误!最小年龄应为22岁!
              大家好!我是李芳,我今年22岁。
              【分析】
              显然,通过封装,实现了对属性的数据访问限制,满足了ACCP5.0教员类的需求。
              另外,同前面的代码相比,上述的代码中更改了对年龄设置的实现,但是由于
              取值方法和赋值方法隐藏了实现的变更,因此并不会影响读取或修改该属性的
              类,避免了大规模的修改,程序的可维护性增强。以上即“代码封装的好处”。
              【总结】
              实现封装的步骤:
              (1)修改属性的可见性来限制对属性的访问。
              (2)为每个属性创建一对赋值方法和取值方法,用于对这些属性的访问。
              (3)在赋值和取值方法中,加入对属性的存取限制。


              IP属地:广东7楼2013-04-25 10:38
              回复
                【现场编程】
                请通过代码封装,实现如下需求:
                (1)编写一个类Book,代表教材:
                ①具有属性:名称(title)、页数(pageNum),其中页数不能少于200页,否则输出错误信息,并赋予默认
                值200。
                ②为各属性设置赋值和取值方法。
                ③具有方法:detail,用来在控制台输出每本教材的名称和页数。
                (2)编写测试类BookTest进行测试:为Book对象的属性赋予初始值,并调用Book对象的detail方法,看看输
                出是否正确。
                【代码】
                ****************************************
                        Book1类
                ****************************************
                01 package s2Java.sg.ch01.exercise;
                02 public class Book1 {
                03   private String title; // 名称
                04   private int pageNum; // 页数
                05
                06   public String getTitle() {
                07     return title;
                08   }
                09
                10   public void setTitle(String title) {
                11     this.title = title;
                12   }
                13
                14   public int getPageNum() {
                15     return pageNum;
                16   }
                17
                18   public void setPageNum(int pageNum) {
                19     this.pageNum = pageNum;
                20   }
                21
                22   /**
                23 * 在控制台输出图书信息
                24 */
                25   public void detail(){
                26     System.out.println("书名:" + title + ",页数:" + pageNum);
                27   }
                28 }
                ****************************************
                       Book1Test类
                ****************************************
                01 package s2Java.sg.ch01.exercise;
                02 public class Book1Test {
                03   public static void main(String args[]){
                04     Book1 book = new Book1();
                05     book.setTitle("Java快速入门");
                06     book.setPageNum(109);
                07     book.detail();
                08   }
                09 }
                运行结果:
                书名:Java快速入门,页数:109


                IP属地:广东8楼2013-04-25 10:39
                回复
                  1.2 构造方法
                  1.2.1 为什么需要构造方法
                  Java中经常会用到构造方法(constructor),实例化一个对象实际上就是去调用这个对象的构造方法。
                  现在开发第二版的ACCP5.0教员类,要求如下:
                  (1)ACCP5.0教员类具有属性:姓名、年龄、学历、职位。
                  (2)ACCP5.0教员类具有行为:自我介绍。
                  【例4】
                  ****************************************
                        AccpTeacher4类
                  ****************************************
                  01 package s2Java.sg.ch01;
                  02 public class AccpTeacher4 {
                  03   private String name;   // 姓名
                  04   private int age;     // 年龄
                  05   private String education; // 学历
                  06   private String position; // 职位
                  07
                  08   public String getName() {
                  09     return name;
                  10   }
                  11
                  12   public void setName(String name) {
                  13     this.name = name;
                  14   }
                  15
                  16   public int getAge() {
                  17     return age;
                  18   }
                  19
                  20   public void setAge(int age) {
                  21     this.age = age;
                  22   }
                  23
                  24   public String getEducation() {
                  25     return education;
                  26   }
                  27
                  28   public void setEducation(String education) {
                  29     this.education = education;
                  30   }
                  31
                  32   public String getPosition() {
                  33     return position;
                  34   }
                  35
                  36   public void setPosition(String position) {
                  37     this.position = position;
                  38   }
                  39
                  40   public String introduction() {
                  41     return "大家好!我是" + name + ",我今年" + age + "岁,学历" +
                  42         education + ",目前职位是" + position;
                  43   }
                  44 }
                  编写一个测试类,来测试一下,要求如下:
                  (1)实例化一个教员对象,并对其初始化。
                  (2)在控制台输出该教员的自我介绍。
                  ****************************************
                       AccpTeacher4Test类
                  ****************************************
                  01 package s2Java.sg.ch01;
                  02 public class AccpTeacher4Test {
                  03   public static void main(String[] args) {
                  04     AccpTeacher4 teacher = new AccpTeacher4();
                  05     teacher.setName("李芳");
                  06     teacher.setAge(23);
                  07     teacher.setEducation("本科");
                  08     System.out.println(teacher.introduction());
                  09   }
                  10 }
                  运行结果:
                  大家好!我是李芳,我今年23岁,学历本科,目前职位是null
                  【分析】
                  (1)在这个结果中,教员的职位信息显然是不符合现实需求的。为什么会造成这种现象呢?
                  问题就在于:在教员类AccpTeacher4中有太多的属性,在通过赋值方法对教员类AccpTeacher4
                  进行初始化时,很容易就会忘记对其中的一项或多项赋值。
                  (2)那么,有没有什么办法可以简化对象初始化(即为实例变量赋值)的代码?
                  其实,实例化一个对象的过程就是调用这个对象构造方法的过程。如果把对象初始化的过程融合
                  进对象实例化的过程中,那就应该可以解决这个问题了。


                  IP属地:广东9楼2013-04-25 10:39
                  回复
                    1.2.2 什么是构造方法
                    构造方法负责对象成员的初始化工作,为实例变量赋予了合适的初始值。
                    构造方法必须满足一下语法规则:
                    (1)方法名与类名相同。
                    (2)没有返回类型。
                    【例5】
                    ****************************************
                          AccpTeacher5类
                    ****************************************
                    01 package s2Java.sg.ch01;
                    02 public class AccpTeacher5 {
                    03   private String name;
                    04
                    05   public AccpTeacher5() {
                    06     name = "无名氏";
                    07   }
                    08
                    09   public String getName() {
                    10     return this.name;
                    11   }
                    12 }
                    ****************************************
                         AccpTeacher5Test类
                    ****************************************
                    01 package s2Java.sg.ch01;
                    02 public class AccpTeacher5Test {
                    03   public static void main(String[] args) {
                    04     AccpTeacher5 teacher = new AccpTeacher5();
                    05     System.out.println("教员姓名为:" + teacher.getName());
                    06   }
                    07 }
                    运行结果:
                    教员姓名为:无名氏
                    【分析】
                    (1)使用new关键字实例化对象的过程实际上就是调用构造方法的过程。
                    (2)在实例化对象时,已经不知不觉地为实例变量赋了默认的初始值,完成了对象的初始化工作。
                      (调用无参的构造方法 ←→ 隐式调用或自动调用)
                    (3)有时,又需要显式的调用构造方法。显式调用 ←→ 调用有参的构造方法。下一小节将涉及到。


                    IP属地:广东10楼2013-04-25 10:40
                    回复
                      1.2.3 带参数的构造方法
                      带参数的构造方法可以在构造方法中传递参数。
                      【例6】
                      ****************************************
                            AccpTeacher6类
                      ****************************************
                      01 package s2Java.sg.ch01;
                      02 public class AccpTeacher6 {
                      03   private String name;
                      04   private int age;
                      05   private String education;
                      06   private String position;
                      07
                      08   public AccpTeacher6(String name, int age, String education, String position) {
                      09     super();
                      10     this.name = name;
                      11     this.age = age;
                      12     this.education = education;
                      13     this.position = position;
                      14   }
                      15
                      16   public String introduction() {
                      17     return "大家好!我是" + name + ",我今年" + age + "岁,学历" + education +
                      18         "目前职位是" + position + "。";
                      19   }
                      20 }
                      很显然,通过带参数的构造方法,显式地为AccpTeacher6教员类的各个实例变量赋予了初始值。
                      ****************************************
                           AccpTeacher6Test类
                      ****************************************
                      01 package s2Java.sg.ch01;
                      02 public class AccpTeacher6Test {
                      03   public static void main(String[] args) {
                      04     AccpTeacher6 teacher = new AccpTeacher6("李芳",23,"本科","咨询师");
                      05     System.out.println(teacher.introduction());
                      06   }
                      07 }
                      【分析】
                      (1)在使用带参数的构造方法实例化对象时,传递的值和构造方法的参数应当在个数、次序和数据
                      类型上互相匹配。
                      (2)通过调用带参数的构造方法,在创建对象时,一并完成了对象成员的初始化工作,简化了对象
                      的初始化代码。
                      (3)在很多情况下,需要为某个类编写多个构造方法,以表现不同的初始化行为。这时就需要“方
                      法重载”(下一小节将涉及到),这也有点像“多态”(后面章节)。


                      IP属地:广东11楼2013-04-25 10:40
                      回复


                        IP属地:广东通过百度相册上传12楼2013-04-25 10:41
                        收起回复
                          【现场编程】
                          编写一个类Book2,代表教材:
                          (1)具有属性:名称(title)、页数(pageNum),其中页数不能少于200页,否则输出错误信息,
                          并赋予默认值200。
                          (2)具有方法:Sdetail,用来在控制台输出每本教材的名称和页数。
                          (3)具有带参数的构造方法:用来完成对象的初始化工作,并在构造方法中完成对页数的最小值限制。
                          编写测试类Book2Test进行测试:初始化一个Book2对象,并调用该Book2对象的detail方法,看看输出
                          是否正确。
                          【代码】
                          ****************************************
                                  Book2类
                          ****************************************
                          01 package s2Java.sg.ch01.exercise;
                          02 public class Book2 {
                          03   private String title;
                          04   private int pageNum;
                          05
                          06   public Book2(String title,int pageNum){
                          07     this.title = title;
                          08     if (pageNum < 200) {
                          09       System.out.println("页数不能少于200页!");
                          10       this.pageNum = 200;
                          11     } else {
                          12       this.pageNum = pageNum;
                          13     }
                          14   }
                          15
                          16   public void detail(){
                          17     System.out.println("书名:" + title + ",页数:" + pageNum);
                          18   }
                          19 }
                          ****************************************
                                 Book2Test类
                          ****************************************
                          01 package s2Java.sg.ch01.exercise;
                          02 public class Book2Test {
                          03   public static void main(String[] args) {
                          04     Book2 book = new Book2("Java入门",107);
                          05     book.detail();
                          06   }
                          07 }
                          运行结果:
                          页数不能少于200页!
                          书名:Java入门,页数:200


                          IP属地:广东13楼2013-04-25 10:41
                          回复
                            1.3.1 生活中的方法重载
                            比如:一个司机既可以驾驶轿车,又可以驾驶巴士,也有可能驾驶火车。
                            虽然驾驶的行为实现各不相同,但毫无疑问,我们都称这个行为为驾驶。
                            驾驶这一行为就构成了生活中的方法重(chóng)载。从图中可以分析出这样的结果:
                            (1)把司机抽象成一个类。
                            (2)司机具有三个方法,方法名称都是驾驶。
                            (3)这三个方法具有不同的参数,分别为轿车、巴士、火车。
                            (4)这三个方法的具体实现各不相同。
                            在Java中,如果两个方法名称相同,但参数项不相同,那么认为一个方法是另一个方法的
                            重载方法,而此过程称为“方法重载”。(仅仅看参数是否不同,没有涉及到返回类型)


                            IP属地:广东通过百度相册上传14楼2013-04-25 10:48
                            回复
                              1.3.2 方法重载的代码示例
                              实际上,我们对方法重载并不陌生!在Java的基础学习中,常见的例子很多,比如以下两例:
                              【例7】
                              ****************************************
                                     AccpTest1类
                              ****************************************
                              01 package s2Java.sg.ch01;
                              02 public class AccpTest1 {
                              03   public static void main(String[] args) {
                              04     int i = 0;
                              05     char c = 'z';
                              06     String str = "hello";
                              07     System.out.println(i);
                              08     System.out.println(c);
                              09     System.out.println(str);
                              10   }
                              11 }
                              运行结果:
                              0
                              z
                              hello
                              【例8】
                              ****************************************
                                     AccpTest2类
                              ****************************************
                              01 package s2Java.sg.ch01;
                              02 public class AccpTest2 {
                              03   public static void main(String[] args) {
                              04     System.out.println(Math.max(1, 2));
                              05     System.out.println(Math.max(1.0F, 2.0F));
                              06     System.out.println(Math.max(1.0, 2));
                              07   }
                              08 }
                              运行结果:
                              2
                              2.0
                              2.0
                              【分析】
                              (1)当运行到代码行Math.max(1,2)时,由于参数均为int类型,因此执行max(int a,int b)方法。
                              (2)当运行到代码行Math.max(1.0F, 2.0F)时,由于参数均为float类型,因此执行
                                 max(float a,float b)方法。
                              (3)当运行到代码行Math.max(1.0, 2)时,由于参数有一个是double类型,因此自动把另一个参数
                                 转换为double类型,从而执行max(double a,double b)方法。


                              IP属地:广东15楼2013-04-25 10:49
                              回复