面向对象编程三大特征

发布于:2023-01-26 ⋅ 阅读:(19) ⋅ 点赞:(0) ⋅ 评论:(0)

面向对象编程三大特征

1. 封装

1.1 封装介绍

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

1.2 封装的理解和好处

隐藏实现细节:方法(链接数据库)<–调用(传入参数…)

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

1.3 封装的实现步骤

  1. 将属性进行私有化private(不能直接修改属性)
  2. 提供一个公共的(public)set方法,用于对属性判断并赋值。
  3. 提供一个公共的(public)get方法,用于获取属性的值。

在这里插入图片描述

1.4 案例演示

实现员工类,不能随便查看人的年龄,工资等隐私,并对其年龄进行合理的验证,年龄合理就设置,否则给默认年龄30岁,年龄要求必须在20~50岁之间。

public class Employee {
    private String name;
    private int age;
    private int salary;

    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>=20&&age<=50){
            this.age = age;
        }else {
            this.age = 20;
        }
        
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public Employee(String name, int age, int salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
}

2. 继承

2.1 为什么需要继承

一个小问题,我们需要编写两个类,一个是小学生(Pupil),一个是学生(Student),两个类的属性和方法中有许多是相同的,我们是否可以将他们的共同点利用起来–> 继承(代码复用性)

2.2 继承基本介绍和示意图

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

在这里插入图片描述

2.3 继承的基本语法

class 子类e ntends 父类{
}

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

父类又叫基类,超类。

子类又叫派生类。

2.4 继承给编程带来的便利

  1. 代码复用性大大提高
  2. 代码的拓展性和维护性提高了

2.5 继承相关细节问题

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
  2. 子类必须调用父类的构造器, 完成父类的初始化 。
  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
  4. 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表) 。
  5. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)。
  6. super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  7. Java 所有类都是 Object 类的子类, Object 是所有类的基类.。
  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)。
  9. 子类最多只能继承一个父类(指直接继承),即 Java 中是单继承机制。

这里关于第3点我们详细介绍

public class A {
    private String name;
    private int age;

    public A() {
        System.out.println("父类无参构造器被调用");
    }

    public A(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("父类有参构造器被调用");
    }

    public void test(){
        System.out.println("我是父类的test方法");
    }
}
public class B extends A{
    private String name;
    private int age;
    private int salary;

    public B() {
        super();
        System.out.println("子类无参构造器调用");
    }
    public B(String name, int age, int salary) {
        super(name, age);
        System.out.println("子类有参构造器调用");
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
}
 public static void main(String[] args) {
        B b = new B();
        B b1 = new B("小白", 11, 8000);
    }

在这里插入图片描述

2.6 继承的内存布局

在这里插入图片描述

3. 多态

3.1 为什么需要多态

请编写一个Master类,喂养Cat和Dog,对于不同的Cat和Dog要喂不同的食物

对于这种问题,多态的重要性就得到了极好的体现,如果不使用多态,代码无疑会及其冗长。下面,我们详细讲解

3.2 多态基本介绍

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

3.2 多态的具体体现

  1. 方法的多态

重写和重载就体现多态 [案例说明]

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; 
    }
  1. 对象的多态

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

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

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

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

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(); //小猫喵喵叫 
    } 
}

3.3 多态快速入门案例

public class Food {
    private String name;

    public String getName() {
        return name;
    }

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

    public Food(String name) {
        this.name = name;
    }
}
class Bone extends Food{
    private String name;

    Bone(String name) {
        super(name);
        this.name = name;
    }
}
class Fish extends Food{
    private String name;

    Fish(String name) {
        super(name);
        this.name = name;
    }
}
public class Animal {
    private String name;

    public String getName() {
        return name;
    }

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

    public Animal(String name) {
        this.name = name;
    }
}
public class Dog extends Animal{
    public Dog(String name) {
        super(name);
    }
}
public class Cat extends Animal{

    public Cat(String name) {
        super(name);
    }
}
public class Master {
    private String name;

    public String getName() {
        return name;
    }

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

    public Master(String name) {
        this.name = name;
    }
	//使用多态机制,可以统一的管理主人喂食的问题 
    //animal 编译类型是 Animal,可以指向(接收) Animal 子类的对象 
    //food 编译类型是 Food ,可以指向(接收) Food 子类的对象
    public void feed(Animal animal, Food food) {
        System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
    }
}

public static void main(String[] args) {
        Animal animal = new Cat("小白");
        Food food = new Fish("鱼")
        Master master = new Master("小明");
        master.feed(animal,food);
        animal = new Dog("小花");
        food = new Bone("骨头");
        master.feed(animal,food);  
    }

3.4 多态注意事项和细节

  1. 多态的前提是:两个类之间存在继承关系。
  2. 多态的向上转型:

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

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

特点:1. 编译类型看左边,运行类型看右边。
2.可以调用父类中的所有成员(需遵守访问权限);
​ 3.不能调用子类中的特有成员;
​ 4.最终运行结果看子类的具体实现。

  1. 多态向下转型:

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

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

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

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

3.5 Java动态绑定机制(非常重要)

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  2. 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
class A{
    public int i = 10;
    public int sum(){
        return getI()+10;
    }
    public int sum1(){
        return i+10;
    }
    public int getI(){
        return i;
    }
}
class B extends A{
    public int i = 20;
    public int sum(){
        return i+20;
    }
    public int sum1(){
        return i+10;
    }
    public int getI(){
        return i;
    }
}
//mian方法中
public static void main(String[] args) {
    //a 的编译类型 A, 运行类型 B
    A a = new B();//向上转型
    System.out.println(a.sum());//40
    System.out.println(a.sum1());//30
}

如果把子类B中的sum方法注释掉,那么执行a.sum()时就会根据继承找父类的sum方法,父类的sum方法中存在getI()这一方法,这时,Java的动态绑定机制便体现出了,当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定*,因此运行类型是B,会获取B类中的i值,也就是20,然后返回给父类中的sum方法,答案是30;

如果把子类B中的sum1方法注释掉,那么和之前一样会去找父类的sum1方法,但这时,父类的sum1方法是直接返回i+10的值,此时这个i,根据当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用,就是父类中的i,也就是值为10,因此此时返回值为20;


网站公告

欢迎关注微信公众号

今日签到

点亮在社区的每一天
签到