JavaSE学习笔记系列:面向对象(3)

1.toString方法

  1. object中定义有toString()方法,其返回值是string类型,它描述的是当前对象的有关信息。
  2. 在进行string与其他类型数据的连接操作时(如system.out.println(“info”+person)),将自动调用该对象的toString()方法。
  3. 可以根据用户需要重写toString()方法。

2.equals方法

  1. public boolean equals(object obj)方法提供定义对象是否“相等”的逻辑。
  2. object的equals()方法定义为:x.equals(y) 当x和y是同一个对象的引用时,返回true,否则返回false。
  3. j2se提供的一些类,如String Date等,重写object的equals()方法,调用这些类的equals()方法,x.equals(y)方法,当x和y所引用的对象是同一类对象且属性内容相等时(并不一定是相同对象),返回true,否则返回false。
  4. 可以根据用户需要在自定义类型中重写equals()方法。
  5. 注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

3.对象转型(casting)

  1. 一个基类的引用类型变量可以“指向”其子类的对象。(父类引用指向子类对象)——它所看到的只是作为父类的那部分所拥有的那些属性和方法。

  2. 一个基类的引用不可以访问其子类对象新增加的成员(属性和方法)。

  3. 可以使用 引用变量 instanceof 类名 来判断该引用型变量所“指向”的对象是否是该类或该类的子类。

  4. 子类的对象可以当作基类的对象来使用称作向上转型,反之称为向下转型。

  5. 对象转型可以增加程序的可扩展性。

4.多态(动态绑定、迟绑定)——核心机制

  1. 动态绑定是指在执行期间(而非编译期)判断所引用对象的实际类型,根据其实际类型调用其相应的方法。
  2. 多态的三个必要条件:
  • 要有继承
  • 要有重写
  • 类引用指向子类对象(实际中new的是哪一个子类对象就调用哪一个子类对象的方法)
  1. 多态性通过覆盖父类的方法来实现,在运行时根据传递对象的引用来调用相应的方法。
  2. 多态就是:传递子类的引用时,子类有的方法就调用子类的对象,子类没有就调用父类的对象。
  3. 多态机制是面向对象的核心机制,增强程序的可扩展性。它是根据实际的类型去调用相应的方法。
  4. 继承是子类使用父类的方法,而多态则是父类使用子类的方法。其技术上的区别是绑定时期,晚期绑定一定是多态。
  5. 多态性不仅包括方法多态性(重载),还包含一种对象多态性的概念,即子类和父类对象的相互转化关系。
    • 向上转型:父类 父类对象=子类实例 (自动完成)
    • 向下转型:子类 子类对象=(子类)父类实例(强制完成)
  6. 对象多态性最核心的部分就是方法的重写与继承关系,只要有继承关系,只要有重写过的方法,则子类向父类转型时,肯定是调用被子类重写过的方法(核心)。
  7. 多态性是指在继承层次或者接口与实现类层次上,如果子类覆盖了父类的方法,或者说实现类实现了接口 定义的方法,那么可以通过一般化的用父类或者接口来调用该方法,JVM在运行期能够根据实际传递的子 类对象引用,来调用相应的方法,产生正确的行为。达到“同一函数,不同行为”的效果。java的多态性是通过动态绑定实现的。
  • 首先是多态性的前提:
    • 在继承层次或者接口与实现类层次上才有多态性;
    • 子类覆盖了父类的方法,或者实现类实现了接口定义的方法,才有多态性;
  • 其次是多态性的表现:
    可以通过一般化的用父类或者接口来调用某一方法,JVM在运行期能够根据实际传递的子类对象引用,来调用相应的方法,从而产生正确的行为。
  • 最后是多态性的实现原理:
    java多态性是通过函数的动态绑定机制实现的

5.抽象类

  1. 用abstract修饰一个类时,该类是一个抽象类。用abstract修饰一个方法时,该方法是一个抽象方法(相当于C++中的纯虚函数)。
  2. 含有抽象方法的类必须为抽象类,抽象类不一定要包含抽象方法。
  3. 抽象类必须被继承,抽象方法必须被重写(由子类去实现)。
  4. 抽象类不能被实例化。但是利用多态可以通过子类实例化。
  5. 抽象方法只需声明,不需实现。
  6. 抽象类可以包含具体数据或具体方法。
  7. 抽象类能否使用final声明呢?
    a) 抽象类必须被子类继承
    b) 被final声明的类不能有子类
  8. 抽象类中能不能存在构造方法?
    a) 允许有构造方法
    b) 但是不能直接调用,是要交给子类调用的,子类对象的实例化中永远是先调用父类中的构造方法
    c) 由此而知,抽象类只不过是比普通类多了一个抽象方法而已
  9. 抽象类中的属性如果要初始化,则还是要依赖于构造方法
  10. 抽象类实际上可以作为模板存在。

6. final关键字

  1. final变量(成员变量与局部变量)的值不能被改变。(局部变量作为形参时,方法内部是不允许改变的)
  2. final的方法不能被重写。
  3. final的类不能被继承。

7.接口

  1. 多个无关的类可以实现一个接口
  2. 一个类(或者抽象类)可以实现多个无关的接口,但是一个接口不能继承一个抽象类
  3. 一个接口可以同时继承多个接口
  4. 与继承关系类似,接口与实现类之间存在多态性(实现接口的方法就是多态)
  5. 接口是常量值和抽象方法的定义的集合
  6. 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现
  7. 接口不是类,不能用new运算符实例化一个接口,但是也是可以利用多态性通过其实现类实例化。
  8. 虽然不能构造接口对象,却能声明接口变量
  9. 接口变量必须引用实现了接口的类对象
  10. 可以使用instanceof检查一个对象是否实现了某个接口
  11. 接口可以扩展。即可以interface1 extends interface2。也可以添加新的属性和方法
  12. 接口中的方法和域被自动设置为public static final(C++中多继承中,如果它的多个父类之间有相同的成员变量时,运行起来会相当得麻烦,并且会出现很多问题。为了修正这个缺陷,java中把成员变量修饰为static使这个变量只属于这个类(因为在多继承中,子类对象包含多个父类对象,而多个父类对象之间是有可能出现相同的成员变量的,所以用static修饰,它就不属于专门的对象),用final修饰使这个变量不被改变)
  13. 接口中只能定义抽象方法,而这些方法默认为public的,而且也只能是public的。
  14. 接口可以多重实现(多继承)。
  15. 多继承中,子类对象是包含多个父类对象的。
  16. 接口实际上是作为标准存在的。

8. 接口和抽象类

8.1 适配器设计模式

a) 正常情况下一个接口的子类要实现全部的抽象方法
b) 但是现在希望可以根据自己的需求来选择性的重写,应该怎么是实现呢?
c) 就用一个类先将接口实现了,但是所有的方法都是空实现,之后再继承此类
d) 这个类必须是抽象类,因为抽象类也不能直接使用。此抽象类就相当于适配器。

8.2 工厂设计模式

a) 现在有如下一道程序:

interface Fruit{
    public void eat() ;
}
class Apple implements Fruit{
    public void eat(){
        System.out.println("吃苹果。。。") ;
    }
};
class Orange implements Fruit{
    public void eat(){
        System.out.println("吃橘子。。。") ;
    }
};
class Factory{  // 工厂类
    public static Fruit getFruit(String className){
        Fruit f = null ;
        if("apple".equals(className)){
            f = new Apple() ;
        }
        if("orange".equals(className)){
            f = new Orange() ;
        }
        return f ;
    }
};
public class InterDemo{
    public static void main(String args[]){
        Fruit f = Factory.getFruit(args[0]) ;
        if(f!=null){
            f.eat() ;
        }
    }
}

所有的接口的实例化对象都是通过工厂类取得的,那么客户端调用的时候就根据传入的名称不同,完成的功能也不同。是为了解开接口和子类之间的耦合性。

8.3 代理设计模式

interface Give{
    public void giveMoney() ;
}
class RealGive implements Give{
    public void giveMoney(){
        System.out.println("把钱还给我。。。。。") ;
    }
};
class ProxyGive implements Give{    // 代理公司
    private Give give = null ;
    public ProxyGive(Give give){
        this.give = give ;
    }
    public void before(){
        System.out.println("准备:小刀、绳索、钢筋、钢据、手枪、毒品") ;
    }
    public void giveMoney(){
        this.before() ;
        this.give.giveMoney() ; // 代表真正的讨债者完成讨债的操作
        this.after() ;
    }
    public void after(){
        System.out.println("销毁所有罪证") ;
    }
};
public class ProxyDemo{
    public static void main(String args[]){
        Give give = new ProxyGive(new RealGive()) ;
        give.giveMoney() ;
    }
};

延伸阅读

1.JavaSE学习笔记系列:面向对象(1)
2.JavaSE学习笔记系列:面向对象(2)