java面向对象
面向对象的理解
参考资料:https://blog.csdn.net/xxf159797/article/details/53669822
类
类是对客观事物的一种抽象,但是客观事物有很多属性和行为,我们不可能把所有的属性和行为都抽象出来,所以有什么需求就抽象哪一部分。
比如抽象一本书,如果以一个作家的身份来抽象,可能得到的属性会是页数、字数、写作时长等,抽象的行为会是新增一页内容,修改一段,或者删除一段。
但是如果以出版社的身份来抽象这本书,我们关心的,抽象出来的属性会是出版日期、售价、销量等,抽象的行为是拟定、出版、售卖等。
对象
通过类具体创建的实体,一个类可以创建出任意多个对象。对象实例化类的各个属性并可以使用类的方法(行为)。
类和对象的关系
类可以理解成是对象的模板。
面向对象三大特性:
参考资料:https://blog.csdn.net/xxf159797/article/details/53669822
封装
隐藏内部实现,对外提供某种访问方式。java里面封装的手段是通过访问修饰符。
修饰符 | 当前类 | 同一包内 | 子孙类 | 其他包 | 其他包子孙类 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | N | Y/N(说明) |
default | Y | Y | N | N | N |
private | Y | N | N | N | N |
举个栗子:现在有一个下载文件的demo,封装就是:
隐藏部分:具体实现,如何联网请求,如何将文件保存到本地等;内部控制变量,进度的修改,文件的大小修改等。这些是不可见的,调用者不需要关心如何实现,同时因为安全性,调用者无法修改一些属性。
公开部分:下载的控制,开始,暂停,取消等;可更改的属性:下载目录,文件命名等;
继承
多个类具有共同属性或行为的时候,可以将他们抽取出来定义到一个公共的父类当中,其他各类与父类形成继承关系。这样做的好处是:
- 子类中不需要重复定义相同的属性和行为
- 子类可以直接访问父类的非私有化成员变量
- 方便扩展,代码复用
继承也有缺点,如果很多子类继承一个父类,如果父类发生变化,子类也联动需要修改,造成类与类之间的“强耦合”关系。类与类之间要存在所属关系,不能够随意继承 。
多态
多态可以说是面向对象的精华所在了,继承(泛化)、封装、抽象等都应用在多态上。但是不仅仅面向对象编程有多态,结构化编程(面相过程)也存在多态,比如方法的重载。这里主要说下面向对象中的多态。
一个对象具有多种形态的表现,多态的前提一般有继承。因为在不同场合或者业务场景中,子类是可以替代父类来完成具体的某件事情。
多态在方法上的体现:(行为上的多态)
- 方法重载:通过不同的方法签名,重载同名的方法。方法签名包括:方法名、参数列表(不包括返回值类型)。也就是说方法的重载,主要依靠参数列表的不同,参数列表包括参数个数和参数类型。方法重载在面向对象和结构化编程都存在。
- 方法重写:前提是子类继承父类,子类可以重写父类的非private方法,完成自己特定的行为。
多态在引用转型的体现:(属性上的多态)
参考资料:https://www.cnblogs.com/xjhere/p/5842461.html
父类引用指向子类对象:Animal animal = new Cat(); 向上转型.由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。
那么这样做有什么意义呢? 因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特,定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。
所以,父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法*,它是无可奈何的;同时,父类中的一个方法只有在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法*,这就是动态连接。也可以叫做动态绑定。动态绑定是指”在执行期间(而非编译期间)“判断所引用对象的实际类型,根据实际的类型调用其相应的方法。
抽象类和接口
参考资料:深入理解Java的接口和抽象类
抽象类
在说java抽象类之前,先说说面向对象的抽象特性。一般我们把面向对象分为三大特性,分别是封装、继承、多态,但是也有分四大特性的,第四个就是抽象特性了。这里不用纠结到底分几大特性,因为它们在面向对象中都非常重要。抽象在前面也讲了,就是对客观事物属性和行为的一种提取。
那么java中的抽象类由哪些特点呢,首先,抽象类无法被实例化,且抽象方法无方法体必须由子类实现,如果没有子类继承这个抽象类来实例化出子类来,这个抽象类定义后是没有被用到的,也就是说毫无意义的。那么抽象类是为继承而生的,继承和抽象类连在一起有什么作用?我的理解是:
- 在没有使用抽象类的情况下,我们让一个类继承一个父类,创建一个子类实例之后,我们可以覆写父类的方法,也可以不覆写,我们可以有自己的选择。
- 而在使用了抽象类做父类的情况下,我们创建一个子类继承这个抽象父类,我们必须实现抽象父类的抽象方法,也就是说,类的模板性被加强了!
上面说的其实是抽象父类和普通父类的最主要的区别。作为一个父类,首先父类是对客观事物的抽象,抽象出一个可以由java语言表达的模板(属性,行为),而抽象父类增强了模板性,可以强制子类实现一些抽象方法。
接口
接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。
接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。
抽象和接口的区别
语法层面的区别这里就不再赘述了,这里说下设计思想的区别。
- 抽象类是对整个客观事物的抽象,包括属性和行为(方法),而被abstract修饰的方法是这个客观事物的固有行为。接口仅仅主要对事物的行为(方法)进行抽象,类实现这个接口后可以扩展更多行为。也就是说,抽象类主要体现的是模板性,固有行为,接口主要体现的是扩展行为。
- 设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。
这里举个经典例子:
interface Alarm{
//扩展行为,不是所有门都有报警行为
void alarm();
}
abstract class Door{
//固有行为,所有门都包含开门和关门行为
abstract void openDoor();
abstract void closeDoor();
}
//没有报警器的门,只继承抽象父类,实现固有行为
class TheDoorWithoutAlarm extends Door{
@Override
void openDoor() {
}
@Override
void closeDoor() {
}
}
//有报警器的门,既继承抽象父类也实现报警接口。实现了固有行为和扩展行为
class TheDoorWithAlarm extends Door implements Alarm{
@Override
public void alarm() {
}
@Override
void openDoor() {
}
@Override
void closeDoor() {
}
}