20145211 《Java程序设计》第4周学习总结——园日涉以成趣

编程思想DRY和Once and Only Once

  • DRY

    DRY原则的为“每一个知识都必须在系统内必须是单一的,明确的,权威的,具有代表性。当DRY的原则成功应用,在系统中,任何单一元素的修改不影响与其逻辑无关的元素。 此外,和元素逻辑相关的一切变化都是可以预见和统一,因此保持同步 。 除了使用这种方法,在他们的代码, Thomas和Hunt依靠代码生成 ,自动生成系统,并依赖脚本语言,观察DRY原则在跨层中的运用。

  • Once and Only Once

    在编写代码时应用 一次且仅一次原则 比实施后容易的多,整合两个类似的函数是相当困难的。
    如果你在编写代码的时候坚持这个原则,他将帮助你的代灵活而有用,而你的代码也会存活的长久兴旺。

教材学习内容总结

第六章 继承与多态

继承

  • 什么是继承

    子类继承父类的特征和行为,使得子类具有父类的各种属性和方法。或子类从父类继承方法,使得子类具有父类相同的行为。

  • 继承的特点

    在继承关系中,父类更通用、子类更具体。父类具有更一般的特征和行为,而子类除了具有父类的特征和行为,还具有一些自己特殊的特征和行为。在继承关系中。父类和子类需要满足is-a的关系。子类是父类。

  • 继承的优势

    使用继承可以有效实现代码复用,避免重复代码的出现。当两个类具有相同的特征(属性)和行为(方法)时,可以将相同的部分抽取出来放到一个类中作为父类,其它两个类继承这个父类。继承实现了面向对象的原则:write once,only once(编写一次、且编写一次)

  • 怎么继承
    在java语言中,用extends(扩展)关键字来表示一个类继承了另一个类。在父类中只定义一些通用的属性和方法。
    子类自动继承父类的属性和方法,子类中可以定义特定的属性和方法。或子类重新定义父类的属性、重写父类的方法可以获得与父类不同的功能。子类的构造方法一定会调用父类的构造方法。任何子类构造方法第一行肯定是this();或者super();两个择一。this();调用本类的其它构造方法。(传递相应参数调用相应的方法)
    super();调用父类的构造方法。

  • 方法重写

    如果在子类中定义的一个方法,其名称、返回类型及参数列表正好与父类中某个方法的名称、返回类型及参数列表相匹配,那么可以说,子类的方法重写了父类的方法。方法重写在不同类,是实现多态的必要条件。

  • 覆盖VS重载

    覆盖是指派生类重新定义基类的虚方法的方法。而重载,是指允许存在多个同名函数,这
    些函数的参数表不同(或许是参数个数不同,或许是参数类型不同,或许两者都不同)。
    重载的概念并不属于“面向对象编程”。重载的可能的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数例如,有两个重载的同名函数

    function func(p : integer) : integer; overload;

    function func(p : string) : integer; overload;

    那么编译器做过修饰后的函数名可能是:int_func、str_func。如果调用

    func(2);

    func(′hello′);

    那么编译器会把这两行代码分别转换成:

    int_func(2);

    str_func(′hello′);

    这两个函数的调用入口地址在编译期间就已经静态(记住:是静态!)确定了。这样的确定函数调用入口地址的方法称为早绑定。

    而覆盖则是:当派生类重定义了基类的虚方法后,由于重定义的派生类的方法地址无法给出,其调用地址在编译期间便无法确定,故基类指针必须根据赋给它的不同的派生类
    指针,在运行期动态地(记住:是动态!)调用属于派生类的虚方法。这样的确定函数调用地址的方法称为晚绑定。引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,
    它就不是多态”。

多态

  • 什么是多态

    多态的特征是表现出多种形态,具有多种实现方式。或者多态是具有表现多种形态的能力的特征。或者同一个实现接口,使用不同的实例而执行不同的操作。

  • 多态的好处

    可以增强程序的可扩展性及可维护性,使代码更加简洁。
    不但能减少编码的工作量,也能大大提高程序的可维护性及可扩展性。多态与继承、方法重写密切相关,我们在方法中接收父类类型作为参数,在方法实现中调用父类类型的各种方法。当把子类作为参数传递给这个方法时,java虚拟机会根据实际创建的对象类型,调用子类中相应的方法(存在方法重写时)。

  • 怎么实现多态
    一般做法是:写一个方法,它只接收父类作为参数,编写的代码只与父类打交道。调用这个方法时,实例化不同的子类对象(new 一个对象)。
    更具体的说:子类重写父类的方法。使子类具有不同的方法实现;把父类类型作为参数类型,该父类及其子类对象作为参数转入;运行时,根据实际创建的对象类型动态决定使用那个方法。在运行时,java虚拟机会根据实际创建的对象类型决定使用那个方法。一般将这称为动态绑定。

public abstract class Vehicle{
   public void drivedByFemale( );
   public void drivedByMale();
}
public class Bus extends Vehicle{
   public void drivedByFemale( ){
       System.out.println("A Female driver drives a bus.");
   }
   public void drivedByMale(){
        System.out.println("A Male driver drives a bus.");
   }
}
 

public class MaleDriver extends Driver {
    public void drives(Vehicle  v){
        v. drivedByMale();
    }
}
public class Test{
     public static void main(){
         Vehicle bus = new Bus();
          Driver male = new MaleDriver();
          male.drives(bus);
     }
}

第七章 接口与多态

  • 什么是接口

    接口是对象之间通信的基本方式,接口描述可属于任何类或结构的一组相关行为。接口可由方法、属性、事件、索引器或这四种成员类型的任何组合构成。接口不能包含字段。接口成员一定是公共的。

    类和结构可以像类继承基类或结构一样从接口继承,但有两个例外:其一是类或结构可继承多个接口。其二是当类或结构继承接口时,它继承成员定义但不继承实现。例如:

public class Minivan : Car, IComparable
{
    public int CompareTo(object obj)
    {
        return 0;
    }
}
  • 接口的实现

接口不能用new运算符直接产生对象,必须利用其特性设计新的类,再用新类来创建对象与抽象类一样,接口要使用也必须通过子类,子类通过implements关键字实现接口。
实现格式:
class 子类名称 implements 接口A, 接口B,….{//子类成员声明}
接口的使用必须通过子类,子类必须覆写全部抽象方法。一个子类虽然只能继承于一个父类,但可以同时实现多个接口。

interface A{
      public String name = “小明”;

      public void print();

      public String getName();

	}
	interface B{
      public void setName();

}
class C implements A, B{
   public void print( ) { ……};

   public  String getName( ) {……};

   public  void setName( ) {……};
}

class C implements A, B{
   //public void print( ) { ……};     //没覆写print方法,编译不过。

   public  String getName( ) {……};

   public  void setName( ) {……};

}

必须实现接口中的所有方法,否则,实现接口的类将带有抽象方法,因此成为抽象类。在覆写来自接口的方法时,必须声明成public。

  • 接口的继承

    接口不能继承一个抽象类,却可以通过extends同时继承于多个接口。

    public abstract class base {……}
    interface B {……} 
    interface C{……}
    interface A extends base{……}    //错误
    interface A extends B, C{ ……}    //正确
    

教材学习中的问题和解决过程

一开始,没有完全理解继承的真正含义。

public class SwordMan {
    private String name;
    private int level;
    private int blood;
    public void fight(){
        System.out.println("挥剑攻击");
    }

    public int getBlood() {
        return blood;
    }

    public void setBlood(int blood) {
        this.blood = blood;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Magician {
    private String name;
    private int level;
    private int blood;
    public void fight(){
        System.out.println("魔法攻击");
    }
    public void cure()
    {
        System.out.println("魔法治疗");
    }
    public int getBlood() {
        return blood;
    }

    public void setBlood(int blood) {
        this.blood = blood;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

虽然SwordsMan与Magician没有定义getName()、getLevel()、与getBlood()等方法,但从Role继承了这些方法,所以就如同例子中可以直接使用。
继承的好处之一,就是若要将name、level、blood改为其他名称,那就只要修改Role.java就可以了,只要是继承Role的子类都无须修改。

代码调试中的问题和解决过程

仔细比较覆盖与重载的区别

我一开始没有完全理解覆盖和重载的区别,后来才发现覆盖是父子类之间,而重载则针对一个类;同时,覆盖的父子类同名、相同的参数列表、相同的返回类型,而重载方法名相同、参数列表不同、与返回类型无关

package com.ctit;

public class Test {
    public static void main(String[] args){
        A a = new B(); //这里是把子类当成父类来看,则只能调用父类中定义的属性和方法。
        //a.hello(5); 如果子类覆盖了父类中的方法,则调用的是子类覆盖后的那个方法。   

        B b = (B)a; //这里是把父类强转成子类,这里千万不能写成A a = new A();这样的话运行时会报错,只能是上面的那个A a = new B();

        b.hello(4);//强转后调用的是子类中的方法(对覆盖来说)
        b.hello2();//强转后也可以调用父类中的方法
    }
}

class A{
    public void hello(int i){
        System.out.println("A="+i);
    }

    public void hello2(){
        System.out.println("hello2");
    }
}

class B extends A{
    public void hello(int j){
        System.out.println("B="+j);
    }
    //下面的这个方法不是覆盖
    public void hello(long l){
        System.out.println("B2="+l);
    }
}

其他(感悟、思考等,可选)

先分享一段对话,告诉我,你读出了什么。

大师: 蚱蜢, 告诉我,在面向对象的道路上,你学到了什么?

门徒:大师,我学到了,面向对象之路,可以『复用』。

大师:继续说...

门徒: 大师, 藉由继承, 好东西可以一再被利用, 所以程序开发时间就会大幅减少, 就好像在林中很快地把竹子截短一样。

大师:蚱蜢呀!软件开发完成『前』以及完成『后』, 何者需要花更多时间呢?

门徒: 答案是『后』,大师, 我们总是需要花许多时间在系统的维护和变化上, 比原先开发花的时间更多。

大师:我说蚱蜢, 这就对啦! 那么我们是不是应该致力于提高可维护性和可扩充性上的复用程度呀?

门徒:是的,大师,的确是如此。

有道是,“一千个读者有一千个哈姆雷特。”对这段话的理解也会因人而异,面向对象让我们不用再重复定义参数不同语句相同的函数,也方便了我们后期的调用。相应的我们要花更多的时间来提高源程序的可维护性与可扩充性。所谓“前人栽树后人乘凉”,正是如此。

如今,在娄老师的指导下,我们都逐渐步入学习java的正轨,我们每个人都有自己的一套java,就像是我们在自家院子里开垦了一个园子,然后在里面种植一些自己喜欢的,时不时地在园中赏花;从不受外界的纷争干扰,不忘初心,正是“园日涉以成趣,门虽设而常关”。有一个自己喜欢的院子,并在其中做一些自己喜欢想做的事,确是一种写意的生活;现在,我们自己的java就像一亩三分地,自己耕耘,自己收获,苦不苦只有自己知道。

古人云,“熟读唐诗三百首,不会写来也会吟。”即便不能完全通透的掌握java,你每天都学着,还是不一样的,何况“园日涉以成趣”。有一种坚持,叫不忘初心。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 100/100 2/2 15/15 学会搭建Java环境,学会写一些简单程序,掌握一些小技巧
第二周 100/200 2/4 22/37 学会使用IDEA
第三周 450/650 1/5 24/61 深入了解面向对象
第四周 750/1450 1/6 30/90 理解继承、多态、接口

参考资料

原文地址:https://www.cnblogs.com/nostalgia-/p/5327341.html