封装、继承、多态

本文详细介绍了Java中的封装、继承和多态。封装是将数据和操作数据的方法绑定在一起,保护数据的安全;继承允许子类继承父类的属性和方法,提高代码复用性;多态则是对象多种形态的表现,包括方法的多态和对象的多态,增强了代码的灵活性。文章通过实例展示了这三大特性的应用和规则,以及它们在实际编程中的重要性。
摘要由CSDN通过智能技术生成

封装

封装介绍

封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作。

封装的理解和好处

1)隐藏实现细节:方法(连接数据库)<一调用(传入参数..)

2)可以对数据进行验证,保证安全合理

封装的实现步骤(三步走)

1)将属性进行私有化private 【不能直接修改属性】

2)提供一个公共的(public)set方法,用于对属性判断并赋值

   

public void setXxx(类型 参数名){//Xxx 表示某个属性
             //加入数据验证的业务逻辑
             属性 = 参数名;
    }

3)提供一个公共的(public)get方法,用于获取属性的值

public 数据类型 getXxx(){//权限判断,Xxx 表示某个属性
             return xx;
    }

实例

/**
 * 创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
 * Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、
 * 密码(必须是六位), 如果不满足,则给出提示信息,并给默认值(程序员自己定)
 * 通过setXxx的方法给Account 的属性赋值。
 * 在AccountTest中测试
 */
public class Account {
    //为了封装,将3个属性设置为private
    private String name;
    private double balance;
    private String pwd;

    //提供两个构造器
    public Account() {
    }

    public Account(String name, double balance, String pwd) {
        this.setName(name);
        this.setBalance(balance);
        this.setPwd(pwd);
    }

    public String getName() {
        return name;
    }

    //姓名(长度为2位3位或4位)
    public void setName(String name) {
        if (name.length() >= 2 && name.length() <= 4) {
            this.name = name;
        } else {
            System.out.println("姓名要求(长度为2位3位或4位),默认值 无名");
            this.name = "无名";
        }
    }

    public double getBalance() {
        return balance;
    }

    //余额(必须>20)
    public void setBalance(double balance) {
        if (balance > 20) {
            this.balance = balance;
        } else {
            System.out.println("余额(必须>20) 默认为0");
        }
    }

    public String getPwd() {
        return pwd;
    }

    //密码(必须是六位)
    public void setPwd(String pwd) {
        if (pwd.length() == 6) {
            this.pwd = pwd;
        } else {
            System.out.println("密码(必须是六位)默认密码为 000000");
            this.pwd = "000000";
        }
    }
    //显示账号信息
    public void showInfo() {
        //可以增加权限的校验
        System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码" + pwd);
//        if() {
//            System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码");
//        }else{
//            System.out.println("你无权查看...");
//        }
    }
}

继承

继承的基本介绍和示意图

Java中的继承是一个对象获取父对象的所有属性和行为的机制。继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends 来声明继承父类即可。

继承的基本语法

class 子类 extends 父类 {

}

1)子类就会自动拥有父类定义的属性和方法

2)父类又叫 超类,基类

3)子类又叫派生类

public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();//内存的布局
        //?-> 这时请大家注意,要按照查找关系来返回信息
        //(1) 首先看子类是否有该属性
        //(2) 如果子类有这个属性,并且可以访问,则返回信息
        //(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
        //(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
        System.out.println(son.name);//返回就是大头儿子
        //System.out.println(son.age);//返回的就是39
        //System.out.println(son.getAge());//返回的就是39
        System.out.println(son.hobby);//返回的就是旅游
    }
}

class GrandPa { //爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}

class Father extends GrandPa {//父类
    String name = "大头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

class Son extends Father { //子类
    String name = "大头儿子";
}

继承给编程带来的便利

1)代码的复用性提高了

2)代码的扩展性和维护性提高了

继承的深入讨论/细节问题

 1) 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问

2) 子类必须调用父类的构造器, 完成父类的初始化

3) 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过

4) 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)

5) super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)

6) super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

7) java 所有类都是 Object 类的子类, Object 是所有类的基类.

8) 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)

9) 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。 思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】

10) 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系

public class ExtendsDetail {
public static void main(String[] args) {
// System.out.println("===第 1 个对象====");
// Sub sub = new Sub(); //创建了子类对象 sub
// System.out.println("===第 2 个对象====");
// Sub sub2 = new Sub("jack"); //创建了子类对象 sub2
System.out.println("===第 3 对象====");
Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
//sub.sayOk();
    }
}

多态

多[多种]态[状态]基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

多态的具体体现

1) 方法的多态 PloyMethod.java

重写和重载就体现多态

public class PloyMethod {
    public static void main(String[] args) {
        //方法重载体现多态
        A a = new A();
        //这里我们传入不同的参数,就会调用不同sum方法,就体现多态
        System.out.println(a.sum(10, 20));
        System.out.println(a.sum(10, 20, 30));

        //方法重写体现多态
        B b = new B();
        a.say();
        b.say();

    }
}
class B { //父类
    public void say() {
        System.out.println("B say() 方法被调用...");
    }
}
class A extends B {//子类
    public int sum(int n1, int n2){//和下面sum 构成重载
        return n1 + n2;
    }
    public int sum(int n1, int n2, int n3){
        return n1 + n2 + n3;
    }


    public void say() {
        System.out.println("A say() 方法被调用...");
    }
}

2) 对象的多态

1.一个对象的编译类型和运行类型可以不一致

2.编译类型在定义对象时,就确定了,不能改变

3.运行类型是可以变化的

4.编译类型看定义时 = 号 的左边,运行类型看 = 号的右边

Animal animal = new Dog();【animal 编译类型是Animal,运行类型Dog】

animal = new Cat(); 【animal的运行类型变成了Cat,编译类型仍然是Animal】

public class Animal {
    public void cry() {
        System.out.println("Animal cry() 动物在叫....");
    }
}

public class Cat extends Animal {
    public void cry() {
        System.out.println("Cat cry() 小猫喵喵叫...");
    }
}

public class Dog extends Animal {
    public void cry() {
        System.out.println("Dog cry() 小狗汪汪叫...");
    }
}

public class PolyObject {
    public static void main(String[] args) {
    //体验对象多态特点
    //animal 编译类型就是 Animal , 运行类型 Dog
    Animal animal = new Dog();

    //因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry 就是 Dog 的 cry
    animal.cry(); //小狗汪汪叫

    //animal 编译类型 Animal,运行类型就是 Cat
    animal = new Cat();
    animal.cry(); //小猫喵喵叫
  }
}

 多态注意事项和细节讨论

多态的前提是:两个对象(类)存在继承关系

多态的向上转型

1.本质:父类的引用指向了子类的对象

2.语法:父类类型   引用名 = new 子类类型();

3.特点:编译类型看左边,运行类型看右边。

可以调用父类中的所有成员(需遵守访问权限)

不能调用子类中特有成员;

最终运行效果看子类的具体实现!

多态的向下转型

1)语法:子类类型    引用名 = (子类类型) 父类引用

2)只能强转父类的引用,不能强转父类的对象

3)要求父类的引用必须指向的是当前目标类型的对象

4)当向下转型后,可以调用子类类型中所有的成员

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

        //向上转型: 父类的引用指向了子类的对象
        //语法:父类类型引用名 = new 子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类

        //向上转型调用方法的规则如下:
        //(1)可以调用父类中的所有成员(需遵守访问权限)
        //(2)但是不能调用子类的特有的成员
        //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
        //animal.catchMouse();错误
        //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
        //,然后调用,规则我前面我们讲的方法调用规则一致。
        animal.eat();//猫吃鱼..
        animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡

        //可以调用Cat的 catchMouse方法
        //多态的向下转型
        //(1)语法:子类类型 引用名 =(子类类型)父类引用;
        //问一个问题? cat 的编译类型 Cat,运行类型是 Cat
        Cat cat = (Cat) animal;
        cat.catchMouse();//猫抓老鼠
        //(2)要求父类的引用必须指向的是当前目标类型的对象
        Dog dog = (Dog) animal; //可以吗?

        System.out.println("ok~~");
    }
}

java 的动态绑定机制

public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());//?40 -> 30
        System.out.println(a.sum1());//?30-> 20
    }
}

class A {//父类
    public int i = 10;
    //动态绑定机制:

    public int sum() {//父类sum()
        return getI() + 10;//20 + 10
    }

    public int sum1() {//父类sum1()
        return i + 10;//10 + 10
    }

    public int getI() {//父类getI
        return i;
    }
}

class B extends A {//子类
    public int i = 20;

//    public int sum() {
//        return i + 20;
//    }

    public int getI() {//子类getI()
        return i;
    }

//    public int sum1() {
//        return i + 10;
//    }
}

多态的应用

多态参数

方法定义的形参类型为父类类型,实参类型允许为子类类型

public class PloyParameter {
    public static void main(String[] args) {
        Worker tom = new Worker("tom", 2500);
        Manager milan = new Manager("milan", 5000, 200000);
        PloyParameter ployParameter = new PloyParameter();
        ployParameter.showEmpAnnual(tom);
        ployParameter.showEmpAnnual(milan);

        ployParameter.testWork(tom);
        ployParameter.testWork(milan);

    }

    //showEmpAnnual(Employee e)
    //实现获取任何员工对象的年工资,并在main方法中调用该方法 [e.getAnnual()]
    public void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());//动态绑定机制.
    }
    //添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法
    public void testWork(Employee e) {
        if(e instanceof  Worker) {
            ((Worker) e).work();//有向下转型操作
        } else if(e instanceof Manager) {
            ((Manager) e).manage();//有向下转型操作
        } else {
            System.out.println("不做处理...");
        }
    }
}

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

public class PloyArray {
    public static void main(String[] args) {
        //应用实例:现有一个继承结构如下:要求创建1个Person对象、
        // 2个Student 对象和2个Teacher对象, 统一放在数组中,并调用每个对象say方法

        Person[] persons = new Person[5];
        persons[0] = new Person("jack", 20);
        persons[1] = new Student("mary", 18, 100);
        persons[2] = new Student("smith", 19, 30.1);
        persons[3] = new Teacher("scott", 30, 20000);
        persons[4] = new Teacher("king", 50, 25000);

        //循环遍历多态数组,调用say
        for (int i = 0; i < persons.length; i++) {
            //老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有JVM来判断
            System.out.println(persons[i].say());//动态绑定机制
            //这里大家聪明. 使用 类型判断 + 向下转型.
            if(persons[i]  instanceof  Student) {//判断person[i] 的运行类型是不是Student
                Student student = (Student)persons[i];//向下转型
                student.study();
                //小伙伴也可以使用一条语句 ((Student)persons[i]).study();
            } else if(persons[i] instanceof  Teacher) {
                Teacher teacher = (Teacher)persons[i];
                teacher.teach();
            } else if(persons[i] instanceof  Person){
                //System.out.println("你的类型有误, 请自己检查...");
            } else {
                System.out.println("你的类型有误, 请自己检查...");
            }

        }

    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
封装继承多态是面向对象编程中的三个重要概念。 封装是指将数据和对数据的操作封装在一个中,通过访问修饰符来控制对数据的访问权限。这样可以隐藏内部实现细节,提高代码的安全和可维护。\[2\] 继承是指一个可以继承另一个的属和方法。通过继承,子可以重用父的代码,并且可以在子中添加新的属和方法。这样可以提高代码的复用和可扩展。\[2\] 多态是指同一个方法在不同的对象上可以有不同的行为。通过多态,可以实现方法的重写和重载,使得程序可以根据对象的实际型来调用相应的方法。这样可以提高代码的灵活和可扩展。\[1\] 总结起来,封装继承多态是面向对象编程的三个基本特,它们可以使代码更加模块化、可维护和可扩展。 #### 引用[.reference_title] - *1* *2* [封装继承多态](https://blog.csdn.net/yahid/article/details/125665027)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C++ 封装继承多态](https://blog.csdn.net/secondtonone1/article/details/124485035)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值