作为一个java码农怎么能不了解面向对象呢!!!,欢迎品尝“面向对象解析”!!!带着思考静心看完
面向对象一般分为三大特征
文章目录
前言
首先先来简单看一下什么是面向对象:面向对象的方法主要是把事物给对象化,包括其属性和行为。面向对象编程更贴近实际生活的思想。总体来说面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象(万物皆对象)
一、封装
什么是封装呢?
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。
数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,
只保留一些对外的接口使其与外部发生联系。
用户无需关心对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
这样做有什么优点呢?
减少耦合:可以独立地开发、测试、优化、使用、理解和修改
减轻维护的负担:可以更容易被理解,并且在调试的时候可以不影响其他模块
有效地调节性能:可以通过剖析来确定哪些模块影响了系统的性能
提高软件的可重用性
降低了构建大型系统的风险:即使整个系统不可用,但是这些独立的模块却有可能是可用的
用代码做一个简单的演示,这里通过private将属性name封装起来,只能在本类中才能调用,外部调用只能通过类提供的get,set方法,或其余一些自定义方法
代码示例
public class AbstractDemo{
//封装
private String name;
//给外部访问提供方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "AbstractDemo{" +
"name='" + name + '\'' +
'}';
}
//省略......
}
二、继承
什么是继承呢?
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的优点和缺点?
优点:
● 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
● 提高代码的重用性;
● 子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有 父的“种”,“世界上没有两片完全相同的叶子”是指明子与父的不同;
● 提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,君不见很多开源框架的扩展接口都是通过继承父类来完成的;
● 提高产品或项目的开放性。
缺点:
● 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
● 降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;
● 增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修 改,而且在 缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大段的代码需要重构。
类继承的格式:
class 父类 {
}
class 子类 extends 父类 {
}
代码示例
上面说到继承可提高代码的重用性,用代码来说一下
创建一个男人类和女人类:
男人类(示例):
public class man {
private String name;
private int id;
public man(String myName, int id) {
name = myName;
id = id;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void play() {
System.out.println(name+"正在玩");
}
}
女人类(示例):
public class woman {
private String name;
private int id;
public woman(String myName, int id) {
name = myName;
id = id;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void play() {
System.out.println(name+"正在玩");
}
}
上面可以看出男人类和女人类的代码结构几乎一样,这个时候就要去想着把这部分重复代码进行封装,所以java就有了继承的思想,创建一个公共类(父类)
创建一个父类mankind
//父类
public class mankind {
private String name;
private int id;
public mankind(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void play() {
System.out.println(name+"正在玩");
}
}
然后男人和女人都可以直接继承这个类
//女人类继承父类,同时创建一个默认的构造函数
public class woman extends mankind{
public woman(String myName, int myid) {
super(myName, myid);
}
}
*********************男人类*********************
public class man extends mankind{
public man(String myName, int myid) {
super(myName, myid);
}
}
*********************调用男人类进行测试*********************
public static void main(String[] args) {
man m = new man("男人", 007);
//我们发现在man类中没有定义这些方法,但是却可以调用,这就是继承的特点,子类拥有父类的方法和属性
//父亲有的,你儿子必须有,儿子有的父亲不一定有
m.eat();
m.play();
m.sleep();
}
//打印结果
男人正在吃
男人正在玩
男人正在睡
简单来说就是父亲有的儿子一定要有,青出于蓝而胜于蓝,最差也要等于“蓝”
Super关键词
在子类继承父类后在默认构造函数中可以看到一个super关键词,也来说一下它的作用:
鼠标放上去后会发现super指向的是父类的构造方法这也就是它的作用
我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
另外还有一个this关键词这个关键词的作用是:
指向自己的引用,调用的是自身的方法
this关键词
public class man extends mankind{
public man(String myName, int myid) {
super(myName, myid);
}
@Override
public void eat(){
System.out.println("男人在睡觉");
}
void test(){
super.eat();
this.eat();
}
}
*************调用测试**************
public static void main(String[] args) {
man m = new man("男人", 007);
m.test();
}
打印结果
从打印结果可以看出this是指向本身的方法,super是指向父类的方法
三、多态
多态其实算是几个特征中比较难以理解的,但是在编码过程中其实又会经常使用多态这个概念,先来看一下多态的官方解释:
多态是同一个行为具有多个不同表现形式或形态的能力
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
1、如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
2、如果当前在 Word 下弹出的就是 Word 帮助;
在 Windows 下弹出的就是 Windows 帮助和支持。
3、同一个事件发生在不同的对象上会产生不同的结果。
仔细思考一下大概能理解多态的概念,但是有感觉“药性”不够,接下来就共同看一下多态到底是什么
先说一下多态的实现有三个条件
1.要有继承(实现implements)
2.要有重写(overWrite&overRide)
3.父类引用指向子类对象
多态也分为两种形式:
编译型多态
编译型多态就是在编译过程中进实现了多态,重载就是最标志的编译型多态
- 编译期间就能决定目标方法
- 通过oveload重载实现
- 方法名相同,参数不同
代码示例
public class overLoad001 {
public int overLoad(int a){
return a;
}
public int overLoad(int a,int b ){
return a+b;
}
public int overLoad(int a,int b,int c){
return a+b+c;
}
public static void main(String[] args) {
overLoad001 overLoad001= new overLoad001();
//在编译过程中就去找到对应的目标方法
System.out.println(overLoad001.overLoad(1));
System.out.println(overLoad001.overLoad(1,3,5));
System.out.println(overLoad001.overLoad(1,2));
}
}
运行结果
运行型多态
顾名思义就是在运行的时候才会去确定目标方法
- 运行时才会决定目标方法,由jvm决定目标方法
- 同名同参
- 重写和继承实现
趁机说一下多态又分为向上转型和向下转型
向上转型
- 向上转型 父类 父类对象 = 子类实例
- 父类有的方法,都可以调用,如果被子类重写了,则会调用子类的方法
- 父类没有的方法,而子类存在,则不能调用。
- 向上转型只对方法有影响,对属性没影响。属性不存在重写。
接下来通过代码来说明,先创建两个类,父类和子类
代码如下(示例):
//先创建一个父类,拥有两个方法
public class father {
void eat(){
System.out.println("父亲在吃饭");
}
void sleep(){
System.out.println("父亲在睡觉");
}
}
//创建一个子类,然后继承父类,同时也有两个和父类相同的方法
public class son extends father{
void eat(){
System.out.println("儿子在吃饭");
}
void sleep(){
System.out.println("儿子在睡觉");
}
}
//创建一个测试类
public class Test003 {
public static void main(String[] args) {
//注意这个创建对象方式上的不同
//符合向上转型的规则 父类 父类对象 = 子类实例
father father = new son();
father.eat();
father.sleep();;
}
}
打印结果
father father = new son();
这种可以看到我们创建的是一个father类型的对象,但是在调用方法确实son中的方法,这其实就是一种多态的体现
当子类中重写了父类的方法那么就会去执行子类中的方法那么通过子类没有去实现父类中的方法会是什么效果呢
public class father {
void eat(){
System.out.println("父亲在吃饭");
}
void sleep(){
System.out.println("父亲在睡觉");
}
//创建一个新的方法,子类没有进行重写
void run(){
System.out.println("父亲在跑步并且子类没有实现我");
}
}
测试结果应该和你想的一样,当子类中额米有重写父类中的方法的时候当然是去执行父类中的方法了
简单来说就是子类重写父类的方法那么就就是子类的实例,在jvm调用的时候把就会去执行子类中的方法,当子类没有重写父类方法的时候那么该方法就是指向父类实例,在调用的时候自然就是调用父类中的方法
以上是多态的向上转型好处是:
- 减少重复代码,使代码变得简洁。
- 提高系统扩展性。
- 用于参数统一化,假设父类有n个子类,方法要接受子类的实例,如果没有向上转型,就需要定义n个方法接收不同的对象。
向下转型
对象的向下转型:子类 子类对象 = (子类)父类实例
接着上面的例子我们在son类中创建一个父类中不存在的方法
public class son extends father{
void eat(){
System.out.println("儿子在吃饭");
}
void sleep(){
System.out.println("儿子在睡觉");
}
//父类中没有的方法
void play(){
System.out.println("儿子在玩");
}
}
然后我们去测试类中调用play方法
可以看到这个时候编译不通过,也就是说向上转型不能去调用父类中没有的子类方法,那么这个时候就去试试向下转型
这里我们看到按照向下转型的语法格式子类 子类对象 = (子类)父类实例我们虽然可以调用子类中的play方法但是却会在运行时报错这是因为
向下转型之前一定要进行向上转型!!
否则在转型时会出现ClassCastException(类型转换异常–运行时异常)
问题: 如果向下转型存在安全隐患,那么如何转型才靠谱?
答:先判断在转型(依靠instanceof关键字实现)引用名 instanceof 类 表示该引用是否能表示该类实例,返回boolean类型。
那么我们先进行向上转型再进行向下转型试一下
这时候我们发现运行通过成功调用play();
向下转型一般是在类需要调用子类的扩充方法时,才需要向下转型。
总结
封装
什么是封装?
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。
数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,
只保留一些对外的接口使其与外部发生联系。
用户无需关心对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
封装的好处
- 减少耦合:可以独立地开发、测试、优化、使用、理解和修改
- 减轻维护的负担:可以更容易被理解,并且在调试的时候可以不影响其他模块
- 有效地调节性能:可以通过剖析来确定哪些模块影响了系统的性能
提高软件的可重用性- 降低了构建大型系统的风险:即使整个系统不可用,但是这些独立的模块却有可能是可用的
继承
什么是继承呢?
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的优点和缺点?
优点:
● 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
● 提高代码的重用性;
● 子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有 父的“种”,“世界上没有两片完全相同的叶子”是指明子与父的不同;
● 提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,君不见很多开源框架的扩展接口都是通过继承父类来完成的;
● 提高产品或项目的开放性。
缺点:
● 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
● 降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;
● 增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修 改,而且在 缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大段的代码需要重构。
多态
多态的好处
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他 任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
看到这如果感觉有所帮助的话就点一个小小的关注吧