《Java编程思想》学习笔记 第6-9章

第六章 访问权限控制

  1. 包名需要独一无二
  2. java访问权限修饰词
  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。

接口和实现

  1. 访问权限的控制常被称为是具体实现的隐藏。**封装:**把数据和方法包装进类中,以及具体实现的隐藏。其结果是一个同时带有特征和行为的数据类型。

类的访问权限

  1. 每个编译单元都只有一个public类。表示每个编译单元都有单一的公共接口用public类来实现。
  2. public类的名称必须完全与含有编译单元的文件相匹配,包括大小写。
  3. 虽然不常用,但是编译单元内完全不带public类也是有可能的。

第七章 复用类

  • https://blog.csdn.net/u013008179/article/details/79619803

两种方式

  1. 只需要在新的类中产生现有类的对象,由于新的类是由现有类的对象所组成,所以这种方法称为组合
  2. 方法则更细致一些:它按照现有类的类型来创建新类,无需改变现有类的形式,采用现有类的形式并在其中添加新的代码,这种神奇的方式被称为继承

组合语法

  • 只需将对象引用置于新类中即可
  • 类中域为基本类型时能够自动被初始化为0,但是对象引用会被初始化为null,编译器并不是简单的为每一个引用都创建默认对象,这一点是很有意义的,因为若真要那样做的话,就会在许多情况下增加不必要的负担,如果想要初始化这些引用,可以在代码中的下列位置进行
    ①:在定义对象的地方,这意味着它们总是能够在构造器被调用之前被初始化
    ②:在类的构造器中
    ③:就在正在使用这些对象之前,这种方式被称为惰性初始化.在生成对象不值得及不必要每次都生成对象的情况下,这种方式可以减少额外的负担.
    ④:使用实例初始化

继承语法

  • 当创建一个类时,总是在继承,因此,除非已明确指出要从其他类中继承,否则就是在隐式的从java标准根类object进行继承
  • 可以把继承看做是对类的复用
  • java使用super()关键字表示超类(父类)的意思,当前类就是从超类继承来的.
  • 对基类子对象的正确初始化也是至关重要的,而且也仅有一种方式来保证这一点:在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需要的所有知识和能力.java会自动在导出类的构造器中插入对基类构造器的调用.
    ①:初始化无参构造器:无参编译器可以轻松的调用
    ②:带参数的构造器:必须用super()显示地编写调用基类构造器的语句,并且配以适当的参数列表
    ③:调用基类构造器必须是你在导出类构造器中要做的第一件事.

代理

  • 代理:java并没有提供对它的直接支持.这是继承与组合之间的中庸之道.因为我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的所有方法(就像继承).

结合使用组合与继承

  • 同时使用组合和继承是很常见的事
  • 最好的清理办法是除了内存以外,不能依赖垃圾回收器去做任何事情.如果需要进行清理,最好是编写你自己的清理方法,但是不要使用finalize().
  • 如果java的基类拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法名称并不会屏蔽其在基类中的任何版本,因此,无论是在该层或者它的基类中对方法进行定义,重载机制都可以正常工作

protected关键字

  • 它指明了就类而言,这是private的,紧靠关键字private就已经足够了.但是在实际项目中,经常会想将某些事物尽可能对这个世界隐藏起来,但仍然允许导出类的成员访问它们.关键字protected就是起这个作用的.它指明就类用户而言,这是private的,但是对于任何继承与此类的导出类或其他任何位于同一个包内的类来说,它却是可以访问的.

向上转型

  • “为新的类提供方法”并不是继承技术中最重要的方面,其最重要的的方面是用来表现 新类和基类之间的关系.这种关系可以用”新类是现有类的一种类型”这句话加以概括.
  • 由于继承可以确保基类中所有的方法在导出类中同样有效,所以能够向基类发送的所有信息同样也可以向导出类发送
  • 将子类引用转换为父类引用的动作,我们称之为向上转型.由于向上转型是从一个较专业的类型向通用类型转换,所以总是安全的,也就是说,导出类是基类的一个超集.它可能比基类含有更多的方法,但它必须至少具备基类中所有的方法.在向上转型的过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取它们.这就是为什么编译器在”未曾明确表示转型”或”未曾指定特殊标记”的情况下,仍然允许向上转型的原因.

final关键字

  • final数据:有时数据的恒定不变是很有用的,比如:
    ①:一个永不改变的编译时常量.
    ②:一个在运行时被初始化的值,而你不希望它被改变
  • 一个既是static又是final的域只占据一段不能改变的存储空间.
  • 编译时常量和运行时常量
    我们用final来修饰以上两种数据来保持它们恒定不变,其中,对于编译时常量,编译器可以在编译时将该常量值代入任何需要它的地方执行计算公式,减轻了一些运行时的负担,在java中,编译时常量必须是基本数据类型,尽管经常看到诸如pubic static final String VAR = “var”这样的代码,但是,这个“VAR”并不是一个编译时常量,也许很多人碰到这样的面试题都会做错。
    当final用于对象引用而不是基本类型时,表示的是对象的引用恒定不变,对象一旦被初始化后,虽然对象自身可以随意修改,但是这个对象的引用无法再指向另一个对象。
    注意:以上关于final用于对象引用的情况同时也使用于数组,因为数组也是对象。
  • 编译时常量与运行时常量的区别?
    ①:编译时常量并不依赖于类,而运行时常量依赖类
    ②:编译时常量在编译时确定值,而运行时常量在编译时是不可能确定值的
    ③:由于编译时常量不依赖类,所以对编译时常量的访问不会引发类的初始化.
    ④:静态块的执行在运行时常量之前,在编译常量之后
    ⑤:我们不能因为某数据是final的就认为在编译时可以知道它的值.因为运行时常量是在运行时候生成的值
  • final与 static final区别?
    VALUE_TWO不变,这是因为它是static的,在装载时已被初始化,而不是每次创建新对象时都被初始化.

第八章 多态

  • https://blog.csdn.net/pengbo6665631/article/details/82492237
  • 多种类型(从同一基类导出的)视为同一类型来处理
    同一份代码也就可以毫无差别地运行在这些不同类型之上了

再论向上转型

  • 对象可以作为自己本身使用,也可以作为它的基类型使用
  • 把对某个对象的引用视为对基类型的引用的做法被称作向上转型
  • 如果让drive(Car car)方法接受Jeep的引用,看起来更直观
  • 但是如果我新添加了若干种车,比如:宝马、奔驰、奥迪、比亚迪等等
  • 那么还得再为它们写对应的drive方法,那么就需要更多的编程,做大量的工作

转机

绑定
  • 将一个方法调用同一个方法主体关联起来被称作绑定
  • 程序执行前进行绑定,叫做前期绑定
  • 程序运行时进行绑定,叫做后期绑定,在对象中安置了某种信息
  • Java中除了static和final方法(包括private)以外所有方法都是后期绑定
  • 将某个方法声明为final,可以防止其他人覆盖该方法,“关闭”动态绑定,生成更有效的代码
  • 大多数情况下并不会对程序的性能有什么提升,所以最好是根据设计而不是性能来使用final
可扩展性
  • 如果上面的Car的例子中添加一个drift()漂移的方法,我们添加新的方法并不会影响drive()方法去调用move()方法
  • 我们所做的代码修改,不会对程序中其他不应受到影响的部分产生破坏
  • 多态让程序员将“改变的事物与未变的事物分离开来”
缺陷:域或静态方法
  • 域不是多态的,和方法是不一样的
  • 静态方法也不具有多态性
  • 静态属性,静态方法,和非静态属性都不具有多态性
  • 简单说,域和静态方法都不具有多态性

构造器和多态

构造器调用顺序
  • 基类的构造器总是在导出类的构造过程中被调用,按照继承层次逐渐向上链接
  • 如果没有明确指定调用某个基类的构造器,它就会默默地调用默认构造器
继承与清理
  • 销毁的顺序应该与初始化的顺序相反
构造器内部的多态方法的行为
  • 如果构造器的内部调用正在构造的对象的某个动态绑定方法
  • 比如或基类的构造器中调用一个被覆盖的方法
  • 被覆盖的方法在对象完全构造之前就被调用,可能会造成一些难于发现的隐藏错误
  • 尽可能的用简单的方法使对象进入正常状态
  • 避免调用其他方法,能安全调用的是final方法(private方法)

协变返回类型

用继承进行设计

  • 组合更加灵活,优先选择组合
纯继承与扩展
  • 纯继承就是完全和基类一样,是一个(is-a)的关系
  • 扩展就是在基类的基础上增加额外信息,像一个(like-a)的关系
  • 扩展导致扩展部分不能被基类所访问

总结

  • 多态意味着“不同的形式”,多态可以带来很多的成效,更快的程序开发过程、更好的代码组织、更好扩展的程序以及更容易的代码维护等

第九章 接口

  • https://blog.csdn.net/chuxue1989/article/details/88238699

抽象类

  • 如果一个类中有抽象方法,那么该类也必须设置成abstract,而一个抽象类可以有0个或者多个抽象方法也可以有非抽象方法和字段

接口

  • 接口使抽象的概念更向前迈进了一步,他是一个完全的抽象类,他根本就没有具体的实现。它里面的字段默认都是 static final修饰的,方法默认都是 public abstract修饰的
  • 接口中的域不能是空final

完全解耦

  • 抽象类是继承概念,继承就代表他们是一个类型的东西
  • 接口是实现概念,这个就是说明该类有接口的实现,也可以说有接口的功能
  • 只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类,如果你想将此方法应用在不在此继承体系的某个类,那么就会不合适。
  • 如果是接口,即使不在此继承体系中,只要实现了接口的方法的类也会适合该方法。从这个方面说接口更能解耦
  • Java中的设计模式更能说明这个问题:适配器模式
1. 类适配器
  • 这个用的非常少,这个要求适配器和要适配的类是一个体系,这里使用的情况就很少
2. 对象适配器
  • 经典的设计模式,在实际情况中,你编写的类很难和调用者的类完全适配,这个时候你基本不会说修改你想要使用的类,因为代价太大,可能很对类对这个类有依赖。所以你需要对这个类进行包装,经过包装后,和调用者的类进行适配。
    jdk经典的 InputStreamRead,就是对inputStream进行包装来适用Read。
3. 接口适配器
  • 经典的用法。很多时候接口的方法很多,但是我们只需要接口的一部分方法,这个时候你基本不会在创建一个类似的接口(只包含原来接口的部分方法),因为这样代码复用性不高,这个时候写一个抽象类对接口进行默认实现,这样创建新类的时候只要继承该抽象类,覆盖你想要的功能(方法即可)

java的多重继承

  • 接口不仅仅是一种更纯粹的抽象类,他的目标比这更高
  • 一个类可以实现多个接口,这也是使用接口的核心原因:为了能够向上转型为多个基类型

通过继承扩展接口

  • 接口可以继承接口,而且可以继承多个接口

接口和类的选择

  • 接口真的很诱人,动态绑定值真的很神奇,通过类能解决的都能用创建接口解决。所以这就引出了一个问题:改如何选择
  • 答:恰当的原则是有限选择类而不是接口,从类开始,如果接口的必要性变得非常明确,那么久进行重构,接口是一种重要的工具,但是他们容易被滥用

你可能感兴趣的:(java基础)