学习笔记20170627

来源:互联网 发布:拳皇14键盘优化 编辑:程序博客网 时间:2024/05/19 17:47

一、面向对象的三大特性

1、封装。它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。(例如通过set、get方法来访问)

访问控制级别表          private           default        protected       public同一个类中          √         √         √         √同一个包中          √         √         √子类中           √         √全局范围内            √

2、继承。Java的继承具有单继承的特点,每个子类只有一个直接父类。子类扩展了父类,将可以获得父类的全部成员变量和方法,

3、多态。Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。

例如:

class BaseClass{

public int book = 6;

         public void base(){

     System.out.println("父类的不同方法");

}

      public void test(){

     System.out.println("父类的被覆盖的方法");

}

}


       public class SubClass extends BaseClass{

//重新定义一个book实例变量隐藏父类的book实例变量

public String book = "轻量级Java EE企业应用实战";

    public void test(){

      System.out.println("子类的覆盖父类的方法");

}

    public void sub(){

    System.out.println("子类的普通方法");

}

   public static void main(String[] args){

     //下面编译时类型和运行时类型完全一样,因此不存在多态

   BaseClass bc = new BaseClass();

     //输出6

   System.out.println(bc.book);

    //下面两次调用将执行BaseClass的方法

   bc.base();

   bc.test();

  //下面编译时类型和运行时类型完全一样,因此不存在多态

SubClass sc = new SubClass();
        // 输出"轻量级Java EE企业应用实战"
        System.out.println(sc.book);
        // 下面调用将执行从父类继承到的base()方法
        sc.base();
        // 下面调用将执行当前类的test()方法
        sc.test();
        
        
        
        
        
        
        // 下面编译时类型和运行时类型不一样,多态发生
        BaseClass ploymophicBc = new SubClass();
        // 输出6——表明访问的是父类对象的实例变量
        System.out.println(ploymophicBc.book);
        // 下面调用将执行从父类继承到的base()方法
        ploymophicBc.base();
        // 下面调用将执行当前类的test()方法
        ploymophicBc.test();
        // 因为ploymophicBc的编译时类型是BaseClass
        // BaseClass类没有提供sub()方法,所以下面代码编译时会出现错误
        // ploymophicBc.sub();

}

}

当把一个子类对象直接赋给父类引用变量时,例如上面BaseClass ploymophicBc = new SubClass();,这个ploymophicBc引用变量的编译时类型是BaseClass,而运行时类型是SubClass,当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就可能出现:相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态。


二、继承与组合

继承是实现类复用的重要手段,但继承带来了一个最大的坏处:破坏封装。相比之下,组合也是实现类复用的重要方式,而采用组合方式来实现类复用则能提供更好的封装性。

  例如:

      Bird  b = new Ostrich();

         b.fly();

对于上面代码声明的Bird引用变量,因为实际引用一个Ostrich对象,所以调用b的fly()方法时执行的不再是Bird类提供的fly()方法,而是Ostrich类重写后的fly()方法

      为了保证父类有良好的封装性,不会被子类随意改变,设计父类通常应该遵循以下规则:

①尽量隐藏父类的内部数据。尽量把父类的所有成员变量都设置成private访问类型,不要让子类直接访问父类的成员变量。

②不要让子类可以随意访问、修改父类的方法。父类中那些仅为辅助其他的工具方法,应该使用private访问控制符修饰,让子类无法访问该方法;如果弗雷中的方法需要被外部类调用,则必须以public修饰,但又不希望子类重写该方法,可以使用final修饰符来修饰该方法;如果希望父类的某个方法被子类重写,但不希望被其他类自由访问,则可以使用protected来修饰该方法。

③尽量不要在父类构造方法中调用将要被子类重写的方法。

  例如:

class Base{

 public Base{

   test();

}

public void test(){                //①号test()方法

        System.out.println("将被子类重写的方法");

}

}

public class Sub extends Base{

    private  String name;

  public void test(){                //②号test()方法

 System.out.println("子类重写父类的方法,"+"其name字符串长度"+name.length());

}

public static void main(String[] args){

     //下面代码会引发空指针异常

     Sub  s  = new  Sub();

}

}

当系统试图创建Sub对象时,同样会先执行其父类构造方法,如果父类构造方法调用了被其子类重写的方法,则变成调用被子类重写后的方法。当创建Sub对象时,会先执行Base类中的Base构造方法,而Base构造方法中调用了test()方法——并不是调用①号test()方法,而是调用②号test()方法,此时Sub对象的name实例变量时null,因此将引发空指针异常。



到底何时需要从父类派生新的子类呢?不仅需要保证子类是一种特殊的父类,而且需要具备以下两个条件之一:

①子类需要额外增加属性,而不仅仅是属性值的改变。例如从Person类派生出Student子类,Person类里没有提供grade(年级)属性,而Student类需要grade属性来保存Student对象就读的年级,这种父类到子类的派生就符合Java继承的前提;

②子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)。例如从Person类派生出Teacher类,其中Teacher类需要增加一个teaching()方法,该方法用于描述Teacher对象独有的行为方式:教学。

原创粉丝点击