IE盒子

搜索
查看: 90|回复: 1

Java编程思想读书笔记(六)

[复制链接]

5

主题

12

帖子

25

积分

新手上路

Rank: 1

积分
25
发表于 2022-12-28 13:49:19 | 显示全部楼层 |阅读模式
今天是五月的最后一天,明天六一了,祝各位朋友们儿童节快乐呀。希望大家永葆童真,坚守初心。每天开开心心,新的六月祝你生活更简单,生活更美好,笑容更灿烂。
今晚,我们开启了新的篇章,第六章 类再生。读了这么久,这本书给我带来的帮助还是挺大的,回顾前几期的笔记,我发现自己越来越热爱读这本书,自己的公众号排版越来越规整,看起来越来越舒服,可能这是我的成长吧。当然成长的背后,是大家的支持与鼓励,谢谢大家给我提供的建议。
“Java引人注目的一项特性是代码的重复使用或者再生,但最具革命意义的是,除代码的复制和修改以外,我们还能做许多其他的事。”
Java中提供两种方法来充分使用代码的方法,第一种是在新类中创建原有类的对象,这种方式叫做“合成”。第二种就是创建一个新类,作为现有的类的一个类型,我们可以原样采取现有类的形式,并加入新的代码,但不会对现有的类造成影响。这就是“继承”。这两句是本书的原话,说的不太明白,我自己润色了一下。第一种是创建新类的时候,把原有的类的对象放入就算合成了。第二种就是继承原有类的属性和方法,再添加新的属性和方法。对原有的类不会造成影响。
6.1 合成的语法

合成语法,我以Java编程思想的例子解释一下。
class WaterSource {
    private String s;
    WaterSource() {
        System.out.println("WaterSource()");
        s = new String("Constructed");
    }
    public String toString() {
        return s;
    }
}

public class SprinklerSystem {

    private String valve1, valve2, valve3, valve4;
    WaterSource source;
    int i;
    float f;
    void print() {
        prt("valve1 = " + valve1);
        prt("valve2 = " + valve2);
        prt("valve3 = " + valve3);
        prt("valve4 = " + valve4);
        prt("i = " + i);
        prt("f = " + f);
        prt("source = " + source);      
    }
   
    public static void main(String[] args) {
        SprinklerSystem x = new SprinklerSystem();
        x.print();
    }
   
    static void prt(String s) {
        System.out.println(s);
    }
}这看起来很蒙圈,我又在网上找了一个例子。https://blog.csdn.net/xiaoxiaoxiaohaozi/article/details/50942533
class Engine {
    public void start() {
    }
    public void rev() {
    }
    public void stop() {
    }
}

class Wheel {
    public void inflate(int psi) {
    }
}

class Window {
    public void rollup() {
    }
    public void rolldown() {
    }
}

class Door {
    public Window window = new Window();
    public void open() {
    }

    public void close() {
    }
}

public class Car {
    public Engine engine = new Engine();
    public Wheel[] wheel = new Wheel[4];
    public Door left = new Door(), right = new Door(); // 2-door

    Car() {
        for (int i = 0; i < 4; i++)
            wheel = new Wheel();
    }

    public static void main(String[] args) {
        Car car = new Car();
        car.left.window.rollup();
        car.wheel[0].inflate(72);
    }
}由于汽车的装配是故障分析时需要考虑的一项因素(并非只是基础设计简单的一部分),所以有助于客户程序员理解如何使用类,而且类创建者的编程复杂程度也会大幅度降低。 如选择继承,就需要取得一个现成的类,并制作它的一个特殊版本。通常,这意味着我们准备使用一个常规用途的类,并根据特定的需求对其进行定制。只需稍加想象,就知道自己不能用一个车辆对象来合成一辆汽车——汽车并不“包含”车辆;相反,它“属于”车辆的一种类别。“属于”关系是用继承来表达的,而“包含”关系是用合成来表达的,这样是不是很清晰了。
6.2 基础的语法

类继承,“这个新类和那个旧类差不多。”为了在代码里表面这一观念,需要给出类名。但在类主体的起始花括号之前,需要放置一个关键字extends,在后面跟随“基础类”的名字。若采取这种做法,就可自动获得基础类的所有数据成员以及方法。
class Cleanser {
    private String s = new String("Cleaner");
    public void append(String a) { s += a; }
   
    public void dilute() {
        append(" dilute()");
    }
    public void apply() {
        append(" apply()");
    }
   
    public void scrub() {
        append(" scrub()");
    }
    public void print() {
        System.out.println(s);
    }
   
    public static void main(String[] args) {
        
        Cleanser x = new Cleanser();
        x.dilute();
        x.apply();
        x.scrub();
        x.print();
    }
}

public class Detergent extends Cleanser{

    // Change a method :
    public void scrub() {
        append(" Detergent.scrub()");
        super.scrub();  // Call base-class version
    }
    // Add methods to the interface :
    public void foam() {
        append(" foam()");
    }
   
    public static void main(String[] args) {
        Detergent x = new Detergent();
        x.dilute();
        x.apply();
        x.scrub();
        x.foam();
        x.print();
        System.out.println("Texting base class : ");
        Cleanser.main(args);
    }
}无论Cleanser 还是Detergent 都包含了一个main()方法。我们可为自己的每个类都创建一个main()。通常建议大家象这样进行编写代码,使自己的测试代码能够封装到类内。即便在程序中含有数量众多的类,但对于在命令行请求的public 类,只有main()才会得到调用。所以在这种情况下,当我们使用“java Detergent”的时候,调用的是Degergent.main()——即使Cleanser 并非一个public 类。采用这种将main()置入每个类的做法,可方便地为每个类都进行单元测试。而且在完成测试以后,毋需将main()删 去;可把它保留下来,用于以后的测试。 在这里,大家可看到Deteregent.main()对Cleanser.main()的调用是明确进行的。 注意Cleanser 在它的接口中含有一系列方法:append(),dilute(),apply(),scrub()以及print()。由于Detergent 是从Cleanser 衍生出来的(通过extends 关键字),所以它会自动获得接口内的所有这些方法——即使我们在Detergent 里并未看到对它们的明确定义。这样一来,就可将继承想象成“对接口的重复利用”或者“接口的再生”(以后的实施细节可以自由设置,但那并非我们强调的重点)。 正如在scrub()里看到的那样,可以获得在基础类里定义的一个方法,并对其进行修改。在这种情况下,我们通常想在新版本里调用来自基础类的方法。但在scrub()里,不可只是简单地发出对scrub()的调用。那样便造成了递归调用,我们不愿看到这一情况。为解决这个问题,Java 提供了一个super 关键字,它引用当前类已从中继承的一个“超类”(Superclass)。所以表达式super.scrub()调用的是方法scrub()的基础类版本。 进行继承时,我们并不限于只能使用基础类的方法。亦可在衍生出来的类里加入自己的新方法。这时采取的做法与在普通类里添加其他任何方法是完全一样的:只需简单地定义它即可。extends 关键字提醒我们准备将新方法加入基础类的接口里,对其进行“扩展”。foam()便是这种做法的一个产物。
6.3  上溯造型

继承是对新类和基础类之间的关系的一种表达。 可这样总结该关系:“新类属于现有类的一种类型”。这种表达并不仅仅是对继承的一种形象化解释,继承是直接由语言提供支持的。作为一个例子,大家可考虑一个名为Instrument 的基础类,它用于表示乐器;另一个衍生类叫作Wind。由于继承意味着基础类的所有方法亦可在衍生出来的类中使用,所以我们发给基础类的任何消息亦可发给衍生类。若Instrument 类有一个play()方法,则Wind 设备也会有这个方法。这意味着我们能肯定地认为一个Wind 对象也是Instrument 的一种类型。下面这个例子揭示出编译器如何提供对这一概念的支持:
class Instrument {
    public void play() {
    }

    static void tune(Instrument i) {
        // ...
        i.play();
    }
}

// Wind objects are instruments
// because they have the same interface:
class Wind extends Instrument {
    public static void main(String[] args) {
        Wind flute = new Wind();
        Instrument.tune(flute); // Upcasting
    }
}程序正常运行,没有报错。 这个例子中最有趣的无疑是tune()方法,它能接受一个Instrument 句柄。但在Wind.main()中,tune()方法是通过为其赋予一个Wind 句柄来调用的。由于Java 对类型检查特别严格,所以大家可能会感到很奇怪,为什么接收一种类型的方法也能接收另一种类型呢?但是,我们一定要认识到一个Wind 对象也是一个Instrument 对象。而且对于不在Wind 中的一个Instrument(乐器),没有方法可以由tune()调用。在tune()中,代码适用于Instrument 以及从Instrument 衍生出来的任何东西。在这里,我们将从一个Wind 句柄转换成一个Instrument 句柄的行为叫作“上溯造型”。
6.4 final关键字

一.final关键字的基本用法

  在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下final关键字的基本用法。
  1.修饰类
  当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。
  2.修饰方法
  “使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“
  因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。
  注:类的private方法会隐式地被指定为final方法。
  3.修饰变量
  修饰变量是final用得最多的地方,也是本文接下来要重点阐述的内容。首先了解一下final变量的基本语法:
  对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
回复

使用道具 举报

1

主题

10

帖子

15

积分

新手上路

Rank: 1

积分
15
发表于 3 天前 | 显示全部楼层
顶起出售广告位
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表