java三大特性:封装,继承与多态

温柔狠角色 温柔狠角色     2023-03-03     274

关键词:

(尊重劳动成果,转载请注明出处:https://blog.csdn.net/qq_25827845/article/details/84592274冷血之心的博客)

目录

(一)封装

封装的定义

封装的好处

(二)继承

继承的概念

子类的特点

构造函数

覆盖/重写的概念

(三)多态

多态的概念

向上转型

向下转型

总结

结束语


        面向对象的语言有三大特性,即封装继承与多态。三大特性是面向对象编程的核心,对于初学者务必加强对三大特性的理解与领会。在这篇博客中,我们通过具体的案例来依次阐述封装继承与多态的概念与使用。

 

(一)封装

封装的定义

何为封装?

        把事物抽象成一个类,将事物拥有的属性和动作隐藏起来,只保留特定的方法与外界联系。当内部的逻辑发生变化时,外部调用不用因此而修改,它们只调用开放的接口,而不用去关心内部的实现。

封装的好处

  • 实现了专业的分工,将处理逻辑封装成一个方法,做到见名知其义
  • 良好的封装能够减少耦合
  • 隐藏信息,实现细节

接下来我们举两个封装的具体案例来进行阐述。

案例一:

package com.pak1;

public class Test 
    public static void main(String[] args) 
        Student student = new Student();
        student.name = "小明";
        student.age = 16;
        student.printStudentAge();

        Student student2 = new Student();
        student2.name = "小白";
        student2.age = 120;
        student2.printStudentAge();

    


class Student 
    String name;
    int age;

    public void printStudentAge() 
        System.out.println(name + "同学的年龄:" + age);
    

输出如下:

这个时候我们可以看到输出的小白同学的年龄120明显不科学,所以我们需要做一些内部逻辑的处理。所以需要进行代码封装,将内部逻辑进行一个隐藏。

封装之后的代码如下:

package com.pak1;

public class Test 
    public static void main(String[] args) 
        Student student = new Student();
        student.setName("小明");
        student.setAge(16);
        student.printStudentAge();

        Student student2 = new Student();
        student.setName("小白");
        student.setAge(120);
        student2.printStudentAge();

    


class Student 
    private String name;
    private int age;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        if (age < 0 || age > 60)
            throw new RuntimeException("年龄设置不合法");
        this.age = age;
    

    public void printStudentAge() 
        System.out.println(name + "同学的年龄:" + age);
    

输出结果如下:

我们将Student这个类的name和age私有化,提供了公共的get/set方法才能进行访问,在get/set方法中我们可以对内部逻辑进行封装处理,外部的调用方不必关心我们的处理逻辑。

        我们再来看另一种封装,在一个方法中,太多的逻辑将会导致该方法违反了单一性,导致该方法的可读性变差,这个时候我们需要将可以拆成一块的方法进行拆分,建立相应的service或者utils来封装该方法。举例如下:

案例二:

package com.pak1;

public class TestFZ 
    public static void main(String[] args) 
        int score = 78;
        if (score > 100 || score < 0) 
            System.out.print("对不起,你的分数输入有错误");
         else if (score > 89) 
            System.out.print("奖励你一台手机");
         else if (score > 79) 
            System.out.print("奖励你一副耳机");
         else if (score > 59) 
            System.out.print("奖励你一朵小红花");
         else if (score > 59) 
            System.out.print("奖励你一朵小红花");
        else 
            System.out.print("奖励你一个耳光");
        


    

好了,这部分的处理逻辑很复杂,看起来可读性也很差,这个时候我们需要封装。封装之后的代码如下:

package com.pak1;

public class TestFZ 
    public static void main(String[] args) 
        int score = 78;
        TestFZ testFZ = new TestFZ();
        testFZ.printReward(score);
    

    public void printReward(int score) 
        if (score > 100 || score < 0) 
            System.out.print("对不起,你的分数输入有错误");
         else if (score > 89) 
            System.out.print("奖励你一台手机");
         else if (score > 79) 
            System.out.print("奖励你一副耳机");
         else if (score > 59) 
            System.out.print("奖励你一朵小红花");
         else if (score > 59) 
            System.out.print("奖励你一朵小红花");
         else 
            System.out.print("奖励你一个耳光");
        
    

这样我们便把处理各个分数段奖励的逻辑进行了封装,增强了可读性,并且外部接口不需要了解内部如何实现。

(二)继承

继承的概念

       继承是面向对象的最显著的一个特征。继承是从已有的类(父类或者超类)中派生出新的类(子类),新的类能吸收已有类的数据属性和行为,并能扩展新的能力(方法的覆盖/重写)。JAVA不支持多继承,一个类只能有一个父类。父类是子类的一般化,子类是父类的特殊化(具体化)

子类的特点

  • 子类拥有父类非private的属性和方法
  • 子类可以添加自己的方法和属性,即对父类进行扩展
  • 子类可以重新定义父类的方法,即方法的覆盖/重写

构造函数

  • 构造函数不能被继承,子类可以通过super()显示调用父类的构造函数
  • 创建子类时,编译器会自动调用父类的无参构造函数
  • 如果父类没有定义无参构造函数,子类必须在构造函数的第一行代码使用super()显示调用

由于后边要阐述多态,这里我们先来介绍一个重要的概念,即方法的覆盖/重写

覆盖/重写的概念

        当子类需要修改父类的一些方法进行扩展,增大功能,程序设计者常常把这样的一种操作方法称为重写,也叫称为覆盖。

可以这么理解:重写就是指子类中的方法与父类中继承的方法有完全相同的返回值类型、方法名、参数个数以及参数类型。这样,就可以实现对父类方法的覆盖。如果子类将父类中的方法重写了,而我们想调用父类中的同名方法怎么办?此时,通过使用super关键就可以实现这个功能,super关键字可以从子类访问父类中的内容,如果要访问被重写过的方法,使用“super.方法名(参数列表)”的形式调用。

下边我们给出一个案例,子类扩展了父类的行为,并且重写了父类中的方法。代码如下:

package com.pak1;

public class Animal 
    private String name;
    private int age;

    public void setName(String name) 
        this.name = name;
    

    public void setAge(int age) 
        this.age = age;
    

    public String getName() 
        return this.name;
    

    public int getAge() 
        return this.age;
    

    @Override
    public String toString() 
        return "" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '';
    


class Dog extends Animal 
    // 对父类中方法的一种重写
    public String getName() 
        return super.getName() + "Dog";
    

    // 狗叫和狗吃饭都是在扩展父类中的行为
    public void voice() 
        System.out.println(super.getName() + " 汪");
    

    public void eat() 
        System.out.println(super.getName() + "吃东西");
    


class Main 
    public static void main(String[] args) 
        Dog dog = new Dog();
        dog.setName("大狗");
        dog.setAge(3);
        System.out.println(dog.toString());

        dog.eat();
        dog.voice();
        System.out.println(dog.getName()); //执行的是Dog中的getName方法
    

(三)多态

多态的概念

多态的本质是:一个程序中同名的不同方法。在面向对象的程序设计中,多态主要有以下三种方式来实现。

  • 通过子类对父类方法的覆盖来实现多态
  • 通过一个类中方法的重载来实现多态
  • 通过将子类的对象作为父类的对象实现多态。

覆盖的概念我们在前面以及介绍了,接下来我们简单阐述下何为重载

  • 重载是指一个类里面(包括父类的方法)存在方法名相同,但是参数不一样的方法,参数不一样可以是不同的参数个数、类型或顺序
  • 如果仅仅是修饰符、返回值、throw的异常 不同,那么这是2个相同的方法

我们重点阐述第三种实现方法,即通过将子类的对象作为父类的对象实现多态

把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。(这句话是我理解第三种方法的关键,请仔细阅读理解)

         继承是面向对象语言中一个代码复用的机制,简单说就是子类继承了父类中的非私有属性和可以继承的方法,然后子类可以继续扩展自己的属性及方法。

         对象的引用型变量是具有多态性的,因为一个引用型变量可以指向不同形式的对象,即:子类对象作为父类对象来使用。在这里涉及到了向上转型和向下转型。

向上转型

        子类对象转为父类,父类可以是接口。公式:Father f = new Son(); Father是父类或接口,Son是子类。

向下转型

        父类对象转为子类。公式:Son s = (Son) f;

在向上转型的时候我们可以直接转,但是在向下转型的时候我们必须强制类型转换。并且,如案例中所述,该父类必须实际指向了一个子类对象才可强制类型向下转型。若Father f = new Father()那么不可以转换,运行会报错。

对于多态,我们先举一个例子。在一个单位中,有职工employee,职工中又有少数是管理者manager,管理者中又有一部分是领导。若小明是管理者manager类的对象,他也可以被看做是employee的对象,即他也可以被看做是一个职工,他同时具备着职工的所有属性。

public class testDuoTai 
 
	public static void main(String[] args) 
		Employee emp1=new Employee("小明",23, 1000);   //emp1是Employee的对象
        System.out.println(emp1.getInfo());
        
        Employee emp2=new Manager("小明",23, 1000,5000); //注意此处emp2是Manager类的对象
        System.out.println(emp2.getInfo());
	
 

//定义一个父类
class Employee

	String name;
	int age;
	float salary;
	
	Employee();
	
	Employee(String name,int age,float sal)
	
		this.name=name;
		this.age=age;
		this.salary=sal;				
	
	String getInfo()
	
		return "职工姓名:"+name+"年龄:"+age+"工资:"+salary;
	

//定义一个子类
class Manager extends Employee

	float allowance;
	Manager(String name,int age,float sal,float aa)
	
		this.name=name;
		this.age=age;
		this.salary=sal;
		allowance=aa;
	

输出结果如下:

接下来我们再来看一个经典的多态讲解案例,代码如下:

package com.pak2;

class A 
    public String show(D d) 
        return ("A and D");
    
    public String show(A a) 
        return ("A and A");
    


class B extends A 
    public String show(B b) 
        return ("B and B");
    
    public String show(A a) 
        return ("B and A");
    

class C extends B 
class D extends B 

public class Test 
    public static void main(String[] args) 
        A a1 = new A();
        A a2 = new B();

        B b = new B();
        C c = new C();
        D d = new D();

        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("--------------");
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("--------------");
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));
    

这段代码的输出是啥呢?大家可以先分析分析,然后再看正确答案。

好了,正确答案如下:

在分析结果之前,我们先来看相关的知识点概念:

  • 父类对象引用变量引用子类对象时,被引用对象的类型不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法

产生多态时候,各个方法调用的优先级顺序由高到低依次为:

this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)

我们来分析以下结果:

(1)System.out.println("1--" + a1.show(b));

       首先a1是一个标准的A对象的引用变量,传入的参数为标准的 new B(),我们在A类的方法中找不到show(B b)的方法,接着去看A的超类是否有show(B b)的方法,发现A没有超类。那么去执行this.show((super)O),即A类中的show(A a)方法,所以输出为A and A

(2)System.out.println("2--" + a1.show(c));

      同理,a1.show(c) C的父类是B,所以C也是A的子类,那么最后还是调用A类中的show(A a)方法,所以输出为A and A

(3)System.out.println("3--" + a1.show(d));

      这个没什么好疑惑的,直接就是调用A类中的show(D obj),所以输出为A and D

(4)System.out.println("4--" + a2.show(b));

      这个的结果输出就有点迷惑人了,小伙伴们会惊奇,为什么不是调用B类中的show(B b)方法输出B and B ?我们来解释下,a2是一个父类A的引用变量指向了一个子类B的对象,也就是说表面类型是A,实际类型是B。当我们调用方法的时候,首先从其表面类型里边寻找方法 show(B b)结果没有找到,那么按照调用优先级,我们最终会调用到this.show((super)O) 也就是说我们调用了A类中的show(A a)方法。按照上边所述的概念:当父类对象引用变量引用子类对象时,被引用对象的类型不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。在当前的表面类型中找到了该方法show(A a),并且在子类(B)中也覆盖了该方法,那么最终会调用实际类型(B类)中的该方法show(A a),所以输出B and A

(5)System.out.println("5--" + a2.show(c));

      这个分析和4中的保持一致

(6)System.out.println("6--" + a2.show(d));

     这个没什么疑问,在A类中找到了该方法show(D d),并且子类没有覆盖该方法,所以直接调用A类中的方法,输出A and D

(7)System.out.println("7--" + b.show(b));

       b.show(b)应该没什么疑问,会直接调用B类中的方法show(B b) 输出 B and B

(8)System.out.println("8--" + b.show(c));

     根据方法调用优先级,最终会调用到B类中的方法show(B b) 输出 B and B

(9)System.out.println("9--" + b.show(d));

     根据方法调用优先级,最终会调用到A类中的方法show(D d) 输出 A and D

      这是多态学习中的一个经典案例,我们要牢记方法之间的调用优先级,并且要分清楚表面类型和实际类型,以及区分子类中是否进行了方法的覆盖等知识点,这样才能做到条理清晰。

总结

        在这篇博客中,我们依次介绍了面向对象的三大特性,即封装继承与多态。针对多态,我们又详细分析了经典的案例,帮助大家学习理解,接下来我会将这篇文章录制成CSDN学院的免费课程(视频教学),CSDN学院搜索 “杨文强” 关注我的课程。

结束语

        如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群824733818一起交流学习。本群给大家提供一个学习交流的平台,欢迎各位真正喜欢提问喜欢分享知识的小伙伴进来交流技术。
 

java三大特性封装继承多态

封装:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类... 查看详情

二面向对象三大特性

一继承与派生  一、继承定义  二、继承与抽象的关系  三、继承与重用性  四、派生  五、组合与重用性  六、接口与归一化设计  七、抽象类  八、继承实现的原理  九、子类中调用父类的方法二多态与... 查看详情

java的三大特性:封装继承多态

一、类的概念:类一般包括两个部分:属性(成员变量)和方法(成员方法)方法组成部分:修饰符(可选)返回值类型(必须)方法名(必须)参数列表(可选)packagecom.classTest.project;publicclassClassTest{//成员变量Stringname;intage;//成员... 查看详情

java三大特性性:封装继承和多态

一、封装  封装是指隐藏对象的属性及实现细节,对外仅提供接口可见。封装实现了信息隐藏,利于软件复用。其优点是达到了模块化的标准,从而提高了代码的复用程度。在某种程度上,封装也大大改善了软件开发的可维护... 查看详情

转oc温故:类的三大特性(封装,继承,多态)

原文标题:OC学习篇之---类的三大特性(封装,继承,多态)我们都知道,面向对象程序设计中的类有三大特性:继承,封装,多态,这个也是介绍类的时候,必须提到的话题,那么今天就来看一下OC中类的三大特性:一、封装封装... 查看详情

三大特性:封装,继承,多态

透切理解面向对象三大基本特性是理解面向对象五大基本原则的基础.三大特性是:封装,继承,多态所谓封装: 也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信... 查看详情

java三大特性之---多态

面向对象编程有三大特性:封装、继承、多态。封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而言它的内部细节是隐藏的,暴露给外界的只是它的访问方法。继承是为... 查看详情

继承封装多态

...识到什么是类,什么是对象了。接下来要看的就是java的三大特征:继承、封装、多态。一、封装(数据的隐藏)在定义一个对象的特性的时候,有必要决定这些特性的可见性,即哪些特性对外部是可见的,哪些特性用于表示内... 查看详情

面向对象的三大特性(封装继承多态)-----继承

继承有几点应该注意的是:继承要在子类加上父类的类名子类和父类都有的方法,优先找子类的方法python里面可以继承多个类C#,java不可以多继承如果继承多个类,继承顺序为从左至右 Python3里面的继承可以多继承,通过继承... 查看详情

面向对象编程的三大特性:继承多态封装

九子类中调用父类的方法方法一:指名道姓,即父类名.父类方法() ViewCode方法二:super() ViewCode 强调:二者使用哪一种都可以,但最好不要混合使用  了解部分:即使没有直接继承关系,super仍然会按照mro继续... 查看详情

理解java的三大特性之多态

面向对象编程有三大特性:封装、继承、多态。     封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它... 查看详情

java面试题详解一:面向对象三大特性(代码片段)

一,多态:1.面向对象四大基本特性:抽象,封装,继承,多态抽象,封装,继承是多态的基础。多态是抽象,封装,继承的表现。2.什么是多态不同类的对象对同一消息作出不同的响应叫做多态3.多态的作用简单来说:解藕。详... 查看详情

类的三大特性(继承,封装,多态)

类的三大特性之继承classAnimals:a_type="哺乳动物"def__init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexdefeat(self):print("%siseating...."%self.name)classPerson(Animals):a_type="高级动物"deftalk(self):pr 查看详情

面向对象的三大特性---封装继承多态

 面向对象的三大特性---封装继承多态首先我们来创建一个控制台程序 新建一个父类Person创建一个子类继承父类Person子类:main函数:输出结果:根据结果显示创建子对象,首先调用父类的构造函数在调用子类的构造函数... 查看详情

面向对象三大特性---封装继承多态

我要走上我的写博之路,随便写写。有不对的地方欢迎提出。好了,我就不多说什么了,干正经事。。。哈哈一、封装(类的封装)创建一个类(构造函数、属性和方法组成)---汽车classCar{type:string; constructor(type:string){ thi... 查看详情

java提高篇之理解java的三大特性——多态

面向对象编程有三大特性:封装、继承、多态。封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。继承是为... 查看详情

java面向对象的三大特性

一封装:1类:封装的是对象的属性和行为2方法:封装的是一段具体的业务逻辑实现3访问控制符:封装的是具体的访问权限2继承:1作用:代码的复用2超类拥有所有派生类所共有的属性和行为,接口拥有部分派生类所共有的行为... 查看详情

面向对象三大特性:继承封装多态(代码片段)

继承:即子类可以继承父类的除了所有属性、方法外的所有内容。子类继承父类,只需要在类名后面加上(父类名)即可。如下定义一个父类,AnimalsclassAnimals:pass再定义一个子类cat,继承父类Animalsclasscat(Animals):pass这样cat类即可继... 查看详情