软件构造——OOP复习总结

大纲

OOP基本概念:object, class, attribute, method, interface, and enumerations
OOP的独特特征:

  • 封装与信息隐藏
  • 继承与重写
  • 多态、子类型、重载
  • 静态与动态分派

Java中的一些重要的对象方法
设计良好的CLASS

基本概念:对象、类、属性和方法

1.Object

  • 状态 该对象中所包含的数据 fields
  • 行为 该对象所支持的操作 methods

Class variable 类成员变量(static 修饰)
class methods类方法(static 修饰)
instance methods 实例方法(必须创建实例)
instance variables 实例成员变量(必须创建实例)
类变量和类方法与一个类相关联,并且每个类发生一次。使用它们并不需要创建对象。
实例方法和变量在每个类的实例中发生一次。

实例变量/方法vs 类变量/方法

class DateApp {
 public static void main(String args[]) {
 Date today = new Date();
 System.out.println(today);
 }
}
class Another {
 public static void main(String[] args) {
 int result;
 result = Math.min(10, 20); 
 System.out.println(result);
 System.out.println(Math.max(100, 200));
 }
}

静态方法不与类的任何特定实例进行关联,而必须在特定对象上调用实例方法(没有静态关键字而声明)。

class Difference {
 public static void main(String[] args) {
 display(); //calling without object
 Difference t = new Difference();
 t.show(); //calling using object
 }
 static void display() {
      System.out.println("Programming is amazing.");
 }
 void show(){
      System.out.println("Java is awesome.");
 }
}
public class MyStatic {
 private String name;
 private static String staticStr = "STATIC-STRING";
 
 public MyStatic (String n){
 this.name = n;
 }
 
 public static void testStaticMethod(){
//you can call static variables here, can not call instance variables
 System.out.println(MyStatic.staticStr); 
 }
 public void testObjectMethod(){
 //you can also call static and instance variables here
 System.out.println(MyStatic.staticStr); 
 System.out.println("Name: "+this.name);
 }
 
 public static void main(String a[]){
 //By using class name, you can call static method
 MyStatic.testStaticMethod();
 MyStatic msm = new MyStatic ("Java2novice");
 msm.testObjectMethod();
 }
}

2.Interface and Enumerations

Java的接口是设计和表达ADT的有用语言机制,其实现为实现该接口的类。

  • Interface和Class: 定义和实现ADT
  • 接口之间可以继承与扩展
  • 一个类可以实现多个接口(从而具备了多个接口中的方法)
  • 一个接口可以有多种实现类

Java接口和类

接口:确定ADT规约;
类:实现ADT;
实际中更倾向于使用接口来定义变量

  • 对变量和参数使用接口类型,除非您知道只有一个实现就足够了
  • 支持改变实现情况

一个例子

 /** Represents an immutable set of elements of type E. */
 public interface Set<E> {
 /** make an empty set */
 public Set();   //Java interfaces can’t have constructors
 /** @return true if this set contains e as a member */
 public boolean contains(E e);
 /** @return a set which is the union of this and that */
 public ArraySet<E> union(Set<E> that); 
 //It isn’t representation-independent
 }
 /** Implementation of Set<E>. */
 public class ArraySet<E> implements Set<E> {
 /** make an empty set */
 public ArraySet() { ... }
 /** @return a set which is the union of this and that */
 public ArraySet<E> union(Set<E> that) { ... }
 /** add e to this set */
 public void add(E e) { ... }
 //This violates the spec for Set, its immutability, so ArraySet is not a legal implementation of Set.
 //It’s missing the contains() method
 }

– 打破了抽象边界,接口定义中没有包含constructor,也无法保证所有实现类中都包含了同样名字的constructor。
– 故而,客户端需要知道该接口的某个具体实现类的名字。
在这里插入图片描述

使用静态工厂,而不是构造函数
在这里插入图片描述

在接口中使用默认方法:

接口中的每个方法在所有实现类里都要实现。
以增量式的为接口增加额外的功能而不破坏已实现的类。
在这里插入图片描述

Enumerations

public enum Month { 
 JANUARY, FEBRUARY, MARCH, ..., 
 OCTOBER, NOVEMBER, DECEMBER;
}
public enum PenColor { 
 BLACK, GRAY, RED, ..., BLUE;
}
PenColor drawingColor = PenColor.RED;
Month month = Month.MARCH;
if(month.equals(Month.MARCH)) {...}
for(Month m : Month.values()) 
 m.name();
 m.ordinal();
 m.comparedTo();
 m.toString();
 ......
public enum Planet {
 MERCURY(3.302e+23, 2.439e6), VENUS (4.869e+24, 6.052e6),
 EARTH(5.975e+24, 6.378e6), MARS(6.419e+23, 3.393e6);
 private final double mass; // In kg.
 private final double radius; // In m.
 private static final double G = 6.67300E-11;
 
 Planet(double mass, double radius) {
 this.mass = mass;
 this.radius = radius;
 }
 public double mass() { return mass; }
 public double radius() { return radius; }
 public double surfaceGravity() {
 return G * mass / (radius * radius);
 }
}



for (Planet p : Planet.values()) 
 System.out.println(p.surfaceGravity());

4封装和信息隐藏

精心设计的代码隐藏了所有实现细节
—将API与实现清晰分离
—模块仅通过API通信
—忽略彼此的内部工作
信息隐藏的好处:

  • Decouples(解耦)组成一个系统的类
    允许它们被单独地开发、测试、优化、使用、理解和修改
  • 加快系统开发速度
  • 减轻维护工作的负担
  • 启用有效的性能调整
  • 增加了软件的可重用性
    -松散耦合的类在其他上下文中通常被证明是有用的

使用接口隐藏的信息:
- 使用接口类型声明变量
- 客户端仅使用接口中定义的方法
- 客户端代码无法直接访问属性
private -声称类
protected -声称类的子类
public -所有类

5 Inheritance and Overriding

(1) Overriding重写

可重写的方法和严格的继承

可重写方法:一种允许重新实现的方法。
严格继承:子类只能添加新方法,无法重写超类中的方法
父类

public class Car {
 public final void drive() {}
 public final void brake() {}
 public final void accelerate() {}
}

子类

public class LuxuryCar extends Car {
 public void playMusic() {}
 public void ejectCD() {}
 public void resumeMusic() {}
 public void pauseMusic() {}
}

final

final字段:防止在初始化后重新分配到该字段
final方法:防止覆盖该方法
final类:阻止扩展该类
e.g., public final class CheckingAccountImpl { … }

Overriding (覆盖/重写)

重写的函数:完全同样的signature
实际执行时调用哪个方法,运行时决定。
如果使用父类的对象来调用该方法,则将执行父类中的版本;
如果使用子类的对象来调用该方法,则将执行子类中的版本。
覆盖一个方法

class Device {
 int serialnr;
 public final void help() {.}
 public void setSerialNr(int n) {
 serialnr = n;
 }
}

父类型中的被重写函数体不为空:意味着对其大多数子类型来说,该方法是可以被直接复用的。

class Valve extends Device {
 Position s;
 public void on() {}
 public void setSerialNr(int n) {
 serialnr = n + s.serialnr;
 }
}

对某些子类型来说,有特殊性,故重写父类型中的函数,实现自己的特殊要求。
可重写的方法被设置为空:

class Device {
 int serialnr;
 public void setSerialNr(int n) {}
}
class Valve extends Device {
 Position s;
 public void on() {..
 }
 public void setSerialNr(int n) {
 seriennr = n + s.serialnr;
 }
} // class Valve

如果父类型中的某个函数实现体为空,意味着其所有子类型都需要这个功能,但各有差异,没有共性,在每个子类中均需要重写。
当子类包含覆盖超类方法的方法时,它也可以通过使用关键字super援引超类法。

class Thought {
 public void message() {
 System.out.println(“Thought.");
 }
}
public class Advice extends Thought {
 @Override // @Override annotation in Java 5 is optional but helpful.
 public void message() {
 System.out.println(“Advice.");
 super.message(); // Invoke parent's version of method.
 }
}

Thought parking = new Thought();
parking.message(); // Prints "Thought."

Thought dates = new Advice(); 
dates.message(); // Prints “Advice. \n Thought.”

Constructors with this and super

在这里插入图片描述
重写的时候,不要改变原方法的本意

(2) Abstract Class

Abstract method:一种具有签名但没有实现(也称为抽象操作)的方法。
Abstract class:包含至少一个抽象方法的类称为抽象类。
接口:一个只有抽象方法的抽象类

abstract class GraphicObject {
 int x, y;
 ...
 void moveTo(int newX, int newY) {
 ...
 }
 abstract void draw();
 abstract void resize();
}

如果某些操作是所有子类型都共有,但彼此有差别,可以在父类型中设计抽象方法,在各子类型中重写

class Circle extends GraphicObject {
 void draw() {
 ...
 }
 void resize() {
 ...
 }
}
class Rectangle extends GraphicObject {
 void draw() {
 ...
 }
 void resize() {
 ...
 }
}

所有子类型完全相同的操作,放在父类型中实现,子类型中无需重写。
有些子类型有而其他子类型无的操作,不要在父类型中定义和实现,而应在特定子类型中实现。

Polymorphism, subtyping and overloading 多态、子类型、重载

(1) Three Types of Polymorphism

特殊多态:function overloading (功能重载)
参数化多态:泛型
子类型多态、包含多态

(2) Ad hoc polymorphism and Overloading 特殊多态和重载

public class OverloadExample {
public static void main(String args[]) {
System.out.println(add("C","D"));
System.out.println(add("C","D","E"));
System.out.println(add(2,3));
}
public static String add(String c, String d) {
return c.concat(d);
}
public static String add(String c, String d, String e){
return c.concat(d).concat(e);
}
public static int add(int a, int b) {
return a+b;
} }

重载:多个方法具有同样的名字,但有不同的参数列表或返回值类型
价值:方便client调用,client可用不同的参数列表,调用同样的函数
重载是静态多态:

  • 根据参数列表进行最佳匹配
  • 静态类型检查
  • 在编译阶段时决定要具体执行哪个方法 (static type checking)

可以在一个类中重载,也可以在子类中重载
要调用的方法的哪个重写版本在***运行时***根据对象类型决定,但是要调用的方法的哪个重载版本基于在***编译时***传递的参数的引用类型。

Overriding vs. Overloading

public class Test { 
 public static void main(String[] args) { 
 A a = new A(); 
 a.p(10); 
 } 
} 
class B { 
 public void p(int i) { 
 } 
} 
class A extends B { 
 // This method overrides the method in B 
 public void p(int i) { 
 System.out.println(i); 
 } 
}
public class Test { 
 public static void main(String[] args) { 
 A a = new A(); 
 a.p(10); 
 } 
} 
class B { 
 public void p(int i) { 
 } 
} 
class A extends B { 
 // This method overloads the method in B 
 public void p(double i) { 
 System.out.println(i); 
 } 
}

注意,当派生类重载原始方法时,它仍然会从基类继承原始方法。
在这里插入图片描述

(3) Parametric polymorphism and Generic programming 参数多态

它能够以泛型方式定义函数和类型,以便基于运行时传递的参数来工作,即允许在不完全指定类型的情况下进行静态类型检查。
泛型编程是一种编程风格,其中数据类型和函数用稍后指定的类型编写,然后在需要时为参数提供的特定类型进行实例化。
通用编程围绕着从具体的、有效的算法中抽象的想法,以获得可以与不同数据表示相结合的通用算法,以产生各种有用的软件。
-类型变量
它们由泛型类声明、泛型接口声明、泛型方法声明和泛型构造函数声明引入。

泛型类:

其定义中包含了类型变量。这些类型变量被称为类的类型参数。

  • 它定义了一个或多个作为参数的类型变量。
  • 泛型类声明定义一组参数化类型,对于类型参数部分的每个可能调用一个。
  • 所有这些参数化的类型在运行时共享相同的类。

泛型接口

这些类型变量被称为接口的类型参数。
-它定义了一个或多个作为参数的类型变量。
-通用接口声明定义一组类型,类型参数部分的每个可能调用。
-所有参数化的类型在运行时共享相同的接口。

泛型方法

  • 这些类型变量被称为该方法的形式类型参数。
  • 形式类型参数列表的形式与类或接口的类型参数列表相同。

使用菱形运算符<>来帮助声明类型变量
– List ints = new ArrayList();
– public interface List
– public class Entry<KeyType, ValueType>

public class PapersJar<T> {
private List<T> itemList = new ArrayList<>();
public void add(T item) {
itemList.add(item);
}
public T get(int index) {
return (T) itemList.get(index);
}
public static void main(String args[]) {
PapersJar<String> papersStr = new PapersJar<>();
papersStr.add("Lion");
String str = (String) papersStr.get(0);
System.out.println(str);
PapersJar papersInt = new PapersJar();
papersInt.add(new Integer(100));
Integer integerObj = (Integer) papersInt.get(0);
System.out.println(integerObj);
} }
public class Pair<E> {
 private final E first, second;
 public Pair(E first, E second) {
 this.first = first;
 this.second = second;
 }
 public E first() { return first; }
 public E second() { return second; }
}
Client:
Pair<String> p = new Pair<>("Hello", "world");
String result = p.first();

集合是一些其他类型的E的有限元素集的ADT。
在这里插入图片描述
泛型接口,非泛型的实现类
泛型接口,泛型的实现类 Java’s HashSet does that for Set.

(4) Subtyping Polymorphism

子类型仅仅是超类型的子集

  • ArrayList 和 LinkedList 是 List的子集.
    在JAVA中,一个类只能继承一个父类,一个类可以实现多个接口。
    在这里插入图片描述
    “B是A的一个子类型”的意思是“每个B都是一个A” .”
    就规范而言:“每个B都满足规范 A.”
    但是编译器不能检查我们是否没有以其他方式削弱了规范:
    子类型的规约不能弱化超类型的规约。
    子类型多态:不同类型的对象可以统一的处理而无需区分

里氏替换原则:

  • 若对每个类型S的对象o1,都存在一个类型T的对象o2,使得在所有针对T编写的程序P中用o1替换o2后,程序P行为功能不变,则S是T的子类型。

永远不要downcast within superclass to a subclass

10在Java中的一些重要的对象方法

§ equals() – true if the two objects are “equal”
§ hashCode() – a hash code for use in hash maps
§ toString() – a printable string representation
在这里插入图片描述
在这里插入图片描述
替代的hashCode覆盖
在这里插入图片描述

11 Designing good classes

不可变类的优点:
简单的
固有线程安全
可以自由共享
不需要防御拷贝
优秀的构建块
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值