面向对象

2018-01-05  本文已影响0人  hey_leex

面向对象

封装

  1. 是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
  2. 提高了代码的复用性,安全性

通过对象去给成员变量赋值,可以赋值一些非法的数据。

public class Student(){
    public int age;
}
//main
Student s = new Student();
s.age = -1;                 //这是不合理的

所以我们将属性封装起来,并让外界通过我指定的通道访问和修改我的属性
用private修饰属性

private关键字:

继承

概述

  1. 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
  2. 通过extends关键字可以实现类与类的继承
    class 子类名 extends 父类名 {}
  3. 单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
  4. 有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。

好处

  1. 提高了代码的复用性

    • 多个类相同的成员可以放到同一个类中
  2. 提高了代码的维护性

    • 如果功能的代码需要修改,修改一处即可
  3. 让类与类之间产生了关系,是多态的前提
    其实这也是继承的一个弊端:类的耦合性很强

     开发的原则:低耦合,高内聚。
         耦合:类与类的关系
         内聚:就是自己完成某件事情的能力
    

java继承的注意

  1. java只支持单继承,不支持多继承。
    一个类只能有一个父类,不可以有多个父类。

     class Son extends Futher{} //ok
     class Son extends Futher,Mother{}//error
    
  2. Java支持多层继承(继承体系)

     class GrandFuther{}
     class Futher extends GrandFuther{}
     class Son extends Futher{}
    
  3. 子类只能继承父类所有非私有的成员(成员方法和成员变量)

  4. 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。

  5. 不要为了部分功能而去继承

         class A {
             public void method1(){}
             public void method2(){}
         }
         
         class B {
             public void method2(){}
             public void method3(){}
         }
         
         //我们发现B类中出现了和A类一样的method2()方法,所以,我们就用继承来体现
         class B extends A {
             public void method3(){}
         }
         这样其实不好,因为这样你不但有了method2(),还多了method1()。
         有可能method1()不是你想要的。
         
     什么时候考虑使用继承呢?
     继承其实体现的是一种关系:"is a"。
         Person
             Student
             Teacher
     Student是Person的一种
    
  6. 直接调用属性名时,同名属性的查找顺序(就近原则)

    子类方法局部->子类成员->父类成员->找不到报错(单层继承情况下)

    同: 属性 -> this.属性 -> super.属性

this&super

不能在static中使用,static属于类的

  1. 调用成员变量

    • this.成员变量 调用本类的成员变量
    • super.成员变量 调用父类的成员变量
  2. 调用构造方法

    • this(...) 调用本类的构造方法
    • super(...) 调用父类的构造方法
  3. 调用成员方法

    • this.成员方法 调用本类的成员方法
    • super.成员方法 调用父类的成员方法

构造函数的关系

子类不继承父类的构造函数,可以用super调用

子类中所有的构造方法再不写super的情况下默认都会访问父类中空参数的构造方法

因为子类会继承父类中的数据,可能还会使用父类的数据。

所以,子类初始化之前,一定要先完成父类数据的初始化。

注意:子类每一个构造方法的第一条语句默认都是:super(),即使删除也有;

当子类没有构造函数的时候,系统默认提供一个无参构造方法

public class Fu {       //父类,提供了有参构造,所有系统不会提供一个无参构造,即没有无参构造
    private String str = "name";
    private int i = 1;

    public Fu(String str, int i) {
        this.str = str;
        this.i = i;
    }
}
//--------------------
public class Zi extends Fu{//子类没有提供构造函数,系统自动提供一个无参构造,但是无参构造第一句默认super(),父类没有,报错
                        //error:Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor
                        //隐式的父类构造函数fu()是未定义的。必须显式调用另一个构造函数 
}
//--------------------
public class Zi extends Fu{//子类也无法提供无参构造
    public Zi() {
                        //error:Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor
                        //隐式的父类构造函数fu()是未定义的。必须显式调用另一个构造函数 
    }
}

一定要注意:

super(…)或者this(….)必须出现在第一条语句
否则,就会有父类数据的多次初始化

所以一般建议任何类都提供无参构造

继承中的方法

子类与父类的方声明不一样,一般情况

重写(Override)

子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖

注意:

  1. 父类中私有方法不能被重写(子类写了相当于自己的创建方法,不算重写)

  2. 子类重写父类方法时,访问权限不能更低

  3. 父类静态方法,子类也必须通过静态方法进行重写。(不算是重写,但现象是这样)

     public class Fu {
         public static void pri() {
             System.out.println("a");
         }
     }
     //----------------------
     public class Zi extends Fu{         //This instance method cannot override the static method from Fu
         public void pri() {
             System.out.println("b");
         }
     }
    

多态

有继承关系
有方法重写(没有方法重写的多态将没有意义)
有父类引用指向子类对象

多态中的成员访问特点:
不能调用调用子类特有的属性和方法

  1. 成员变量
    • 编译看左边,运行看左边。
  2. 构造方法
    • 创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
  3. 成员方法
    • 编译看左边,运行看右边。
  4. 静态方法
    • 编译看左边,运行看左边。(静态和类相关,算不上重写,所以,访问还是左边的)

class Fu {
    public int num = 100;

    public void show() {
        System.out.println("show Fu");
    }
    
    public static void function() {
        System.out.println("function Fu");
    }
}

class Zi extends Fu {
    public int num = 1000;
    public int num2 = 200;

    public void show() {
        System.out.println("show Zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }
    
    public static void function() {
        System.out.println("function Zi");
    }
}

class DuoTaiDemo {
    public static void main(String[] args) {
        //要有父类引用指向子类对象。
        //父 f =  new 子();
        Fu f = new Zi();
        System.out.println(f.num);
        //System.out.println(f.num2); //num2 cannot be resolved or is not a field(Fu中找不到num2)
        f.show();
        //f.method();   //The method method() is undefined for the type Fu(Fu中找不到method)
        f.function();
    }
}   

好处与弊端

  1. 多态的好处:
    • 提高了代码的维护性(继承保证)
    • 提高了代码的扩展性(由多态保证)
  2. 多态的弊端
    • 不能调用调用子类特有的属性和方法

向上向下转型

向上转型

Fu f = new Zi();

向下转型:把父类的引用强转为子类的引用

Zi z = (Zi)f;

多态继承中的内存图解

B0iOfer.png

多态中的对象变化内存图解

  1. 不可以访问子类的方法
  2. 不可以强转成其他子类(ClassCastException)
image
//ClassCastException
DuoTaiDemo f1 = new Zi();
DuoTaiDemo f2 = new DuoTaiDemo();
DuoTaiDemo f3 = (Zi2)f1;
DuoTaiDemo f4 = (Zi)f2;
上一篇下一篇

猜你喜欢

热点阅读