Java面向对象

到这里为止,Java前面的基础知识我们已经说完了,接下来我们开始说Java面向对象的相关内容。首先来看几个概念。

 

面向过程

要说面向对象,我们首先要弄明白面向过程,之前我们所写的代码都是直接在主函数里面书写,它其实就是面向过程。

面向过程,核心是过程两个字。过程即解决问题的步骤,它考虑的是实际地实现,针对一个特定的问题去思考其解决步骤。一般的面向过程是从上往下步步求精,所以面向过程最重要的是模块化的思想方法。因此在模块化编程的时候才会有“低耦合,高内聚”的思想来提高效率。

面向对象

而面向对象也离不开面向过程。我们可以把面向过程当做面向对象每一部分的实现。就比如造一辆汽车,面向对象就是思考车是由什么零件组成的,而每一个零件的制作就是一个个过程,要经过一道道程序才能做出来。因此,面向对象可以帮助我们从宏观上掌握、分析整个系统。 但是,具体到实现部分的微观操作(就是一个个过程),仍然需要面向过程去处理。

这就是面向对象和面向过程之间的联系。简单来说,面向对象就是从宏观上来说所有的步骤,而面向过程就是每一个步骤的具体实现。

类就是具有相同行为和特征的一些具体事物的总称。

对象

对象就是由一个类所描述的内容从而产生的一个具体的事物。

关于对象的内存创建一

    1.在堆内存中开辟一个空间并分配地址;

    2.按照类的描述,在该空间中定义成员变量,并且有默认初始化值;

    3.加载成员函数进入方法区(只加载一次);

    4.对象创建完毕 将空间地址赋值给相应的变量;

    5.变量调用成员变量;

              先通过该变量所存储的地址去堆空间中找,然后在该空间中找相应的成员变量。

    6.变量调用成员函数。

              直接去方法区中找该成员函数,将该函数加载进栈内存开始运行。为了方便区分哪个对象调用的该成员函数,由this这个关键字段来进行区分。this主要存的是当前对象的地址。

PS:当成员函数在操作变量的时候 ,先在当前函数的空间里找局部变量,如果没有找到,再去this所指向的堆内存中对象所属空间里去找。

关于对象的内存创建二

    1.在堆内存中开辟一个空间并分配地址;
    2.对成员变量进行【默认初始化】;
    3.相应的构造函数进栈,刚开始就对成员变量进行【显式初始化】;
    4.接着再去执行构造函数中的内容【针对性初始化】;
    5.构造函数执行完毕 弹栈 将对象的地址赋值给相应变量即可。

private关键字

是一个权限关键字,表示私有权限,该成员变量或成员函数只能够在类中被访问,而外界不可访问。

我们可以通过对象直接修改对象中的成员变量,但是这样的话有一个弊端:就是我们如果赋予了一个错误的值,那么势必会导致程序后期的运行结果。也就是说我们对象的成员变量并不是完全需要让外界可访问,如果能够被外界访问,那么势必也能被外界修改。为了防止外界直接修改对象的成员变量,就有了private私有化关键字的出现。但是成员变量加了private的话,不能修改,也不能获取了,此时就死局了。我们不能保证后期对成员变量不进行修改或获取,本质上而言,我们应该防范的是:无条件的修改。

也就是说,修改是可以修改的,但是你不能忽略对象的感受,不能不按要求进行修改。不能直接修改的意思就是间接修改(即是不是应该加上相应的对值的判断,即语句if-else)。

setter是一个Java当中的规范  修改器  它主要负责修改成员变量,本身就是一个成员函数,命名方式一般为 setXxx:  setAge setName

getter  访问器  主要负责访问成员变量(返回成员变量)  getter看需求

所以在今后的代码中,成员变量一律私有,然后再去设置访问器和修改器。如果成员变量和局部变量重名了,只需要在成员变量之前加this.即可。

成员变量与局部变量的区别

1.存储位置
        局部变量存储在栈内存中函数的所属空间里。
        成员变量存储在堆内存中对象的所属空间里。

2.生命周期
        局部变量随着函数的进栈而存在,随着函数的弹栈而消失。
        成员变量随着对象的创建而存在,随着对象的销毁而消失。

3.访问范围
        局部变量的访问范围仅仅在函数当中。
        成员变量的访问范围在当前类中。

4.初始化值
        局部变量必须先进行初始化,之后再能被调用。
        成员变量在创建时有默认初始化 。

面向对象特征之一——封装

封装:从字面意义上来看,就是将一些杂七杂八的东西进行统一的管理。比如收纳盒、衣柜、书柜等,就可以简单理解为封装。它最大的好处就是节约代码、方便管理、降低耦合性。
在代码中有什么体现:

循环:主要解决有规律且重复性执行的代码。

函数:主要解决具有独立功能的一段代码,后期进行复用即可。

数组:主要解决多种同类型数据的操作,统一操作,方便类管理。

类:主要将数据和行为进行统一方便操作,仿真现实中的事物。

构造函数

目前,我们只能将对象创建完毕之后,再进行对成员变量的赋值,那一个问题就来了,如何在创建对象之前/之中对我们的成员变量进行赋值呢?这个时候,构造函数就出来了。构造函数的主要作用:在创建对象之时对成员变量进行赋值操作。

构造函数的格式:

权限修饰符 函数名(参数列表){

       函数体;

}

下来我们来说一下构造函数和成员函数的区别:
       1.构造函数只在创建对象的时候调用,而且仅仅调用一次。
          成员函数在创建对象之后调动,可以调用任意次数。

2.成员函数可以调用成员函数。
          成员函数不可以调用构造函数。
          构造函数可以调用成员函数,只不过此时的成员函数不应该当做对象的特有行为而向外界提供的,仅仅是构造函数中的代码略多,从而分出来的函数,本质上这个函数还是构造函数的内容。
          构造函数也可以调用构造函数,它能适当减少代码的冗余,提高构造函数的利用率。原则上一般是参数较少的构造函数调用参数较多的构造函数,具体的调用方式并不像成员函数一样写个方法名。

那么有了构造函数,是否还需要Setter和Getter?这个其实不一定,看各人需求,如果确定数据后期要被修改,就需要添加。

面向对象特征之一——继承

继承,顾名思义,就是一个继承一个,继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码。被继承的类叫父类,去继承的类叫子类。我们一般使用extends关键字来实现类与类的继承关系。

继承关系特点:首先Java语言的继承关系是一种单继承的关系。

1.一个子类只能有一个父类,而一个父类可以有多个子类。

2.子类可以使用父类的属性和方法,但是父类不能够访问子类独有的属性和方法。

3.创建子类对象时,先执行父类的构造方法,然后在再执行子类的构造方法。

4.使用super关键字,去调用父类的构造方法。

super父类的引用、超类的引用、基类的引用,用法和this关键字类似。

执行顺序:父类的静态代码块 ------ 子类的静态代码块 ------ 父类的构造方法 ----- 子类的构造方法

方法的重写

重写的满足条件:

  1. 一定发生在两个类中(父-子的关系 祖--孙的关系),并且这两个类一定是继承关系。
  2. 访问修饰符相同、返回类型相同、方法名字相同、方法体不同,子类的访问修饰符不能比父类更严格。
  3. 重写是多态的表现特征之一

面向对象特征之一——多态

多态,简单来说就是同一个行为具有多个不同表现形式或形态的能力。

细化来说就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

多态的两种实现形式:两者之间要存在继承或者是实现关系(接口)。

多态的实现的三个必要条件:继承、重写、向上转型。

向上转型和向下转型:强制转换和自动转换

向上转型对应着:自动转换。也就是子类引用的对象转换为父类类型,通俗地说就是是将子类对象转为父类对象。

Animal animal = new Cat(); 

就比如我们的父类是Animal类,子类是Cat类,将子类对象 Cat 转化为父类对象 Animal,这个时候 animal 这个引用调用的方法是子类方法。

另外,子类引用不能指向父类对象。即Cat c = (Cat)new Animal(),这样是不行的。

向下转型对应着:强制转换。就是把父类对象转为子类对象。向下转型只能转型为本类对象。拿一个例子来说。

//假设我们之前Animal类、Dog类、Cat类都已经定义好了

Animal a = new Cat();
Cat c = ((Cat) a);
c.eat();//输出  猫吃鱼

Dog d = ((Dog) a);
d.eat();
//报错 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.Dog

Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();
//报错 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat

为什么第一段代码可以运行成功,而第二段、第三段代码就报错了呢?这是因为 a 本身就是 Cat 对象,所以它理所当然的可以向下转型为 Cat,同时也理所当然的不能转为 Dog,你见过一条狗突然就变成一只猫这种事吗?而 a1 为 Animal 对象,它也不能被向下转型为任何子类对象。比如你去考古,发现了一个新生物,知道它是一种动物,但是你不能直接说,它是猫,或者说它是狗。

未完待续。。。。。。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值