什么是面向对象?
在学习Java中,面向对象是一个非常重要的概念,准确理解面向对象对于我们学习Java这门语言有极大的作用。文章较长,耐心看完你就会明白什么是面向对象!
首先我们要明白,人是高级的动物,遇到问题会想办法找工具来帮助自己解决问题。
假设有这么一个场景:
有一天你看着天空,突发奇想,一直在思考怎么飞上天?于是你就在想有什么工具能让你飞上天?这时聪明的你突然想到了热气球可以带你飞上天,于是你马上去画了一个热气球的图纸,并造出了一个彩色的热气球,最后借助热气球你成功飞上了天空~
请注意,以上的故事体现的就是面向对象的思想:
- 当你遇到困难,你会寻找可以帮助你的工具(Java中的各种写好的包,直接调用里面的方法(相当于故事里的工具)实现你的目的)
- 当没有现成的热气球,你会想到要设计出一个热气球工具(相当于Java写好的包中没有我们想要的类和方法(工具),所以我们要想到自己去画图纸(类)
- 最后我们对照图纸(类),根据图纸造出了一个彩色的热气球(对象)
所以面向对象的思想其实就是借助工具,好比java提供了很多写好的类供我们调用,我们要用工具去创造。如果没有工具,我们就自己创造工具使用,这就是面向对象的精髓。
上面的图纸比做类,图纸里面会标明热气球在制造的时候可以用什么颜色(变量),图纸里面标明热气球要有一个燃烧器(方法),倒入燃料产生火焰。我们根据这样的图纸制造了一个彩色的气球,这个彩色的气球就可以理解为一个对象,因为这个气球我们已经造了,而且指定的是彩色,是现实的东西,所以我们也叫实例。根据图纸(类),我们也可以创造(new)出红色、黄色的热气球,这就是创造不同的对象,也叫不同的实例。
接下来我们再来说说面向对象的三个特性:
1.封装性
- 是面向对象的核心思想之一,封装就是将数据和对数据的操作封装在一起(放在同一个类中)
- 假如有一个关于正方形的图纸(类),那这个图纸一般会标上正方形的边长(变量,或者说数据),如果要计算正方形的面积,我们可以在图纸下面写一条计算公式(方法),当我们要计算正方形的面积的时候,我们就会把正方形的边长代入到公式中,得到结果。
- 以上就是封装的核心,再举个例子,张三砍了李四,造成李四凉凉。是张三直接让李四凉凉的吗?我们转变一下思想:李四有一个让自己凉凉的方法,张三去砍李四,相当于调用了李四的凉凉方法,让李四自己凉凉了。
- 对于封装的理解,我们需要转变常规思维,看明白了你就会豁然开朗
2.继承
- 继承的出现是为了简化代码,减少重复工作,子类可以继承父类的属性与方法,同时也可以重写父类的某些方法、定义自己独有的方法。
- 可以简单理解继承做的是抽取有相同点、相似性的类,抽取出来的相同部分作为父类,以后我们写相关的类时,我们就不用再把属性和方法重写写一遍,只要继承一下父类,基本的属性与方法就有了,再写一点自己的独特的方法,一个新类就完成了。
举个例子:
有一个班长类和组长类
都有属性:姓名、学号
都有方法:学习、吃饭、睡觉
班长有另外一个方法:管理班级
组长有另外一个方法:管理小组
我们把姓名、学号、学习、吃饭、睡觉抽取出来,写一个父类Student类,只要SquadLeader类和GroupLeader类一继承就都有了,我们只要写一份代码。这个例题代码放在文章最后面。
多态
- 多态的意思为对象的多种形态。多态的出现前提是有继承关系,经典应用是在方法中,使用父类型作为参数,可以接收所有子类的对象,简写代码
- 多态有一个弊端,不能使用子类特有功能,需要使用时是要进行类型转换的,多态常伴随instanceof关键字,用于判断对象所属类型。
- 口诀:
对于成员变量:编译看左,运行看左
对于成员方法:编译看左,运行看右
/*javac在编译代码的时候会看左边父类有没有name这个变量
* 如果有,那编译成功,如果没有,就编译失败了。
* java运行代码时,实际就是左边父类成员变量name的值
* */
Animal a = new Dog();
System.out.println(a.name);
/*javac在编译代码的时候会看左边父类有没有show()这个方法
* 如果有,那编译成功,如果没有就编译失败了
* java在运行时,实际上是运行子类的show()方法
* */
a.show();
附录-继承例题代码
父类-Student
public class Student {
//成员变量
private String name;
private int id;
//空参构造方法,用于初始化
public Student() {}
//全参构造方法
public Student(String name,int id) {
this.name = name;
this.id = id;
}
//以下为标准JavaBean 因为我们使用了private 修饰了变量
//所以需要提供相对应的变量的get、set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//学习方法
public void study() {
System.out.println(getName()+"在学习");
}
//吃饭方法
public void eat() {
System.out.println(getName()+"在吃饭");
}
//睡觉方法
public void sleep() {
System.out.println(getName()+"在睡觉");
}
}
子类-SquadLeader
public class SquadLeader extends Student{
//班长类
//extdens 为继承的关键字
//这里已经继承了Student类的变量和方法,我们不需要再写那么多
//只需写班长的独有方法
//构造方法不会被继承,要写
public SquadLeader() {}
public SquadLeader(String name,int id) {
super(name,id);
}
public void manageClass() {
System.out.println("学号为"+getId()+"的"+getName()+"在管理班级");
}
}
子类-GroupLeader
public class GroupLeader extends Student{
//组长类,独有的管理小组方法
public GroupLeader() {}
public GroupLeader(String name,int id) {
super(name,id);
}
public void manageGroup() {
System.out.println("学号为"+getId()+"的"+getName()+"在管理小组");
}
}
主类-Test
public class Test {
public static void main(String[] args) {
//小明是班长对象,小红是组长对象
SquadLeader s = new SquadLeader("小明",2020);
GroupLeader g = new GroupLeader("小红",2021);
s.eat();
s.sleep();
s.study();
s.manageClass();
g.eat();
g.sleep();
g.study();
g.manageGroup();
}
}
程序运行结果: