Java(面向对象篇)

1、什么是面向对象?

记得初次接触Java时,老哥告诉我Java是一个面向对象的语言,我当时问了一句:“对象!!???,那是什么东西?”。老哥呵呵一笑,说:‘“这个玩意,我现在说你也不懂,以后你会慢慢体会到的“。时隔多年,而今再回首当初,才若有所思,哦呵!原来你就是对象!

Java有一句经典名言”万物皆对象!“只有等你学习Java到一定的程度之后,你才能体会到这句话的真理。在认识Java对象之前,先了解一下Java核心概念:封装,继承,多态

封装(Encapsulation)就是把对象的属性和行为结合成一个独立单位,并尽可能的隐藏在对象的内部。它有两个含义:一是把对象的全部属性和行为结合在一起,形成一个不可分割的独立单位。对象的属性(除了公共属性值)只能由这个对象的行为来读取和修改。二是尽可能屏蔽对象的内部细节,对外形成一道屏障,与外部的联系只能通过外部接口实现。

继承(Inheritance)是一种联结类与类的层次模型。继承性是指特殊类的对象拥有其一般类的属性和行为。继承意味着“自动地拥有”,即特殊类中不必重新定义已在一般类中定义过的属性和行为,而它却自动地、隐含地拥有其一般类的属性与行为。继承允许和鼓励类的重用,提供了一种明确表述共性的方法。一个特殊类既有自己新定义的属性和行为,又有继承下来的属性和行为。尽管继承下来的属性和行为是隐式的,但无论在概念上还是在实际效果上,都是这个类的属性和行为。当这个特殊类又被它更下层的特殊类继承时,它继承来的和自己定义的属性和行为又被下一层的特殊类继承下去。因此,继承是传递的,体现了大自然中特殊与一般的关系。

多态(Polymorphism)是指类中同一函数名对应多个具有相似功能的不同函数,可以使用相同的调用方式来调用这些具有不同功能的同名函数。 

这些都是官方话,拿到现实生活中,假如把大千世界虚拟化比喻成Java帝国,世界上有什么呢?常见的,有人。抽象到Java帝国就是”人类“(Class Person{}),就拿人类在做比喻,人类都有手足。女娲造人就好比Java帝国的关键字new,女娲造一个人就得捏一个人,这个人是男人,叫亚当。Java帝国就是 Person p = new Persion(); p.setSex("男"); p.setName("亚当"); 怎样理解封装呢?女娲造所有的人都有手足。Java帝国就是吧手足属性封装到Person类内部,这样new出来的每一个人都有手足。手足是人类的一个属性。每个人的手足是要自己来支配,不对外提供。怎样理解继承呢?随着社会的发展,世界上出现了机器人,机器人有着和人类一样的属性,手足。Java帝国就是 Robot extends Person{} ,机器人也就有了手足了,不用在Robot类内部在封装一个手足属性,因为他已经遗传了人类的手足属性。至于人类是血肉动物,这是人类相对于机器人特有的,private修饰了,是不会遗传给机器人的。怎样理解多态呢?最好的例子就是你的女友,女友有听的行为。可是听到不同类型的话,会表现出不同的情绪。当你传递赞美类型话时,表现很迷人。传递幽默类型的话时,表现会大笑。当你传递各种不同类型的话时,表现很厌烦。都是听,不同参数表现不同。Java帝国女朋友这个实例会有多个相同听的接口hear(String a);hear(int b);hear(String a, int b);参数不同行为方式也不同。

其实面向对象的核心思想就是抽象,对类别的抽象和功能的抽象,动物类就是对自然界所有的动物抽象成一个类。每一个具体的动物就是动物类的一个实例。动物类都有具有运动的行为方式,那么所有的行为方式可以抽象成一个接口。飞行,爬行。鸟类实现了飞的接口,两栖类实现了爬行接口。Java帝国就是抽象类和抽象接口了,通过封装,继承,多态,就形成了丰富多彩的Java帝国。这就是我所理解的面向对象。

 

2、抽象类和接口的区别是什么?

区别一,抽象类需要被子类继承,接口需要被实现。

区别二,抽象类可以方法的申明和方法的实现,而接口只能有方法的申明,不能有方法的实现。

区别三,抽象类的变量是普通的变量,而接口的变量只能是公共的静态的常量。

区别四,抽象类只能被单继承,但是接口可以多继承。

注意一,类实现了接口,接口里的所有方法以及接口父接口里的方法都必须实现,除非该类是一个抽象类,类继承了一个类,类申明的抽象方法,子类也必须实习,除非子类是一个抽象类。

注意二,接口申明的变量一定是静态公共变量,即时没有public static final,修饰,在编译之后也会被修饰的。

注意三,接口申明抽象,其实接口都是抽象的以及接口里的方法都是都是被 public abstract 修饰的,在编码的时候会一般都会省略,但是编译之后也会加上去的。

注意四,抽象类是对类别的抽象,而接口是对功能的抽象。接口是设计的结果,抽象类是重构的结果。且接口的抽象级别更高,它更为抽象。

3、类的执行顺序

在了解类的执行顺序之前,先来了解一下类的加载过程。

类的加载一般会经过,加载,链接,初始化。

加载:就是将class文件加载到内存中,并将这些数据转换成方法区中的运行时数据(静态变量,静态代码块,常量池等),在堆中生成一个class类对象代表这个类(反射原理),作为方法区类数据的访问入口。

链接:分为验证,准备,解析三个阶段,验证确保加载的类信息符合JVM规范,没有安全方面的问题。准备正式为类变量(static变量)分配内存空间,并设置类变量的初始值。这些内存将在方法区进行分配。注意此时的设置初始值是默认值,具体复制在初始化阶段完成。解析就是将虚拟机常量池引用替换为直接引用(地址引用)

初始化:执行类的构造器方法的过程。类构造器方法是有编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。当初始化一个类的时候,如果发现其父类还没有进行初始化则需要先初始化其父类。

由此可见类的执行顺序是:父类的(静态变量,静态代码块),子类的(静态变量,静态代码块),父类的(非静态变量,非静态代码块,构造方法),子类的(非静态变量,非静态代码块,构造方法)。

 

4、什么是Java序列化和反序列化,原理是什么?

Serializable接口:是启用其序列化接口。实现java.io.Serializable 接口的类是可序列化的。可序列化的类的所有子类型本身都是可序列化的。序列话接口没有方法和字段,仅用于标识可序列化的语义。

允许非序列化类的子类型序列化,子类型可以假定负责和保存父类型的公有的、保护的和(假如可访问)包的域的状态。只要该类(父类)有一个无参构造,可初始化它的状态,那么子类型就可以承担这样的责任。如果没有无参构造函数,在这种情况下申明一个可序列化的类是一个错误。此错误将在运行时被检测。

那么,有一个问题产生了,为什么父类需要提供一个无参数的构造?

父类必须提供无参构造的前提是,父类没有实现序列化接口。若父类也实现了序列化接口,是可以不提供无参数构造的。至于为什么要提供无参构造,其实与继承和类的加载方式有关系。java对象的构造必须先有父对象,才有子对象。获得对象就是调用构造函数,构造函数的调用都会默认先调用父类的构造函数。在写继承的时候,你会发现父类假如有有参构造,子类一定也要有有参构造,且构造函数首行显示调用super();无参构造其实也是有的,只不过隐藏了。可以想一下,构造函数是干什么的呢?是在加载的时候,执行初始化给类变量赋值的。父类在执行有参构造函数时,这个参数的值其实就是子类传过来的。但是再问一句,为什么一定要先调用父类构造函数呢?子类是可以访问父类的数据,假如子类已经执行了构造函数,也就是有了实例,系统这时候用通过子类对象去访问父类的变量,这下完了,父类还没加载好呢,你就来访问,不就乱套了吗。这时可能又会问,没加载可以等一下父类加载完毕不就好了吗。但是玩意父类万一加载失败了呢?那么子类不是白白加载了,而且还要占用内存,子类就成垃圾,这样会造成内存浪费。

序列化就是把对象转化成二进制流,可用于网络传输或者保存到磁盘中,然后经过反序列化吧对象从二进制流中恢复成原来的过程。但是需要注意的是,在反序列化过程中,创建子类对象是需要先构建父类,而这时假如父类没有实现序列化接口,那么只能调用父类的无参构造作为子类的默认父类。因此当我们取父对象的变量值时,它的值是调用父类无参构造函数后的值。如果你考虑到这种序列化的情况,在父类无参构造函数中对变量进行初始化,否则的话,父类变量都是默认声明的值,如int型的默认是0,string型的默认是null。

可参考:https://blog.csdn.net/zh15732621679/article/details/79803105

 

5、面向对象的设计思想与常见的模式

设计思想:单一职责原则,开闭原则,里氏替换原则,依赖注入原则,接口分离原则,迪米特原则。

单一职责原则:其实就是经常说的”高内聚,低耦合“;每个类应该只有一个职责,对外提供一种功能,而引起类变化的原因应该只有一个。

开闭原则:一个对象对扩展开放,对修改关闭。也就是对类的改动是通过增加代码进行的,而不是修改现有的代码。

里氏替换原则:在任何父类出现的地方都可以用它的子类来替代。(看到这,貌似我上面那个机器人的例子不是太恰当。)

依赖注入原则:依赖于抽象,不要依赖于具体实现。在应用过程中,所有的类如果使用或依赖于其他的类,则应该依赖这些类的抽象类,而不是这些其他的类的具体类。为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程而不是具体的实现编程。

接口分离原则:不应该强迫程序依赖它们不需要使用的方法。一个接口不需要提供太多行为,一个接口应该提供一种对外的功能,不应该把所有的操作封装到一个接口中。

迪米特原则:一个对象应当对其他对象尽可能少的了解。也就是说降低各个对象之间的耦合,提高系统的可维护性。在模块之间只通过接口编程,而不理会模块的内部工作原理,它可以使各个模块耦合度降低最低,促进软件的复用。

 

设计模式的分类:


创建型模式:对象的创建(6)

简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。


结构型模式:对象的组成(结构)(7)

外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。


行为型模式:对象的行为(10)

模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。

 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值