[Java教程]24.面向对象三大特性

Java教程专栏:https://blog.csdn.net/qq_41806966/category_9929686.html

hello,I'm shendi

这节学习面向对象三大特性


目录

面向对象三大特性

封装

 

实例

继承

父子关系

多实现

方法的重写

多态

实例


面向对象三大特性

面向对象三大特性分别为

  • 封装(不要告诉我你是怎么做的,只要做就可以了)
  • 继承(使一个类与另一个类建立父子关系)
  • 多态(事物的多态性)

先从封装开始


封装

封装是三大特性中最简单的

用的多的地方就是Java Bean了

*Java Bean 就是一个类,只不过这个类比较特别,是专门用表示数据的,这里先了解下

那么,什么是封装呢?

封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。

封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员。

通俗的讲,封装就是将变量私有化(private),并且在类里提供对此变量操作的方法

封装是一种思想,不止局限于变量.

举个粒子

  • 我有一台手机,这台手机属于我,别人可以使用一下,但是不能改变这个手机属于我的事实
    • 所以这台手机是私有的,别人可以获取,但是不能对此变量进行设置,这就是对手机做了封装 (只提供获取的操作)
  • 有一个奇怪的房子,当有人打开房门时会记录次数,并将此人信息记录
    • 记录的次数是一个变量,打开房门是一个方法.

为什么需要封装呢?

通过上面的例子举栗子

  • 手机是一个变量,如果是public的,也就是说别人都可以随意修改我持有的手机,甚至可以改成null(空),如果别人改成空就代表我没有手机了,所以,这当然不是我想要的,于是把变量私有化,并且提供一个公有的方法来获取这个手机
  • 例2更加容易理解,有一个变量为记录打开房门的次数,并且打开房门会使得次数+1
    • 打开房门的次数没有人能够知道,除了房子本身.
    • 打开房门的次数可以通过打开房门来进行修改,但是这个修改是被限制的(每次+1,而不是随意修改)

 

实例

读万卷书不如行万里路,敲代码更助于学习理解

我们实现一个电子书籍类

每一个书籍都有书名,作者,评论数,赞,不赞等数据

对于用户来说,书名,作者,是不可修改的,但是可以知道内容

用户可以发表评论,赞此书,以及不赞此书

先自己尝试着敲代码,然后再看下方的示例代码

示例代码

此类中有五个变量,对应的有五个方法,代码如下

/** create with Shendi */
public class Encapsulation {
	/** 采用驼峰式命名,之前讲过首单词小写,后续单词的第一个字母大写
	 * 书名 */
	private String bookName = "神奇的书";
	// 作者
	private String author = "当然是神仙";
	// 评论数
	private int cNum = 0;
	// 赞数
	private int goodNum = 0;
	// 不赞数
	private int noGoodNum = 0;
	
	// 评论
	public void comment(String c) {
		System.out.println("评论了: " + c);
		// 这里评论数要+1, 此方法对评论数做了封装
		cNum++;
	}
	
	public void good() {
		System.out.println("神奇人物赞了" + bookName);
		// 赞数++
		goodNum++;
	}
	
	public void noGood() {
		System.out.println("神奇人物觉得此不行: " + bookName);
		// no赞数++
		noGoodNum++;
	}
	
	// 获取书名,书名不可以被用户修改,封装了书名
	// 这里的get是获取的意思,对于变量的封装的获取操作,前缀都应该为get(是一种规范)
	public String getBookName() {
		return bookName;
	}
	
	// 获取作者
	public String getAuthor() {
		return author;
	}
}

对一个变量的封装通常分为两种,一种是获取(get),一种是设置(set)

对于获取,方法名应该以 get 开头

对于设置,方法名应该以 set 开头

这是一种规范,因为后面会使用到 IDE(编辑器),里面可以提示一个类有某些方法...

在列举一种非常常见的封装代码

对一个变量提供get和set方法

private int num;
public int getNum() {
    return num;
}

public void setNum(int num) {
    this.num = num;
}

这种就是又提供获取又提供设置

  • 获取的方法是返回一个int,因为是获取
  • 设置的没有返回值,但是需要传递一个参数,代表你要设置的值

方法里的 this 关键字之前讲过,代表使用当前类里的对象,而不是方法里的(因为num和num重名了,如果不用this就会使用方法里的num,而达不到想要的效果)

那么,你可能会有疑问了,既然又提供get,又提供set,那么为什么要将变量私有化呢?为什么不直接public?

因为封装的作用不仅仅在于此,可以解耦合,如果直接使用变量,当我们需求更改,需要改变那个变量的时候,例如上方的num要改为字符串类型

这个时候使用到此变量的类都会出错,当使用的类很多,我们需要一个一个去修改(耦合在一起了),那得多恐怖

但是我们提供了封装的方法,例如getNum();

当我们将 num 变量改成字符串的时候,出错的只有 getNum() 这个方法,我们可以只用修改此方法来达到更改需求的目的 


继承

程序语言为了更加便于理解,于是越来越人性化,越来越贴近生活

继承可以让两个类建立父子关系

需要知道的是,在 Java 中只允许单继承,但是可以多实现

使用 extends 关键字来表示继承

例如

class A extends B {}

这个时候,A就是B的子类(儿子),B就是A的父类(父亲)

父子关系

当你的类继承了另一个类,那么子类会自动继承父类的属性和行为,在之前学过的权限访问修饰符中可以看出,除了private修饰的属性/方法,其余的子类也会自动拥有

子类对象可以自动转换成父类,但是父类转换成子类需要强制转换

例如

class B {

}

class A extends B {

}

class Test {
    ........main() {
        A a = new A();
        B b = a;
    }
}

但是父类转换子类需要强制转换

....main() {
    B b = new B();
    // 强制转换的语法是在需要被转换的对象前加一个括号,括号内是要转换的类型
    A a = (B) b;
}

子类对象转父类称为向上转型(向上的),父类对象转子类称为向下转型

需要注意的是,父类对象转子类,如果此对象不是子类对象,则会出现转换错误

很好理解,因为子类属于父类,但是父类不属于子类

多实现

我们还没有学习接口,后续将会进行学习

一个新的关键字 implements 用于实现接口

Java中,类只能继承类,但是可以实现接口

接口就是只定义一些行为(方法)的特殊类

实现接口的代码

class A implements B {

}

与继承一样,也可以进行转换

不同的是可以实现多个接口

并且子类需要实现接口里的所有方法

例如接口里有一方法a

那么子类也需要写一个方法a

方法的重写

在子类中,可以写一个与父类的方法一模一样的方法,那么使用这个方法的时候使用的就是子类的方法

这种被称为方法的重写


多态

多态可能难以理解,当学习了设计模式后会对多态以及继承的使用有一个更深的体会

什么是多态?

多态也是一种思想,事物的多态性,比如说,相同的方法,不同的对象使用有不同的结果

例如鱼类,有的鱼吃肉,有的鱼吃草...

实现多态的必要条件是继承

实例

直接实践比较容易理解

就以鱼来举栗子

每个鱼都有吃的方法

A鱼吃肉,B鱼吃草

代码如下

public class Fish {
	public void eat() {
		System.out.println("父类的鱼吃啥?");
	}
}

class FishA extends Fish {
	public void eat() {
		System.out.println("A鱼吃肉");
	}
}

class FishB extends Fish {
	public void eat() {
		System.out.println("B鱼吃草");
	}
}

上面的鱼A和鱼B都继承Fish类,并重写了eat方法

那么,如何体现多态呢?

接下来我们编写main函数和提供一个格外的方法

public class Fish {
	public void eat() {
		System.out.ptintln("父类的鱼吃啥?");
	}
	
	public static void main(String[] args) {
		FishA a = new FishA();
		FishB b = new FishB();
		fishEat(a);
		fishEat(b);
	}
	
	// 这里是静态的方便使用
	// 参数是父类,这样我们可以实现多态
	public static void fishEat(Fish f) {
		// 如果传递的子类对象这里调用的就是子类的方法
		f.eat();
	}
}

编译运行

输出结果如下

A鱼吃肉
B鱼吃草

可以看出,一个方法,传递不同对象有不同结果 


下一节学习接口

猜你喜欢

转载自blog.csdn.net/qq_41806966/article/details/108553712
今日推荐