• 20145208 《Java程序设计》第4周学习总结


    20145208 《Java程序设计》第4周学习总结

    教材学习内容总结

    继承

    • 在学习指导中我了解到继承是符合DRY原则的,DRY(Don't repeat yourself),字面意思来看是"不要重复自己"。它强调的意思就是在进行编程时相同的代码不要重复写,最好只写一次,然后可以在其他地方直接引用。如此一来,可以提高代码重用率,缩减代码量,同时也有助于提高代码的可读性和可维护性。当需要做出更改时,只需要更改一个地方即可。
    • 这就是我们学习继承的目的之一:避免重复的代码段。
    • ISP原则:一个类对另一个类的依赖应该限制在最小化的接口上。
    • OCP原则:软件构成(类,模块,方法等)向扩展行为开放,向修改行为关闭。
    • Is-a原则:指的是类的父子继承关系,例如类A是另一个类B的子类(类B是类A的父类)。
    • LSP原则:子类必须能够用来当作基类使用。如果类A继承类B,任何能使用A的地方,B也同样可以使用。
    • extends
      • JAVA中只有单一继承,就是说只可以有一个父类,我们使用extends继承的时候只能继承一个类,如果我们想要继承多个的时候,就需要用的第七章的接口(Interface)。
    public class Game1Role {
        private String name;
        private int level;
        private int blood;
        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;
        }
    }
    
    • 上图代码是一个设定好的规则,从规则中的代码可以看出,我们将name,level,blood这些变量都用private封装了,这是继承的基础。
    • 那么为了不重复一些代码我们就可以让所有符合这个规则的类都继承这个规则。如下代码:
    public class Game1SwordsMan extends Game1Role {
        public void fight(){
            System.out.println("挥剑攻击");
        }
    }
    
    • 多态:
      • 多态从字面上的解释就是某一类事物的多种存在形态,以抽象讲法解释就是使用单一接口操作多种类型的对象。
    public class Game2RPG {
        public static void main(String[] args) {
            Game1SwordsMan swordsMan=new Game1SwordsMan();
            swordsMan.setName("Justin");
            swordsMan.setLevel(1);
            swordsMan.setBlood(200);
            Game1Magician magician=new Game1Magician();
            magician.setName("Monica");
            magician.setLevel(1);
            magician.setBlood(100);
            showBlood(swordsMan);
            showBlood(magician);
        }
        static void showBlood(Game1Role role){
            System.out.printf("%s 血量 %d%n",role.getName(),role.getBlood());
        }
    }
    

    代码中showBlood()方法通过Role类型既可以操作SwordsMan对象,也可以操作Magician对象,这就是多态。

    • UML:
      • 它是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持,包括由需求分析到规格,到构造和配置。 UML是一种建模语言,而不是一个开发过程。
    • 覆盖(Override):
      • 覆盖(Override)与重载(overload)的区别:覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用;重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。
      • Annotation:@override:在使用此annotation时只要在被修饰的方法前面加上@Override。表示要求编译程序检查该方法是不是真的重新定义了父类中某个方法。代码如下:
    public class Game6SwordsMan extends Game6Role {
        public void fight(){
            System.out.println("挥剑攻击");
        }
        @Override
        public String toString(){
            return "剑士"+super.toString();
        }
    }
    
    • 抽象方法、抽象类:
      • abstract修饰的类为抽象类,其除了不能通过new实例化对象外,和一般的类没有什么不同。可以有静态成员(静态方法,静态变量)一般成员,构造方法,可以被继承,另外还可以有abstract修饰的方法,类中含有 abstract修饰的方法只能是abstract类。与接口比较,它是单继承的,接口是多实现的。
      • 如下代码中就使用了abstract修饰:
    public abstract class Game4Role {
        private String name;
        private int level;
        private int blood;
        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 abstract void fight();
    }
    
    • 思考题:
      • Square(正方形)类继承Rectangle(矩形)类合适吗?
        • 不合适。虽然在数学逻辑上面觉得并没有错,但是Square(正方形)在某些场合是不能替代Rectangle(矩形)的,让Square(正方形)继承Rectangle(矩形)是一种不合理的设计,其违背了Liskov替换原则(LSP)。也就是虽然他们符合了IS-A规则,但是我们设计继承体系时,子类应该是可替代的父类的,是可替代关系,而不仅仅是IS-A的关系。

    继承语法的细节

    • super与this:
      • super关键字表示父类的意思。this变量代表对象本身。即super()和this()类似,区别是,super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
      • 调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
    public class OceanWorld1Anemonefish extends OceanWorld1Fish {
        public OceanWorld1Anemonefish(String name) {
            super(name);
        }
        @Override
        public void swim() {
            System.out.printf("小丑鱼 %s 游泳%n", name);
        }
    }
    
    • java.lang.Object
      • toString:toString()方法返回该对象的字符串表示。toString()是由对象的类型和其哈希码唯一确定,同一类型但不相等的两个对象分别调用toString()方法返回的结果可能相同。
      • equlas:equlas()方法的正确理解应该是:判断两个对象是否相等。重写equals()方法必须重写hasCode()方法。
      • hashCode:hashCode()方法返回一个整形数值,表示该对象的哈希码值。两个对象相等 <=> equals()相等 => hashCode()相等。因此,重写equlas()方法必须重写hashCode()方法,以保证此逻辑严格成立,同时可以推理出:hasCode()不相等 => equals()不相等 <=> 两个对象不相等。
      • instanceof:如果 object 是 class 的一个实例,则 instanceof 运算符返回 true。如果 object 不是指定类的一个实例,或者 object 是 null,则返回 false。

    接口与多态

    • 接口
      • 接口(interface)定义行为:接口与类属于同一层次,实际上,接口是一种特殊的抽象类。
      • implements:是实现接口的方法。
      • 思考题:接口与抽象类的别?
        • 接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。

    接口语法细节

    * enum:enum很像特殊的class,实际上enum声明定义的类型就是一个类:
    
    public enum EnumAction {
        STOP, RIGHT, LEFT, UP, DOWN
    }
    

    在本章中将枚举类用在了switch语句中:

    import static java.lang.System.out;
    public class EnumGame {
        public static void main(String[] args) {
            play(EnumAction.RIGHT);
            play(EnumAction.UP);
        }
        public static void play(EnumAction action) {
            switch (action) {
                case STOP:
                    out.println("播放停止动画");
                    break;
                case RIGHT:
                    out.println("播放向右动画");
                    break;
                case LEFT:
                    out.println("播放向左动画");
                    break;
                case UP:
                    out.println("播放向上动画");
                    break;
                case DOWN:
                    out.println("播放向下动画");
                    break;
            }
        }
    }
    
    • 接中可以使用extends继承接口,并且可以继承多个接口:
    public class OceanWorld4Seaplane extends OceanWorld4Airplane implements OceanWorld1Swimmer {
        public OceanWorld4Seaplane(String name) {
            super(name);
        }
        @Override
        public void fly() {
            System.out.print("海上");
            super.fly();
        }
        @Override
        public void swim() {
            System.out.printf("海上飞机 %s 航行海面%n", name);
        }
    }
    

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

    • 教材P202中的Airplane.java类名是Seaplane而不是Airplane。将Airplane.java修改为Seaplane.java就可以了
    • 教材P204中第二个Human,java存在同样问题。或者我们可以把Human.java代码改成如下代码:
    public class OceanWorld4Human {
        protected String name;
        public OceanWorld4Human(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public class SwimPlayer extends OceanWorld4Human implements OceanWorld1Swimmer {
            public SwimPlayer(String name) {
                super(name);
            }
            @Override
            public void swim() {
                System.out.printf("游泳选手 %s 游泳%n", name);
            }
        }
    }
    
    • 教材P207的Boat.java中存在语病:
      “船在水面 %s 航行%n”,应改成“船 %s 在水面航行%n”

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

    • 在运行如下代码的时候,虽然编译通过了,但是我觉得程序的输出比较不合理,应该存在着问题:

    我觉得程序红框内的输出应该是像前面那几个一样的,然后我再相应的类中找到了问题,书上的代码是这样的:

    这样不论我们给定的名字是什么都不会显示出来,这样并不合理啊?!所以我要修改一下:

    public class OceanWorld3FlyingFish extends OceanWorld1Fish implements OceanWorld3Flyer {
        public OceanWorld3FlyingFish(String name) {
            super(name);
        }
        @Override
        public void swim() {
            System.out.printf("飞鱼 %s 游泳%n", name);
        }
        @Override
        public void fly() {
            System.out.printf("飞鱼 %s 会飞%n", name);
        }
    }
    

    这样的话输出就舒服多了:

    • 上面的问题解决完了,我又觉得光是游泳太单调了,为什么不加入之前弄好的飞行的东西呢?
      • 所以我修改了代码如下:
    public class OceanWorld4Ocean {
        public static void main(String[] args) {
            doSwim(new OceanWorld1Anemonefish("尼莫"));
            doSwim(new OceanWorld1Shark("兰尼"));
            doSwim(new SwimPlayer("贾斯汀"));
            doDive(new OceanWorld4Submarine("黄色一号"));
            doSwim(new OceanWorld4Seaplane("空军零号"));
            doSwim(new OceanWorld3FlyingFish("甚平"));
            doSwim(new OceanWorld4Boat("方舟"));
            doFly(new OceanWorld4Helicopter("黑鹰"));
        }
        private static void doDive(OceanWorld4Submarine diver) {
            diver.dive();
        }
        private static void doFly(OceanWorld4Helicopter flyer) {
            flyer.fly();
        }
        static void doSwim(OceanWorld1Swimmer swimmer) {
            swimmer.swim();
        }
    }
    

    我模仿doSwim()方法定义了新的doDive()和doFly()就达到了我的目的:

    其他(感悟、思考等)

    • 经过了本章学习,我感觉自己的比上周又进步了很多,而且几周时间,在练习的过程中我已经敲了将近两千行代码了,就像老师说的那样,通过敲代码的练习,真真切切的可以感受到自己对代码的理解一直在上升,一开始我会抱有疑问:敲代码不就是可以记忆的更好么?其实不止如此,敲代码的过程也要是一个思考的过程,我们敲代码不是单纯的敲键盘,脑袋也要进行思考,出现了问题要去发现问题解决问题,没有问题也要去想想这段代码虽然运行成功了,但是合理么?如果合理,还有可以改进的地方么?带着思考去学习,进步才会越来越大,就像老师给的那道思考题——正方形可以继承长方形么?如果我们单纯的敲代码,我们可以敲出一个运行成功的代码,结果也是我们想的,但是,正确答案是不可以的,那么正确答案就需要我们自己思考,设计一个验证的方案,不光这道思考题如此,我们以后接触的代码会越来越复杂,很多地方无论逻辑上还是规则上都需要进行思考。
    • 本周学习,我最大的收获就是对代码思考的越来越多了,不只是在敲代码了。

    学习进度条

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 5000行 30篇 400小时 成为超过高级初学者的存在
    第一周 150/150 1/3 15/15 第一个JAVA程序
    第二周 150/300 2/5 20/35 第一次对教材代码进行自己的修改
    第三周 400/700 2/7 20/50 熟练的进行代码托管
    第四周 1210/1910 2/9 30/80 在敲代码的时候有自己思考

    代码行数:

    代码托管截图:

    参考资料

  • 相关阅读:
    JS判断鼠标移入元素的方向
    EJB开发第一个无状态会话bean、开发EJBclient
    Android摇一摇振动效果Demo
    吃饭与团队惬意
    Factorization Machines 学习笔记(三)回归和分类
    代理---视图间数据的传递:标签显示输入的内容【多个视图中】
    cocos2d-x v3.2 FlappyBird 各个类对象详细代码分析(7)
    金典 SQL笔记(4)
    用GDB调试多进程程序
    C程序设计的抽象思维-算法分析-大多数元素
  • 原文地址:https://www.cnblogs.com/20145208cy/p/5323712.html
Copyright © 2020-2023  润新知