封装、继承、多态,认识一下!

封装、继承、多态,认识一下!

作为学习java必须了解的Java特性,跟随本文,认识一下它们吧

封装

最常见的操作,比如我们要定义一个Book类,会将其下定义的变量私有化,然后提供公开的get、set方法。那为什么要这样做呢?原因呢也很简单,我们不希望类以外的程序可以随意的修改我们已经定义好的变量,只能通过我们提供的公有方法来修改或获取;甚至有些字段我们可以只提供get方法,不提供set方法,那么外部就无法修改我们的变量。而这就是封装的基本表现了。
除此之外,有时我们也会对方法进行封装,比如我们有一段逻辑,要获取某作者最新出版的书籍的相关信息,那么就可以将这部分逻辑封装起来,成为一个独立的功能块。当外部想要获取这个信息时,只需要调用我们已经封装好的方法即可。比如下面这一段代码:

public class RecommendService {
    
    BookService bookService;

    // 伪代码
    public Recommend getRecommendations(String authorName){
        Recommend recommend = new Recommend();

        // 1.对传参的非空判断等处理

        // 2.根据authorName查询其最新出版的书籍 
        //   [重点:不需要关心具体的实现,只要了解使用后的结果]
        Book book = bookService.getLatestBookByAuthor(authorName);

        // 3.组装要返回的推荐信息

        return recommend;
    }
}

这段代码中,特别要注意的第二点逻辑说明,这里,我们只想获取一条书籍的推荐信息,我们并不想关心具体的实现,可能这一段逻辑在项目多处使用了,那么封装起来,一是避免了重复代码的使用,二是当这段逻辑内部的实现有改动,只需要更改一处即可,极大的简化了代码的维护。这也是封装的意义所在——降低耦合。
最后简单总结一下封装的特性(意义):

  1. 私有化成员属性,避免类外部的程序对其随意的修改,只能通过提供的公有化方法操作属性。
  2. 隐藏方法的具体实现,使得外部的调用更自由,逻辑清晰。
  3. 将功能模块化,以降低耦合。

继承

继承,简单来说,就是为了实现代码的重用。继承的关键字是extends,extend意为扩展,“public class A extends B(){}”,从这段使用继承的基本结构中,可简单理解为就是A对B的扩展。而这里,引申出两个概念——子类(派生类),父类(基类,超类)。上述中,B的角色是父类,它就好比制作PPT时选用的模板,而A的角色是子类,它在模板(B)上去绘制,可以对模板里可修改的文字、图片进行修改。
以下面两段代码说明一下:

public class Sport {
    // 名称
    private String name;

    public Sport(String name) {
        this.name = name;
    }
    
    public void print(){
        System.out.println("Sport");
    }
}
public class Football extends Sport {
    // 规则说明
    private String rule;

    public Football(String name, String rule) {
        super(name); // 调用父类构造器
        this.rule = rule;
    }

    public void print(){
        System.out.println("我是足球");
    }

}
public class Football extends Sport {

    // 规则说明
    private String rule;

    public Football(String name, String rule) {
        super(name);// 调用父类构造器
        this.rule = rule;
    }

//    public void print(){
//        System.out.println("我是足球");
//    }

    public static void main(String[] args) {
        Football football = new Football("足球","...");
        football.print();
    }

}

这里,FootBall类继承了Sport类,有这样几点说明:

  1. FootBall类继承了Sport类,所以可以获取Sport类定义的name变量。而既然name属性是属于父类Sport的,那么就应该在Sport的构造器中为name属性赋值,而在Football类中的构造器,只需调用父类对应赋值的构造器即可。
  2. 额外说明的是Football类拥有了name属性,不代表在构造器中可以使用this.name=name来赋值,因为Sport类中name属性是私有化的,如果两个类是在同一个包下,则修改Sport类的那么属性为protected,会发现this.name=name来赋值不再报错,但是实际开发中,往往父类、子类不在同一个包下,所以不推荐这样使用。
  3. FootBall类继承了Sport类,就获取了父类里定义的print方法,所以,虽然Football类里没有定义print方法,依旧可以使用。注意:构造方法不能被继承。
  4. main方法中实例化Football时,其执行顺序是先进入Football类的构造器,然后执行Sport类初始化(构造),进而再开始Football类自己的定义初始化,最后再回到自己的构造器做剩下的事情。
  5. 关于构造器额外补充一点,Sport类有一个有参的构造器,那无参的构造器就没有了,当有第三个类想要继承Sport时,自动生成的构造器会有super()这一段,提示异常,因为其默认要走父类的无参构造器,解决方法就是在Sport类中增加无参的构造器。

继承虽然作为Java的基本特性之一,但需要慎重使用。不正确的使用继承容易造成逻辑混乱,难以理解和维护。一般来说,当两者是从属关系(比如猫和动物的关系)就可以用继承,而像电脑与显示器的关系,就不适合使用继承关系

多态

多态是最重要的表现特征,算得上是一个综合应用。
首先说说多态的必要条件:

  1. 存在继承关系
  2. 子类重写父类的方法
  3. 父类的引用指向子类对象

用更容易的代码来理解一下:

public class Sport {
    // 名称
    private String name;

    public Sport(String name) {
        this.name = name;
    }

    public void print(){
        System.out.println("Sport");
    }
}
public class Football extends Sport {

    // 规则说明
    private String rule;

    public Football(String name, String rule) {
        super(name);// 调用父类构造器
        this.rule = rule;
    }

    @Override
    public void print(){
        System.out.println("我是足球");
    }
}
public class Test {
    public static void main(String[] args) {
        Sport sport = new Football("football","rule"); // 向上造型
        sport.print();
    }
}

输出结果:我是足球

Football类继承了Sport类,在main方法中,首先完成了一个向上造型。所谓造型,就是一个类型的对象赋值给另外一个类型的变量。这个时候sport变量所管理的是Football类中的东西。在Football类中重写了print方法,那么此时调用sport.print()执行的就是Football类中重写的方法。
Java的对象变量都是多态的,有两种表现形式,一种叫声明式类型(静态类型),一种是动态类型。声明式类型就是直观看的到的类型,main方法中定义的sport变量,其声明式类型就是Sport,而其动态类型是Football。
这里明确一下:Java是不存在对象给对象的赋值,而是让两个对象的管理者管理同一个对象。
子类的对象可以赋值给父类的变量,但是反过来,父类的对象赋值给子类的对象是不成立的。要想实现,可以利用造型,但前提是sport实际管理的是Football类型才行。如图所示:
在这里插入图片描述

还有一种多态的表现形式是接口的实现。接口相当于一个对外提供一系列的规范化方法的控制者,它没有具体的实现,而多态的表现就在于接口的实现。在不同的场景下实现接口,就可以满足不同的需要。下面给出一个简单的例子:

public interface SportDao {
    // 获取一项运动
    public void getSport();
}
public class FootballDaoImpl implements SportDao {
    @Override
    public void getSport() {
        System.out.println("我是足球");
    }
}
public class BasketballDaoImpl implements SportDao {
    @Override
    public void getSport() {
        System.out.println("我是篮球");
    }
}

在不同的实现类中对接口里定义的方法进行重写,以完成不同的业务需要。

第三种形式就是继承抽象类,重写里面的抽象方法。抽象类或抽象方法的关键字是abstract。抽象类归根结底还是一个类,而他对于普通类来说特殊的地方只在于它不能实例化对象,而因此,他必须被继承才能使用。抽象类常常和接口拿来比较,这里给出一些总结:

  1. 一个类只能继承一个抽象类,但可以实现多个接口。
  2. 接口中的方法都是隐式抽象的,无方法体,不需要声明abstract关键字;而抽象类中的方法可以有方法体。
  3. 接口中不能含有静态代码块以及静态方法,而抽象类可以有。
  4. 接口中没有构造方法,而抽象类中可以有。
  5. 接口中新加入方法,java8之前实现该接口的类都需要实现新方法(java8中允许使用default方法来克服这个问题),而抽象类里新加方法,可以给一个默认实现。
  6. 接口中的成员变量只能是 public static final 类型的,接口中的类可使用的修饰符只有public,也可以是无修饰符的;而抽象类中的成员变量可以是各种类型的,抽象类中的方法也可以是各种类型的。

通过抽象类实现的多态表现在对抽象方法的重写上,代码示例如下:

public abstract class Sport {
    private String a;

    public void getSport(){
        System.out.println("获取运动");
    }

    public abstract void print();
}
public class FootballService extends Sport {
    @Override
    public void print() {
        System.out.println("我是足球");
    }
}
public class BasketballService extends Sport {
    @Override
    public void print() {
        System.out.println("我是篮球");
    }
}

以上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值