前言

😁最近系统的梳理了一下Java的基础知识,面向对象无疑是Java的一大特色。

😉提到C语言我们会想到面向过程,提到Java我们不免想到面向对象。

❓细心思考,面向对象到底是什么呢?

😃C语言的基本组成单位是函数(Function),我们把问题拆分成若干个小问题,通过顺序、选择、循环结构解决这些问题的过程叫做面向过程

😋Java的基本组成单位是类(Class),万物皆是对象,对象有它的属性和方法。对象映射现实中的事物,我们通过对象之间的关系来描述事物之间的联系,这种思想就是面向对象。它最大的特点就是抽象。因而不好理解,需要通过实践才能体会到面向对象的优势所在。

Java

面向对象

类的概念

😁类是面向对象的特色。万物皆是对象,我们通常把某一类事物的共同特点抽象出来,它们组成了类。

🤣类是对某一类事物特点的抽象,这些定义有些晦涩难懂,我们不妨举一个例子:

🐾自行车、汽车、火车,它们是三个不同的对象

🛒它们都是交通工具,既然是交通工具,都有速度。当然,也有自己的外观,如颜色。这是它们的属性

🎉除此之外,它们的功能有:前进、刹车。这是它们的方法

java1

🎡如图所示,交通工具就是一个类,自行车、汽车、火车是这个类的实例化对象

😁类是抽象的,而对象的具体的。我们称对象是对类的实例化

我们通过代码实现上述例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.itheima.first;

public class Transport {

int speed; //交通工具的速度
String color; //交通工具的颜色

//交通工具前进
void run(){
System.out.println("交通工具前进");
}

//交通工具刹车
void stop(){
System.out.println("交通工具刹车");
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.itheima.first;

public class Temp{
public static void main(String[] args){

Transport bicycle = new Transport(); //创建一个对象bicycle

bicycle.speed = 5; //设置速度为5
bicycle.color = "Red"; //设置颜色为Red

System.out.println("自行车的速度:" + bicycle.speed + " 自行车的颜色:" + bicycle.color); //打印输出速度和颜色

bicycle.run(); //自行车前进
bicycle.stop(); //自行车刹车
}
}

我们运行后得到如下结果:

1
2
3
自行车的速度:5    自行车的颜色:Red
交通工具前进
交通工具刹车

🛒这就是典型的面向对象。我们将类具体化为bicycle对象,bicycle具有类的特征,我们给它赋了具体的值。

🧧我们还发现,实例化对象的方法是:

1
Transport bicycle = new Transport();    //创建一个对象bicycle

🎃我们创建bicycle对象时:

new Transport()实际上在中创建了一个Transport对象

bicycle是一个对Transport对象的引用变量,它保存在中。

😂为什么要这样设计呢?这和Java的垃圾回收机制有关,一但没有引用变量指向堆中的对象,这个对象就会被当作垃圾回收,节省系统资源。

访问控制权限

😀对于类、成员属性和成员方法,提供了四种访问级别:private、default、protected、public

private(当前类访问级别):成员只能被当前类访问,无法被外部访问。(用于对类的封装)

default(包访问级别):如果我们省略类或者成员的访问级别修饰符,默认为default,这个类或成员只能被本包中其它类访问。

protected(子类访问级别):成员既能被同包下的任意类访问,也能被不同包下该类的子类访问。

public(公共访问级别):类或成员能被所有类访问。

🎃下面,展示一个权限级别的表格:

访问范围 private default protected public
同一类中
同一包中
子类中
全局范围

抽象类和接口

🍟抽象类即可以包含抽象方法,也可以不包含抽象方法。(抽象方法必须在抽象类中定义)

❓抽象方法是什么呢?使用abstract修饰,定义的方法没有方法体

例如:Animal是一个抽象类,动物的叫声不是固定的,它有一个抽象方法shout,我们不知道shout的具体实现。

😉因为是抽象类,没有给抽象方法具体的实现,当然也不能创建对象。所以必须派生子类,通过子类继承抽象类重写抽象方法

下面使用代码演示上述例子:

1
2
3
4
5
package com.itheima.first;

public abstract class Animal {
public abstract void shout();
}
1
2
3
4
5
6
7
package com.itheima.first;

public class Dog extends Animal{
public void shout(){
System.out.println("汪汪汪~");
}
}
1
2
3
4
5
6
7
8
package com.itheima.first;

public class Temp {
public static void main(String[] args){
Dog dog = new Dog();
dog.shout();
}
}

程序输出结果:

1
汪汪汪~

🎡由此可见,当我们的父类不需要实例化对象,仅仅提供抽象方法时,可以将它写为抽象类

🎈通过抽象类派生子类子类重写抽象方法,然后实例化所需要的对象。

🎫接口是特殊的抽象类,当抽象类中所有的方法都是抽象方法时,这个抽象类可以写为接口。

🎎接口不再使用class,而是interface关键字。

JDK8以后,接口除了抽象方法,还可以包含默认方法和静态方法(类方法)

默认方法使用default修饰,静态方法使用static修饰。这两种方法可以有方法体

注意:接口也可以进行子接口继承操作。为了解决类的单继承限制,一个子接口可以继承多个父类。

(这里不再给出例子,感兴趣可以自行实验)

封装

封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。例如,用户使用电脑,只需要使用手指敲键盘就可以了,无需知道电脑内部是如何工作的,即使用户可能碰巧知道电脑的工作原理,但在使用时,并不完全依赖电脑工作原理这些细节。

🎃我们还是继续上面的例子。

🔩对于交通工具的属性来说,我们只需要set和get它的属性。

如果我们直接使用 bicycle.speed = 5 这样的语句对对象的属性进行修改,很有可能造成某些数值的错误

如果我们使用 bicycle.speed = -1 这在java的语法中是没有问题的,但是显示不符合实际

😘我们可以将speed和private的访问权限修改为private以防止外部对它的修改

😄然后定义setSpeed、getSpeed、setColor、getColor四个方法对属性进行读写

那么,前文的代码就可以修改为如下这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.itheima.first;

public class Transport {

private int speed; //交通工具的速度
private String color; //交通工具的颜色

//设置颜色
public void setColor(String color) {
this.color = color;
}

//设置速度
public void setSpeed(int speed) {
if(speed >= 0) {
this.speed = speed;
}
}

//获取速度
public int getSpeed() {
return speed;
}

//获取颜色
public String getColor() {
return color;
}

//交通工具前进
void run(){
System.out.println("交通工具前进");
}

//交通工具刹车
void stop(){
System.out.println("交通工具刹车");
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.itheima.first;

public class Temp{
public static void main(String[] args){

Transport bicycle = new Transport(); //创建一个对象bicycle

bicycle.setSpeed(5);
bicycle.setColor("Red");

System.out.println("自行车的速度:" + bicycle.getSpeed() + " 自行车的颜色:" + bicycle.getColor()); //打印输出速度和颜色

bicycle.run(); //自行车前进
bicycle.stop(); //自行车刹车
}
}

🎃代码中出现了this关键字。this表示当前类的对象,this.color表示当前对象的成员变量color。(这样可以避免成员变量方法内部变量名的冲突)

继承

继承主要描述的就是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展。例如,有一个汽车的类,该类中描述了汽车的普通属性和功能,而轿车的类中不仅应该包含汽车的属性和功能,还应该增加轿车特有的属性和功能,这时,可以让轿车类继承汽车类,在轿车类中单独添加轿车特有的属性和功能就可以了。继承不仅增强了代码的复用性、提高开发效率,还为程序的维护补充提供了便利。

😄我们还是通过具体的例子来理解继承。

🚗假设我们有一个类:汽车

🎶汽车是一个大的范围,继续可以划分为轿车和跑车等。

🔩轿车和跑车都具体汽车的特点,同时具有自己的特点

java2

  • 汽车是父类

  • 桥车和跑车是汽车的子类

  • 宝马、五菱、兰博基尼、玛莎拉蒂是子类的实例化对象

子类既可以对父类进行拓展、也可以重写父类的方法。

下面,我们使用代码来展示一下上述内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.itheima.first;

public class Car {
private int speed;
private String color;

public void setSpeed(int speed) {
this.speed = speed;
}

public void setColor(String color) {
this.color = color;
}

public String getColor() {
return color;
}

public int getSpeed() {
return speed;
}

public void run(){
System.out.println("前进");
}

public void stop(){
System.out.println("刹车");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.itheima.first;

public class SportCar extends Car{

//跑车类重写父类的run方法
public void run(){
System.out.println("跑车起飞");
}

//跑车类拓展父类方法:显示价格
public void printPrice(){
System.out.println("跑车价值100万");
}

}
1
2
3
4
5
6
7
8
9
10
11
package com.itheima.first;

public class Temp{
public static void main(String[] args){
SportCar sportCar = new SportCar(); //定义子类对象sportCar
sportCar.setSpeed(10); //设置速度
sportCar.setColor("红色"); //设置颜色
sportCar.run(); //子类重写父类的方法,输出子类的方法
sportCar.printPrice(); //子类拓展方法,显示跑车价格
}
}

运行后输出结果是:

1
2
跑车起飞
跑车价值100万

由此可见,子类既可以对父类进行拓展,也可以重写父类的方法。子类会继承父类中public成员

通过子类继承父类的特点,我们可以提高代码复用性灵活性

有一点需要注意:所有的类都是直接或间接继承Object类,如果我们定义类没有写extends,它默认是Object的子类

多态

多态指的是在一个类中定义的属性和功能被其他类继承后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同行为特性。例如,当听到“Cut” 这个单词时,理发师的行为表现是剪发,演员的行为表现是停止表演等。不同的对象,所表现的行为是不一样的。

🎡这里很容易和继承弄混。

继承,子类继承父类->子类重写父类方法或拓展父类->创建子类引用变量->引用子类对象

多态,子类继承父类->子类重写父类方法->创建父类引用变量->引用子类对象

把子类对象直接赋值给父类引用变量这句话是关键。我们创建的是父类引用变量,它指向子类对象。实际上发生了类型转换

多态的优点是消除了类之间的耦合关系、提高程序拓展性、可维护性

下面使用一个例子演示多态:

1
2
3
4
5
package com.itheima.first;

public abstract class Animal {
public abstract void shout();
}
1
2
3
4
5
6
7
package com.itheima.first;

public class Dog extends Animal{
public void shout(){
System.out.println("汪汪汪~");
}
}
1
2
3
4
5
6
7
8
package com.itheima.first;

public class Temp {
public static void main(String[] args){
Animal dog = new Dog();
dog.shout();
}
}

程序输出内容:

1
汪汪汪~

🐕由于dog是Animal类型,它只有Animal成员,不能执行Dog类特有的成员方法

🎃我们把Dog类对象当作它的父类Animal类对象来使用,这里实际上是自动向上转型

🎠既然有向上转型,也有向下转型,向下转型需要我们强制转型。这里不再详细说明,有兴趣可自行查找资料。

总结

🐾以上内容仅仅是个人对Java面向对象特性中类、抽象类和接口、封装、继承和多态的一些理解。

🎈所涉及的知识点也只是讲了一些有代表性的知识点,并没有过于深入探讨研究。

🎡仅仅是个人看法,用于加深对面向对象编程思想的理解。

🚩创作不易,本人保证所发文章均为精心筹备。

💌如需转载,请保留作者信息和博客地址。

📡如果感觉博客对你略有帮助,欢迎转发给你的朋友,让他们加入到技术风暴中来吧!