一,抽象是什么,抽象和面向对象有什么关系
抽象,个人理解,就是抽象的意思
我们都知道面向对象的四大特征:封装,继承,多态,抽象
为什么抽象是面向对象的特征之一,抽象和面向对象有什么关系?
这个东西比较复杂,我自己的水平也很浅,下面说说自己的个人理解
面向对象的诞生
面向对象之前,我们操作内存中的同名变量,动来动去都是同一份;
有了面向对象之后,我们操作的数据被不同对象各自的内存空间分割开,不是同一份。
面向过程
函数从类当中获取并操作数据
不同的函数使用的变量,是内存当中的同一份
面向对象
方法从对象当中获取并操作数据
不同对象的相同方法调用的相同变量,来源于方法区类信息的多份拷贝,
在堆内存中分别属于不同的对象,不是同一份
从内存结构的角度来看,面向对象与面向过程,最大的进步就是内存中数据访问的解耦
public class Person {
private int age;
private String name;
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
}
public Person() {
}
public static void main(String[] args) {
Person p1 = new Person(17,"樱岛麻衣");
Person p2 = new Person(16,"梓川咲太");
}
}
继承与抽象
Java的继承机制,其实就是对现实世界事物之间关系的一种归纳总结
当这种总结是具体而准确的时候,就是单纯的继承
比如Animal类,子类Dog和Cat,显然都具有年龄(age)属性,具有移动(move())方法,所以
这些归纳总结出来的共有的属性,就写在了父类Animal当中,实现了代码和逻辑的复用;
但是,当这种总结继承不能非常具体和准确时,就变成了抽象
比如动物繁衍,单细胞生物就是直接分裂,多细胞生物,有的卵生,有的胎生,等等等等……
繁衍显然是动物拥有的方法,但是又没办法写的那么清楚,最终就变成了抽象方法
重写与抽象的区别(个人理解)
有人说,重写方法不就可以了吗,为什么要专门定义抽象?
一,逻辑关系不同
抽象类当中的抽象方法,只定义方法,不写明实现,需要等待子类实现,明显是从无到有的一种逻辑关系。
而重写,更像是一种增强,父类不需要继承,就可以拥有自定义实现的方法,没有子类也可以
二,实际含义不同
抽象是一套组合拳,不光是方法,就连类也变成了抽象的类,这里抽象的含义主要指事物的本质,因为在单继承环境下,本质只可能有一个
抽象类本身不能实例化也印证了这一点,“本质”就是抽象的,不能映射成现实的对象;
而重写的含义更像是一种“中间阶段”,实实在在的实体类,映射成现实的对象,并没有接近事物的本质
面向对象和抽象的关系
面向对象就是把现实问题抽象为对象,通过调用每个对象的属性或功能去解决问题。
不存在多个对象,这种不同对象的不同实现也就无从定义
这种多个对象同时存在的功能的实现,依赖于内存中数据访问的解耦
- 解耦之后,我们通过继承将代码复用,同时又恢复了耦合,
- 为了将这部分死灰复燃的耦合给解耦掉,同时依然做到代码复用,我们发明了多态(一个父类对象可以接收任意一种子类的对象,将子类方法与子类类型解耦)
- 我们发现实际继承中,出现了难以具象化构建的情况,于是出现了抽象
推荐阅读
Java编程最佳实践之多态 - 阿里云开发者社区
抽象的使用
abstract修饰的类被称为抽象类
abstract修饰的方法被称为抽象方法
- 抽象类当中的抽象方法不能实现
- 如果有类继承了抽象类,那么一定要重写并实现这个抽象方法
- 抽象类才能有抽象方法,普通类不能有抽象方法
- 抽象类可以有非抽象的普通方法,类的普通方法必须实现;子类不会被强制要求重写当前抽象类的普通方法
- 抽象类不能创建对象,但是可以使用多态;
- final不能与abstract同时用,因为两者概念冲突(final修饰类表示基类,基类不能被继承,而抽象类又需要继承;只有子类继承,创建子类对象,才能执行自己的方法)
- abstract不能与private同时修饰抽象方法,因为abstract表示需要子类重写,而private又屏蔽了子类的访问,概念冲突(abstract方法默认是public的)
- 抽象方法不能使用static,因为static方法针对类层次,类内共享;abstract方法只有继承之后创建子类对象,才能被执行,属于对象层次
- 子类不想重写实现父类的抽象方法,这个子类必须也是抽象类
- 抽象类可以有构造方法,但是不能实例化,构造器的作用是多态创建抽象类对象的时候,先初始化抽象父类,也就是在new子类构造器之前,先new 父类构造器
面试题
抽象类一定是一个父类吗?
答案:是的,因为需要子类覆盖其方法后,才可以对子类实例化