java 的 四 个 基 本 特 性 ——封装 继承 多态 抽象
赶上明天就还是五一c小长假了,准备在这几天写几篇原创文章,供大家一起学习。
首先今天就来好好地唠一唠,到底java的那几个特性都是什么呢?到底怎么用呢?相信一定有一些小白对此会有些懊恼,没关系的,谁还不是从那个时候过来的呢!接下来我来一步一步的由潜到深的谈一谈我的看法,下面是我要说的内容
1.总体概括
2.概念的理解
3.代码示例并且分析
4.个人心得总结
1.总体概括
sequenceDiagram
封装->>继承: java的四个基本特性
多态->>抽象: java的四个基本特性
2.概念的理解
- [1] 封装:
- 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了代码的安全性。
通俗一点的可以这么理解,其实生活中有很多例子的,我来打几个比方,
例如:我们都使用果QQ这个聊天软件的,那么咱们要是想要使用它的话就必须要先注册
,等注册好的时候下次我们在直接输入我们自己设定的密码就可以了,不需要进行其他的操作
这个过程其实就是把QQ里面的数据给封装起来了,防止用户随
意更改,只有程序员才可以,这样他便可以保护程序的安全性
也就是说用户不需要直到QQ他是怎么执行的,内部是怎么实现的,对用户进行隐藏起来了
还有一种解释也可以说明:比如说个人计算机有很多组件——CPU 内存 磁盘 风扇 等等...
我们不需要直到他的个个组件之间是怎么联系的,只要知道他们的个个功能是如何实现的就可以了
生活中的例子其实有很多很多 我就不一一说了。(要是还不明白可以私信或者评论区留言)
- [2] 继承
- 继承”(Inheritance),
继承是指一个对度象直接使用另一对象的属性和方法。事实上,我们遇到的很多实体都有继承的含义。例如,问若把汽车看成一个实体,它可以分成多个子实答体,如:卡车、公共汽车等。这些版子实体都具有汽车的特性,权因此,汽车是它们的"父亲",而这些子实体则是汽车的"孩子"(但是孩子也会有自己新产生的特征)。子类是父类的特殊化,也就是子类的实例(对象)一定是父类的实例 ,但是反过来不一定成立
同样也说一个通俗易懂的例子:比如说,你家的家谱图,这其实就是一个很明显的一个继承关系
你的爸爸继承了你的爷爷(也就是子类继承父类),那么你的爸爸肯定会有可你爷爷相同的特征,但是呢! 你一定会发现你有一些特征是不同于你的爷爷的(当然也不同于你的奶奶),你会有你自己独一无二的特征,这就是继承的关系
- [3] 多态
- 概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用父类的引用指向子类的对象(变量)。
原因:我们知道,封装可以隐藏实现细节,使得代码模块化;
继承可以扩展已存在的代码模块(类);
它们的目的都是为了代码重用。而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性.。
耦合度讲的是模块模块之间,代码代码之间的关联度,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的的目的,模块模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。
有两个好处: 1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承 2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。//多态的真正作用, 可以用在方法的参数中 和 方法的返回类型中。 (子类变量引用父类的变量)
- [4] 抽象:
就是把一个对象分析出各个属性, 来替代表达的手法 。
抽 就是抽离;象 ,表复象。表示出来的部分
比如一棵树。整个一看我们就知道是树,但是具体是为什么呢
这制样就要拿树和其它东西比出不一样的地方,这些地方就是抽象出来的。
抽象出来的东西脱离了树本身,也就变得没有意义,但是组合起来百就是树的概念。
比如一棵树,10米高,树皮粗糙,树叶是针形,树干很直,等等。这些属性组合起来会感觉是一颗松树。但是单独说 10 米,没有对象的话,就不知道这个是说的什么东西。
编程上将对象抽象化是很有用的一个方法,能将枯燥的数据与单一度对象对应起来,这样易于理解,也便于编程。
例如在编写学员管理系统。
学生的定义,首先要有名字,再有性别,问再有学号,等等等等。这些就是抽象出来的属性
3.代码示例并且分析
- [1] 多态
public class Main {
public static void main(String[] args) {
// 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}
public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
class Income {
protected double income;
//构造方法
public Income(double income) {
this.income = income;
}
//定义一个方法
public double getTax() {
return income * 0.1; // 税率10%
}
}
//子类Salary继承父类Income
class Salary extends Income {
//构造方法
public Salary(double income) {
//super调用了继承的Salary中的构造方法
super(income);
}
@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
输出:800.0
观察totalTax()方法:利用多态,totalTax()只需和income来打交道它完全不需要知道要StateCouncilSpecialAllowance和Salary的存在,就可以完全计算出得到的税,如果我们要增加一种稿费的收入,只需要重income中派生出来,然后正确覆盖getTax方法()就可以,把新的类型传入给getTax()就可以了
,不需要在重新修改代码
可以看出:多态是一个多么强大的功能,就是允许添加更多类型的子类实现功能扩展,却不需要修改基于父类的代码
- [2] 继承
public class Bike {
int speed;
int brand;
int colornum;
//构造方法
Bike(){
System.out.println(" call bike constructor");
}
public void speedUp() {
speed = 0;
System.out.println(" too slow");
}
public void presshorn() {
System.out.println(" I am riding the bike");
}
}
public class SpeedBike extends Bike{
/**
* super可以调用数据成员及其构造方法
*/
SpeedBike(){//子类的构造方法
super();
super.colornum=12;//子类调用数据成员
super.presshorn();
System.out.println("call bike construction");
}
public void ride() {
System.out.println("I am riding the bike");
}
/**
* super可以调用父类的方法
*/
public void speedUp() {
super.speedUp();
speed+=10;
System.out.println("so fasyt! ," + " my speed is " + speed + " now");
}
}
public class DemoBike{
public static void main(String[] args) {
SpeedBike aride = new SpeedBike();
aride.presshorn();
aride.speedUp();
aride.ride();
}
}
输出:
call bike constructor
I am riding the bike
call bike construction
I am riding the bike
too slow
so fasyt! , my speed is 10 now(这个输出代码就是覆盖重写了父类的方法)
I am riding the bike
- [3] 抽象
如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract来实现,因为无法执行抽象方法,因此这个类必须申请为抽象类
例如:Person 类定义了抽象方法run(),那么,在实现子类Student的时候,就必须覆盖run()方法
public class Main {
public static void main(String[] args) {
Person p= new Student();
p.run();
}
}
abstract class Person() {
public abstract void run();
}
class Student extends Person{
@overriding
public void run() {
System.out.println("Student . run");
}
}
- [4] 封装
package com.fengzhuang;
class Car{
private String name;//私有成员,名称
private String color;//私有成员,颜色
private String size;//私有成员,大小
//得到String类型名字的方法,最后return 返回去
public String getName(){
return name;
}
public String getColor(){
return color;
}
public String getSize(){
return size;
}
//因为方法名和参数名相同,所有用this
public void setName(String name){
this.name=name;
}
public void setColor(String color){
this.color=color;
}
public void setSize(String size){
this.size=size;
}
}
package com.fengzhuang;
public class Test{
public static void main(String[] args){
Car b=new Car();//实例化操作
b.setName("宝马");//赋值
b.setColor("红色");
b.setSize("大型");
//很明显这些过程看不到如何实现。
String name=b.getName();//取值
String color=b.getColor();
String size=b.getSize();
//最后输出结果
System.out.println(name+":"+color+":"+size);
}
}
输出:
宝马:红色:大型
解析:因为声名变量的时候我们已经设置他们几个为私有变量了,所以我们要是还想在访问它的话只有通过set这个建立器才可以进行访问
抽象和接口在实际开发一个项目中可是很常用的呢,为了把所掌握的知识灵活的应用到开发中,下面是自己在实际写项目的时候遇到的问题,希望对你们有所帮助。
抽象类:强调的是把共同的属性方法给抽象出来,统一写到一个地方(他们实现的代码是一样的),方便维护。(也就是上面所说的面向对象的特征中的继承)。
接口:也就是抽象的行为,比如说:一个狗,他的颜色,白色,黄色等,那么狗就可以看作成接口,它的颜色之类的就可以抽象成方法。当多个对象都拥有相同的行为,但行为的具体实现方式不一样的时候就可以用接口抽象(也就是面向对象中的多态的特性)。
所以一般在实际开发项目中接口和抽象类是配合使用而不是相互代替
例如:所有的订单都有单号,单价,数量,而且是相同的,所以可以用一个抽象类给统一描述出来
public abstract class AbstractOrder{
private String seriable;//单号
private Double money;//单价
private int number;//数量
}
再有一个商品订单,还有一个独有的商品的名称 属性。所以在新建一个ProductOrder继承AbstractOrder
public class ProductOrder extends AbstractOrder{
private String productName;
}
另外,所有的订单都需要支付,但是支付方式又不一样,比如:微信支付,支付宝支付,同一种行为,但是具体的行为方式又不一样,所以用一个接口给抽象出来(规定一个行为标准)
public interface PayWay{
public boolean pay();
}
public class weixinPayWay implements PayWay{
@override
public boolean pay(){
System.out.println("微信支付成功 ");
return false;
}
}
因为所有的订单都需要支付,所以只需要改造AbstractOrder类在里面增加一个 支付行为
Public abstract class AbstractOrder{
private String serialNo;//单号
private Double money;//单价
private int number;//数量
private PayWay payWay;//支付行为
}
比如:每种支付方式,支付之前都需要验证一下子,支付金额是真的不确定,不能小于等于0,因为校验证方式,校验证代码都是一样的,所以我们可以定义一个抽象类给他抽象出来
public abstract class AbstractPayWay implements PayWay{
private Double money;
private boolean verify(){
reurn money !=NULL && money>0;
}
/**
这里实现了payWay中的pay接口方法,所以AbstractPayWay的子类,无需实现该方法
*只需要实现doPay()方法,并且如果doPay()方法被成功f调用说明校验证成功了。
*/
@override
public boolean pay(){
if(!=verify){
System.out.println(" 支付金额验证错误");
return false;
}
return this.doPlay();
}
public abstract boolean doPay();
}
4.个人心得总结
前面已经说了这么写了,那我就最后说一点,总结一下这些吧!
封装的优势在于定义只可以在类内部进行对属性的操作,外部无法对这些属性指手画脚,要想修改,也只能通过你定义的封装方法;
继承减少了代码的冗余,省略了很多重复代码,开发者可以从父类底层定义所有子类必须有的属性和方法,以达到耦合的目的;
多态实现了方法的个性化,不同的子类根据具体状况可以实现不同的方法,光有父类定义的方法不够灵活,遇见特殊状况就捉襟见肘了
这些是我对这些的理解,希望可以对大家有所帮助。——总而言之,这块真的是非常重要的,就是java语言的跟呀!大家一定要好好的理解,多琢磨琢磨,多写写代码,多思考,自然就不难了,就好比"会了不难,难了不会"这个道理是一样的,写这篇文章一方面是为了记录一下子知识点,另一方面也是希望可以帮助那些对这些概念,和代码的运用一知半解的朋友们,原创这篇文章真的很不容易写了好久,希望大家可以多多支持,要是有不懂的可以私信我或者在地下评论,看到了之后我会尽我所能为大家解答的,大家一起学习。(另外明后天我还会陆续连载一些原创文章的要是觉得我写的对你们有帮助的话,可以关注我一下子,方便查找 )