本节讲学习ADT的具体实现技术:OOPjava
【对象】编程
【类】数组
【接口】安全
一个接口的实例:编程语言
/** MyString represents an immutable sequence of characters. */ public interface MyString { // We'll skip this creator operation for now // /** @param b a boolean value // * @return string representation of b, either "true" or "false" */ // public static MyString valueOf(boolean b) { ... } /** @return number of characters in this string */ public int length(); /** @param i character position (requires 0 <= i < string length) * @return character at position i */ public char charAt(int i); /** Get the substring between start (inclusive) and end (exclusive). * @param start starting index * @param end ending index. Requires 0 <= start <= end <= string length. * @return string consisting of charAt(start)...charAt(end-1) */ public MyString substring(int start, int end); }
一种实现:ide
1 public class FastMyString implements MyString { 2 3 private char[] a; 4 private int start; 5 private int end; 6 7 /** Create a string representation of b, either "true" or "false". 8 * @param b a boolean value */ 9 public FastMyString(boolean b) { 10 a = b ? new char[] { 't', 'r', 'u', 'e' } 11 : new char[] { 'f', 'a', 'l', 's', 'e' }; 12 start = 0; 13 end = a.length; 14 } 15 16 // private constructor, used internally by producer operations. 17 private FastMyString(char[] a, int start, int end) { 18 this.a = a; 19 this.start = start; 20 this.end = end; 21 } 22 23 @Override public int length() { return end - start; } 24 25 @Override public char charAt(int i) { return a[start + i]; } 26 27 @Override public MyString substring(int start, int end) { 28 return new FastMyString(this.a, this.start + start, this.end + end); 29 } 30 }
客户端如何使用此ADT?这是一个例子:函数
MyString s = new FastMyString(true); System.out.println("The first character is: " + s.charAt(0));
但其中有问题,这么实现接口打破了抽象边界,接口定义中没有包含constructor,也没法保证全部实现类中都包含了一样名字的constructor。 故而,客户端须要知道该接口的某个具体实现类的名字。由于Java中的接口不能包含构造函数,因此它们必须直接调用其中一个具体类的构造函数。该构造函数的规范不会出如今接口的任何地方,因此没有任何静态的保证,即不一样的实现甚至会提供相同的构造函数。性能
在Java 8中,咱们能够用valueof的静态工厂方法 代替构造器。学习
public interface MyString { /** @param b a boolean value * @return string representation of b, either "true" or "false" */ public static MyString valueOf(boolean b) { return new FastMyString(true); } // ...
此时,客户端使用ADT就不会破坏抽象边界:ui
MyString s = MyString.valueOf(true); System.out.println("The first character is: " + s.charAt(0));
总结:接口的好处
Safe from bugs
ADT是由其操做定义的,接口就是这样作的。
当客户端使用接口类型时,静态检查确保他们只使用由接口定义的方法。
若是实现类公开其余方法,或者更糟糕的是,具备可见的表示,客户端不会意外地看到或依赖它们。
当咱们有一个数据类型的多个实现时,接口提供方法签名的静态检查。
Easy to understand
客户和维护人员确切知道在哪里查找ADT的规约。
因为接口不包含实例字段或实例方法的实现,所以更容易将实现的细节保留在规范以外。
Ready for change
经过添加实现接口的类,咱们能够轻松地添加新类型的实现。
若是咱们避免使用静态工厂方法的构造函数,客户端将只能看到该接口。
这意味着咱们能够切换客户端正在使用的实现类,而无需更改其代码。
【抽象类】
【封装】
public class Person { private String name; private int age; }
1 public class Person{ 2 private String name; 3 private int age; 4 5 public int getAge(){ 6 return age; 7 } 8 9 public String getName(){ 10 return name; 11 } 12 13 public void setAge(int age){ 14 this.age = age; 15 } 16 17 public void setName(String name){ 18 this.name = name; 19 } 20 }
采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
【继承与重写】
super
调用超类方法。例子以下:
1 class Animal{ 2 public void move(){ 3 System.out.println("动物能够移动"); 4 } 5 } 6 7 class Dog extends Animal{ 8 public void move(){ 9 super.move(); // 应用super类的方法 10 System.out.println("狗能够跑和走"); 11 } 12 } 13 14 public class TestDog{ 15 public static void main(String args[]){ 16 17 Animal b = new Dog(); // Dog 对象 18 b.move(); //执行 Dog类的方法 19 20 } 21 }
【多态与重载】
1 public class OverloadExample { 2 public static void main(String args[]) { 3 System.out.println(add("C","D")); 4 System.out.println(add("C","D","E")); 5 System.out.println(add(2,3)); 6 } 7 public static String add(String c, String d) { 8 return c.concat(d); 9 } 10 public static String add(String c, String d, String e){ 11 return c.concat(d).concat(e); 12 } 13 public static int add(int a, int b) { 14 return a+b; 15 } 16 }
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();
子类型多态
子类型的规约不能弱化超类型的规约。
子类型多态:不一样类型的对象能够统一的处理而无需区分,从而隔离了“变化”。
【重写与重载的区别】
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 必定不能修改 |
返回类型 | 能够修改 | 必定不能修改 |
异常 | 能够修改 | 能够减小或删除,必定不能抛出新的或者更广的异常 |
访问 | 能够修改 | 必定不能作更严格的限制(能够下降限制) |
调用状况 | 引用类型决定选择哪一个重载版本(基于声明的参数类型)。 在编译时发生。 | 对象类型(换句话说,堆上实际实例的类型)决定选择哪一种方法在运行时发生。 |
方法的重写(Overriding)和重载(Overloading)是java多态性的不一样表现,重写是父类与子类之间多态性的一种表现,重载能够理解成多态的具体表现形式。
【泛型】(参数多态)
ublic interface Set<E> { /** * Test for membership. * @param e an element * @return true iff this set contains e */ public boolean contains(E e); /** * Modifies this set by adding e to the set. * @param e element to add */ public void add(E e); } public class CharSet1 implements Set<Character> { private String s = ""; @Override public boolean contains(Character e) { checkRep(); return s.indexOf(e) != -1; } @Override public void add(Character e) { if (!contains(e)) s += e; checkRep(); } }
public interface Set<E> { // ... public class HashSet<E> implements Set<E> { // ...
Map<E, F>, Map<String, Integer>
List<?> list = new ArrayList<String>();
Pair<String>[] foo = new Pair<String>[42]; // won't compile
toString()
,hashCode()
,clone()
,equals()
等。