面向对象

coffee

前言

面向对象是现在高级计算机语言的一个特性,Java、C++、python 等都是面向对象的编程语言。

这里有部分转载的内容。



概念

面向对象 是相对于面向过程 而言的,是基于面向过程演变而来,和面向过程一样,都是一种编程思想。


面向过程

强调的是功能的行为过程,代表语言:C语言。

例子:把大象装进冰箱

    1.  打开冰箱。
    2. 存储大象。
    3. 关上冰箱。

“打开”、”存储”、”关上”都是功能行为,在代码中的直观体现就是函数或者方法,这就是一种面向过程的以功能行为为主体的思想体现。


面向对象

是将功能封装进对象,强调具备了功能的对象。代表语言:Java、C++、Python。

例子:把大象装进冰箱

    1. 冰箱打开。
    2. 冰箱存储。
    3. 冰箱关闭。

可以看到,所有的操作都是以”冰箱”为主体,而不是功能行为。也就是说冰箱自己已经具备”打开”、”存储”、”关上”的行为功能,我们只需要让冰箱执行它具备的功能就可以了。这就是一种面向对象的以执行功能的对象为主体的思想体现。


面向对象的三大特征
  • 封装
  • 继承
  • 多态



类与对象

类:是对现实生活中具体事物的描述

对象:就是这类事物存在的个体。

java中通过类来描述生活中的具体事物,将这个类创建后,就是对象。


类与对象的关系

类与对象

可以理解为:类就是图纸,汽车就是堆内存中的对象。

对于同一类事物可以抽取它们的共性的内容,定义在类中。如:生活中的汽车,每一台车都有轮胎数和颜色。
那么在通过java描述汽车这类事物时,就可以将这两个共性属性作为类中的属性进行定义。
通过该类建立的每一个汽车实体都具有该属性,并可以有对象特有的属性值。


类的定义

生活中描述事物无非就是描述事物的属性和行为。如:人有身高,体重等属性,有说话,打球等行为。

Java中用类class来描述事物也是如此。
属性:对应类中的成员变量。
行为:对应类中的成员函数。
定义类其实在定义类中的成员(成员变量和成员函数)。


成员变量和局部变量

​ 成员变量:

    1. 成员变量定义在类中,在整个类中都可以被访问。
    2. 成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
    3. 成员变量有默认初始化值。

​ 局部变量:

    1. 局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
    2. 局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
    3. 局部变量没有默认初始化值。


构造方法(函数)

对象的创建及初始化,必须依靠其构造方法。

如果一个类没有定义任何构造方法,则默认有一个无参数的构造方法。

如果类中定义了构造方法,则默认的构造方法失效。

构造方法可以有多个,以重载的形式存在。


构造方法的特点
  1. 方法名称与类名相同
  2. 不用定义返回值类型
  3. 没有返回值
class Person{
       private String name ;
       private int age ;

       //定义一个Person类的构造方法
       //构造方法,而且是空参数的
      Person(){
            //对象创建时,会调用构造方法里面的语句,进行一些初始化操作
            //此处表示,对象创建时会打印“person run”
            System.out.println("person run");
      }

       public void speak(){
            System.out.println(name + ":" + age);
      }
}

class ConsDemo{
       public static void main(String[] args){
             //构造方法:构建对象时调用的函数
             //作用:可以给对象进行初始化
            Person p = new Person();
            p.speak();
      }
} 


一般方法与构造方法的区别

​ 构造方法:对象创建时,就会调用与之对应的构造方法,对对象进行初始化,并且只会调用一次。
​ 一般方法:对象创建后,需要方法功能时才去手动调用,可以被调用多此。



this 关键字

this 指代本类对象的引用

当成员变量和局部变量重名,可以用关键字 this 来区分,this 就是所在函数所属对象的引用。
简单说,哪个对象调用了this 所在的方法,this 就代表哪个对象。一般方法调用默认加this。

class Person{
          private String name ;
          private int age ;

          Person(String name){
             //通过this区分成员变量和局部变量
             this.name = name;
          }

          Person(String name, int age){
             //this也可以用于在构造函数中调用其他构造函数
            //this 调用其他构造时,必须写在第一行,因为初始化动作要先执行
             this(name);
             this.age = age;
          }

          public void speak(){
             System.out.println(name + ":" + age);
          }
}

class ConsDemo{
       public static void main(String[] args){
            Person p1 = new Person("旺财" );
            p1.speak();
            Person p2 = new Person("小强" ,10);
            p2.speak();
      }
} 


static 关键字

static关键字用于修饰成员变量和成员函数

被修饰后的成员具备以下特点:

  1. 随着类的加载而加载。
  2. 优先于对象存在。
  3. 被所有对象所共享。
  4. 可以直接被类名调用。
class Person{
        //成员变量,实例变量
       String name;
       //静态变量,类变量
       //所有对象共享的属性用static修饰
       static String country = "CN";
       public void show(){
            System.out.println(country + ":" + name);
             //等效语句:System.out.println(Person.country + ":" + this.name);
      }
}

class StaticDemo{
       public static void main(String[] args){
            Person p = new Person();
            System.out.println(p.country);
             //可以用类名直接调用
            System.out.println(Person.country);
      }
} 


成员变量与静态变量的区别
    1. 两个变量的生命周期不同
    成员变量随着对象的创建而存在,随着对象被回收而释放。
    静态变量随着类的加载而存在,随着类的消失而消失。
    2. 调用方式不同
    成员变量只能被对象调用。
    静态变量可以被对象调用,还可以被类名调用。
    3. 别名不同
   成员变量也称为实例变量。
   静态变量也称为类变量。
    4. 数据存储位置不同
   成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
   静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

静态方法只能访问静态成员,如果访问非静态成员,就会报错

非静态方法既可以访问静态成员,又可以访问非静态成员



封装

封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

作用:将变化隔离、便于使用、提高重用性、安全性。
封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问。

/*
人:
属性:年龄
行为:说话
*/
class Person{
       //private:私有,是一个权限修饰符,用于修饰
       //不希望别人直接访问赋值,需要通过私有化把属性进行隐藏
       private int age ;

       //通过提供set、get公共方法对其访问
       public void setAge( int a){
             //在set方法内可以对属性的赋值进行限制
             if (a > 0 && a < 130){
                   age = a;
            } else
                  System.out .println("错误的数据" );
      }

       public int getAge(){
             return age ;
      }

       void speak(){
            System.out .println("age = " + age);
      }
}

class PersonDemo{
       public static void main(String[] args){
            Person p = new Person();
            //通过其他方式访问
            p.setAge(20);
            p.speak();
            //赋值不合法,set方法就不允许成功赋值
            p.setAge(-20);
      }
} 



继承

通过 extends 关键字让类与类之间产生继承关系。
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。子类可以直接访问父类中的非私有的属性和行为,却无法继承父类中私有的内容。


作用

继承的出现提高了代码的复用性。
继承的出现让类与类之间产生了关系,提供了多态的前提。

class Person{
      String name;
      int age ;
}

class Student extends Person{
       void study(){
            System.out.println("student study..." + age);
      }
}

class Worker extends Person{
       void work(){
            System.out.println("worker work..." + age);
      }
}

class ExtendDemo{
       public static void main(String[] args){
            Student s = new Student();
            s. name = "zhangsan" ;
            s. age = 20;
            s.study();

            Worker w = new Worker();
            w. name = "lisi" ;
            w. age = 30;
            w.work();
      }
}

Java只支持单继承,不支持多继承,但支持多层继承(继承体系)。如:C继承B,B继承A,就会出现继承体系。


特征
  1. 变量
    子类出现非私有的同名成员变量时,子类访问本类中变量时,用this;子类访问父类中变量时,用super

  2. 函数(方法)
    子类出现和父类一模一样的方法时,当子类调用该方法时,会运行子类方法的内容,因为方法重写(覆盖override)

  3. 构造函数
    子类中所有的构造函数都会默认访问父类中的空参数的构造函数,因为每一个子类构造内第一行都有默认的语句super();
    如果父类中没有空参数的构造函数,那么子类的构造函数内,必须通过super语句指定要访问的父类中的构造函数。
    如果子类构造函数中用this来指定调用子类自己的构造函数,那么被调用的构造函数也一样会访问父类中的构造函数


final 特点
  1. 这个关键字是一个修饰符,可以修饰类,方法,变量。
  2. 被final修饰的类是一个最终类,不可以被继承。
  3. 被final修饰的方法是一个最终方法,不可以被覆盖。
  4. 被final修饰的变量是一个常量,只能赋值一次。


抽象类

Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。

abstract class Demo{
     void show1(){}
     void show2(){}
}


特点
  1. 抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。
  2. 抽象方法只定义方法声明,并不定义方法实现。
  3. 抽象类不可以被创建对象(实例化)。
  4. 只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。
  5. 抽象类只能单继承。


抽象类的细节
  1. 抽象类中是否有构造函数?

    有,用于给子类对象进行初始化。

  2. 抽象类中是否可以定义非抽象方法?

    可以。其实,抽象类和一般类没有太大的区别,都是在描述事物,只不过抽象类在描述事物时,有些功能不具体。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,比一般类多了一个抽象函数。而且比一般类少了一个创建对象的部分。

  3. 抽象关键字abstract和哪些不可以共存?

    Final修饰的不能被重写

    Private修饰的不能访问

    Static修饰的随着类的加载而加载,此时还没有对象

  4. 抽象类中可不可以不定义抽象方法?可以。抽象方法目的仅仅为了不让该类创建对象。



接口

当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口 interface

interface Demo{
       public static final int NUM = 4;
       public abstract void show1();
       public abstract void show2();
}

/*实现*/
class DemoImpl implements Demo{
       public void show1(){}
       public void show2(){}
}

class InterfaceDemo{
       public static void main(String[] args){
            DemoImpl d = new DemoImpl();
            System.out.println(d.NUM);
            System.out.println(DemoImpl.NUM);
            System.out.println(Demo.NUM);
      }
}


抽象类和接口的区别
  1. 抽象类只能被继承,而且只能单继承。 接口需要被实现,而且可以多实现。
  2. 抽象类中可以定义非抽象方法,子类可以直接继承使用。 接口中都是抽象方法,需要子类去实现。
  3. 抽象类使用的是 is a 关系。 接口使用的 like a 关系。
  4. 抽象类的成员修饰符可以自定义。 接口中的成员修饰符是固定的。全都是public的。


多态

定义

某一类事物的多种存在形态。

函数本身就具备多态性,即某一种事物有不同的具体体现。

比如:父类引用或者接口的引用指向了自己的子类对象。

Animal a = new Cat();

  • 好处

    提高了程序的扩展性。

  • 弊端

    当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。

    (前期不能使用后期产生的功能,即访问的局限性)


多态的前提
  1. 必须要有关系,比如继承、或者实现。
  2. 通常会有覆盖操作。
class DuoTaiDemo{
     public static void main(String[] args){
          //自动类型提升,猫对象提升到了动物类型。但是特有功能无法访问,作用就是限制对特有功能的访问。
          //专业讲:向上转型,将子类型隐藏。就不能使用子类的特有方法了。
          Animal a = new Cat();
          a.eat();
          //a.catchMouse();//报错

          //如果还想用具体动物猫的特有功能。
          //你可以将该对象进行向下转型。
          Cat c = (Cat)a; //向下转型的目的是为了能够使用子类中的特有方法。
          c.eat();
          c.catchMouse();

          //注意:对于转型,自始至终都是子类对象在做类型的变化。
          //Animal a = new Dog();
          //Cat c = (Cat)a;//但是类型不能随意转换,否则可能会报出ClassCastException的异常
     }

     public static void method(Animal a){
          a.eat();
     }
}


多态的特点

成员函数在多态调用时,编译看左边,运行看右边。

静态成员函数和成员变量,无论编译和运行都看左边。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值