面向对象(一)

简介: 面向对象(一)

一、软件开发方式


1、面向过程


一种较早的编程思想,顾名思义该思想是站在过程的角度思考问题,强调的是我该怎么去做。即功能的执行过程,即先干啥,后干啥。


 面向过程思想中函数是一等公民,每个函数负责完成某一个功能,用以接受输入数据,函数对输入数据进行处理,然后输出结果数据。


而每一个功能我们都使用函数(类似于方法)把这些步骤一步一步实现,使用的时候依次调用函数就可以了。

面向过程的设计思想,系统软件适应性差,可拓展性差,维护性低。


二、面向对象


一种基于面向过程的新的编程思想,顾名思义该思想是站在对象的角度思考问题,我们把多个功能合理的放到不同对象里,强调的是我该让谁来做。


面向对象最小的程序单元是类,必须先存在类的定义,再有对象,而具备某种功能的实体,称为对象。


举个例子,小明完成买菜,做菜,吃饭,洗完,写代码功能。

大家一起来看看有对象和没对象的区别:


image.png

wps4.jpg


左图是没有对象的,右图是有对象的。区分面向过程的我该怎么做和面向对象的我该让谁来做的思想。


面向过程和面向对象各有千秋,面向对象更符合我们常规的思维方式,稳定性好,可重用性强,易于开发大型软件产品,有良好的可维护性,它拥有三大特征:

  • 封装(Encapsulation)
  • 继承(Inheritance)
  • 多态(Polymorphism)


三、成员变量和局部变量


3.1、变量的分类


根据变量定义位置的不同,分成两大类:

  • 成员变量:直接定义在类中,方法外面。又称之为字段(Field),不要称之为属性(错误),后讲
  • 局部变量:除了成员变量,其他都是局部变量,具体存在于三个地方
  • 方法内
  • 方法的形
  • 代码块中(一对花括号)


3.2、变量的初始化


变量的初始化表示在内存中开辟存储空间,只有初始化之后,才能使用。

  • 成员变量:默认是有初始值的,不同类型的初始值,如下图
  • 局部变量:没有初始值,所以必须手动先初始化才能使用


3.3变量的作用域


变量根据定义的位置不同,也决定了各自的作用域是不同的,关键看变量所在的那对花括号。

  • 成员变量:在所定义的类中都有效
  • 局部变量:从开始定义的位置开始,只能在自己所在的花括号内有效


3.4变量的生命周期


变量的生命周期,表示变量在内存在能存活多久。

  • 成员变量:存储在堆内存中,随着对象的销毁而销毁
  • 局部变量:存储在栈内存中,随着所定义方法的调用结束而销毁
  • 局部变量存储在方法中,每次调用方法都会在栈空间开辟一块内存空间——栈帧,方法调用结束,栈帧就被销毁了,内存中的存储的变量数据也销毁了


3.5类和对象的关系


面向对象思想中有两个非常重要的概念,类和对象,其中:

  • 类(class),是对某一类事务的抽象描述(状态和行为),如下图的抽象女人图。
  • 对象(object),表示现实生活中该类事物的个体,也称之为实例,如下图的每一个具体的女人。
  • 类可以看作是对象的数据类型,就好比无论你是谁,只要是女人,那么类型就是女人。


image.png
wps5.jpg


上图,从左往右看是抽象的过程,从右往左看是实例化的过程,所谓实例化就表示根据类这个模板制造出每一个对象。
任何事物存在就有一定的功能,在面向对象中,任何事物都可以看成对象,也就是万物皆对象的概念。
注意,在开发中,必须先有类,再使用new关键字根据类来创建出对象。


四、类的定义


类是拥有相同特性(状态)和行为(功能)的多个对象的抽象。而一般的,描述类或者说定义类,就从状态和行为上分析,那么怎么来表示状态和行为呢?


  • 使用成员变量来表示状态
  • 使用成员方法来表示行为
    定义语法格式:

public class 类名{
    //可编写0到N个成员变量
    [修饰符] 数据类型  变量名1;
    [修饰符] 数据类型  变量名2;
    //可编写0到N个成员方法
    [修饰符] 返回值类型  方法名称(参数){
        //方法体
    }
}


注意:

  • 成员变量和方法都 能使用static修饰,修饰符是可选用的,都先不使用任何修饰符
  • 在面向对象设计中,描述对象的类和测试类分开来编写
  • 在描述对象的类中,不需要定义main方法,专门在测试类中提供main方法。


五、访问修饰符


车库有一个车位,旁边写着”公共车位”,那么该车位就是公共的,谁都可以访问它。如果我在车位旁边写上“私家车位”,那么该车位就只能是我自己来访问。外界(除我之外)都访问不了,像“公共”、“私有”这种限制外界访问的标记符号,就称之为访问修饰符。


      访问修饰符,决定了有没有权限访问某个资源。

      封装其实就是要让有些类看不到另外一些类中定义的字段和方法。Java提供了不同的访问权限修饰符来限定类中的成员让谁可以访问到。


image.png


wps7.jpg


  • private:表示当前类私有的,类访问权限,只能在本类中操作,离开本类之后就不能直接访问
  • 不写(缺省):表示当前包私有,包访问权限,定义和调用只能在同一个包中,才能访问
  • protected:表示子类访问权限,同包中的可以访问,即使不同包但是有继承关系也可以访问
  • public:表示公共的,可以在当前项目中任何地方访问


六、面向对象


1、this关键字


局部变量和成员变量同名,此时在方法中调用变量时根据就近原则,优先使用局部变量,示意图如下。


image.png

image-20200605174604319.png


可以看出setName方法中两次使用的name,都是直接寻找距离自己最近的形参name,就相当于把参数name的值设置给参数name,根本就没有把参数值设置给成员变量。


  该问题,更专业的叫法是局部变量和成员变量存在二义性,也就是变量名有歧义。为了解决该问题——有请this关键字。


  使用 this.变量名的语法,此时访问的就是成员变量,


image.png


image-20200605174658036.png


使用构造器还是setter方法

构造器和setter方法都可以给对象设置数据:

  • 构造器,在创建对象的时候设置初始数据,只能初始化一次。
  • setter方法,创建对象后再设置初始数据,可以设置多


2、继承


子类继承父类之后,可以拥有到父类的某一些成员(字段和方法),根据访问修饰符来判断:

  • 如果父类中的成员使用public和protected修饰,子类都能继承.
  • 如果父类和子类在同一个包中,使用缺省访问修饰的成员,此时子类可以继承到
  • 如果父类中的成员使用private修饰,子类继承不到。private只能在本类中访问
  • 父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同


3、方法覆盖


当子类存在一个和父类一模一样的方法时,我们就称之为子类覆盖了父类的方法,也称之为重写。那么我们就可以在子类方法体中,重写编写逻辑代码。

方法的调用顺序:


通过对象调用方法时,先在子类中查找有没有对应的方法,若存在就执行子类的,若子类不存在就执行父类的,如果父类也没有,报错。

方法覆盖的细节:


private修饰的方法不能被子类所继承,也就不存在覆盖的概念。

  1. 实例方法签名必须相同 (方法签名= 方法名 + 方法的参数列表)
  2. 子类方法的返回值类型是和父类方法的返回类型相同或者是其子类
  3. 子类方法中声明抛出的异常小于或等于父类方法声明抛出异常类型
  4. 子类方法的访问权限比父类方法访问权限更大或相等


4、super关键字


问题,在子类中的某一个方法中需要去调用父类中被覆盖的方法,此时得使用super关键字。

public class Ostrich extends Bird{
    public void fly() {
        System.out.println("扑扑翅膀,快速奔跑...");
    }
    public void say() {
        super.fly();//调用父类被覆盖的方法
        fly();//调用本类中的方法
    }
}


如果调用被覆盖的方法不使用super关键字,此时调用的是本类中的方法。

super关键字表示父类对象的意思,更多的操作,后面再讲。

super.fly()可以翻译成调用父类对象的fly方法。


5、抽象类和抽象方法


使用abstract修饰的方法,称为抽象方法。

public abstract 返回类型 方法名(参数);


抽象方法的特点:


  • 使用abstract修饰,没有方法体,留给子类去覆盖
  • 抽象方法必须定义在抽象类或接口中

public abstract class 类名{
}


一般的,抽象类以Abstract作为类名前缀,如AbstractGraph,一看就能看出是抽象类。

抽象类的特点:


  • 抽象类不能创建对象,调用没有方法体的抽象方法没有任何意义
  • 抽象类中可以同时拥有抽象方法和普通方法
  • 抽象类要有子类才有意义,子类必须覆盖父类的抽象方法,否则子类也得作为抽象类
    父类代码:

public abstract class AbstractGraph {
    public abstract double getArea();   //没有方法体
}


子类代码:

public class Circle extends AbstractGraph {
    private int r;// 半径
    public void setR(int r) {
        this.r = r;
    }
    public double getArea() {   //覆盖父类抽象方法
        return 3.14 * r * r;    //编写方法体
    }
}


== 符号到底比较的是什么:

  • 比较基本数据类型:比较两个值是否相等
  • 比较对象数据类型:比较两个对象是否是同一块内存空间
    每一次使用new关键字,都表示在堆中创建一块新的内存空间。




相关文章
|
Java
1.7 面向对象
1.7 面向对象
53 0
面向对象(1)
面向对象(1)
74 0
到底什么是面向对象。
到底什么是面向对象。
46 0
|
存储 Java 编译器
初步认识面向对象
初步认识面向对象
|
Java
2. 面向对象(三)
2. 面向对象(三)
151 0
|
Java C++
2. 面向对象(二)
2. 面向对象(二)
116 0
|
Java
面向对象(一)
面向对象基础
96 0
|
存储 Java
面向对象(二)
面向对象(二)
面向对象(二)
|
Java 程序员 C语言
关于面向对象的深入理解
最开始的计算机程序编码就是0101,程序员完全要以机器的二进制思维去思考问题;后来有了汇编只是编码形式上有了变化,但是本质并没有改变,程序员们的关注点还是在于机器本身,程序员要对CPU、寄存器等硬件了如指掌;当C语言、COBOL等面向过程的语言横空出世后,这是一次本质上的革命,把程序员从二进制的世界中解救了出来,终于可以让他们“像人一样”去思考问题啦。
关于面向对象的深入理解