面向对象--------三巨头

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ ა
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏:xiaoxie的Java系列专栏——CSDN博客●'ᴗ'σσணღ*
我的目标:"团团等我( ◡̀_◡́ ҂)" 

感谢您的阅读

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞 + 收藏⭐️ + 留言​+关注(互三必回)!

面向对象--------三巨头_第1张图片Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),面向对象是一种编程范式,它将程序的组织方式从过程化的思维方式转变为以对象为中心的思维方式。在面向对象编程中,程序被组织成一组相互协作的对象,每个对象都有自己的状态和行为,并且可以通过消息传递来进行交互。面向对象的编程语言提供了类和对象的概念,通过定义类来创建对象,并通过对象之间的交互来实现程序的功能,Java面向对象有三大巨头------封装继承多态 。下文博主将一一介绍它们的语法以及优点等等。

一.封装

1.什么是封装

封装是面向对象编程中的一个重要概念,指的是将抽象出来的数据和对数据的操作封装在一起,形成一个类(或对象),使其只能通过类(或对象)提供的接口来访问和操作数据,同时隐藏了数据的实现细节,从而达到保护数据的安全和完整性的目的。通过封装,程序员可以将复杂的系统简化并提高代码的可维护性和可扩展性。

2.为什么要封装

封装的目的是保护数据的安全和完整性,同时隐藏数据的实现细节,提高代码的可维护性和可扩展性,具体有以下几个方面的好处:

  1. 保护数据的安全和完整性:封装可以将数据隐藏起来,使得外部代码无法直接访问和修改数据,从而防止数据被意外修改或篡改,提高数据的安全性和可靠性。

  2. 隐藏实现细节:封装可以隐藏数据的实现细节,将复杂的实现逻辑封装到类的内部,对外部代码来说,只需要关心调用类的接口即可,不必关心类的内部实现,降低了代码的耦合度,提高了代码的可维护性和可读性。

  3. 提高代码的可维护性和可扩展性:封装可以将数据和操作进行分离,使得修改数据的实现细节并不会影响对外部接口的调用方式,从而提高了代码的可维护性和可扩展性,方便系统的后续维护和升级。

3.该如何实现封装

Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

访问限定符
NO 范围 private default(默认) protected public
1 同一个包中的同一类 ☑️ ☑️ ☑️ ☑️
2 同一个包中的不同类 ☑️ ☑️ ☑️
3 不同包中的子类 ☑️ ☑️
4 不同包中的非子类 ☑️

说明:访问限定符不仅可以限制成员属性的访问权限也可以限制类的访问权限;一般成员变量由private 所修饰 成员方法由 public所修饰;default :表示的是没有写访问限定符就默认为default所修饰

4.实例举例

public class Employee {
    private String name;   // 将属性进行封装
    private String department;   // 将属性进行封装
    private int age;   // 将属性进行封装
 
    public String getName() {
        return name;   // 只暴露出了获取属性的接口
    }
 
    public void setDepartment(String department) {
        this.department = department;   // 只暴露出了设置属性的接口
    }
 
    public void increaseAge() {
        age++;   // 只暴露出了对属性进行修改的接口
    }
}
 

在这个例子中,将员工的姓名、部门和年龄进行了封装,只在外部暴露了获取姓名和设置部门、增加年龄的接口,从而保护了属性的安全和完整性,同时隐藏了实现细节。

5.说明

当然以上举得例子只是封装一个小小的优点之一,等和继承与多态结合起来一起使用,你就会发现封装的妙用了

二.继承

1.什么是继承

继承是面向对象编程中的一个概念,它指的是一个类可以派生出新的类,新的类可以继承原来类的属性和方法,同时可以在原有基础上增加自己的属性和方法,从而达到代码复用的目的。继承可以通过子类来扩展或者修改父类的功能,提高代码的可维护性和可复用性。在继承关系中,被继承的类被称为父类或基类,继承的类被称为子类或派生类。

2.为什么要继承呢

首先让我们看一下下面的例子  

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name+"正在吃");
    }
}
class Dog {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name+"正在吃");
    }
    public void Bark() {
        System.out.println(this.name+"汪汪叫");
    }
}
class Bird {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name+"正在吃");
    }
    public void Bugu() {
        System.out.println(this.name+"布谷布谷叫");
    }
}

从以上代码可以看出我们设计出的了三个类,相信细心的读者们可以发现这三个类有很多共性的地方,代码有很多的重复使用了,而继承就是为了解决这个问题

3.继承的使用

面向对象--------三巨头_第2张图片上述图示中,Dog和Bird都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Bird可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。
从继承概念中可以看出继承最大的作用就是:实现代码复用,还有就是来实现多态

4.继承的语法

在Java中如果要表示类之间的继承关系,需要借助extends关键字,具体如下

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name+"正在吃");
    }
}
class Dog extends Animal {
    
    public void Bark() {
        System.out.println(this.name+"汪汪叫");
    }
}
class Bird extends Animal {
   
    public void Bugu() {
        System.out.println(this.name+"布谷布谷叫");
    }
}

5.继承中的一些注意事项

1.Java只能单继承,不可以实现多继承

2.成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。

3.子类要想访问父类中的成员属性可以使用关键字 super()来访问如下图

class Animal {
    public String name = "小黑";
    public int age;
    public void eat() {
        System.out.println(this.name+"正在吃");
    }
}
class Dog extends Animal {
    public String name = "旺财";
    public void Bark() {
        System.out.println(this.name+"汪汪叫");
    }
    public void func() {
        System.out.println(super.name);
    }

}
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.func();
    }
}

结果如下

面向对象--------三巨头_第3张图片4.父子父子,先有父再有子,即:子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name+"正在吃");
    }
}
class Dog extends Animal {

    public Dog(String name, int age, String sex) {
        super(name, age);
        this.sex = sex;
    }
    public String sex;
    public void Bark() {
        System.out.println(this.name+"汪汪叫");
    }
    public void func() {
        System.out.println(super.name);
    }

}

因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。

注意:
1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现

5. super和this

super和this是两个关键字,都是用来引用对象或类的,但是它们有不同的作用和用法。

this关键字用于在一个类的方法中引用该类的成员变量、方法或构造函数。通常用于区分成员变量和方法名相同的情况。例如:

public class Person{
    private String name;
    
    public Person(String name){
        this.name = name;
    }
    
    public String getName(){
        return this.name;
    }
}

在上述代码中,this.name引用了该类的成员变量name,而非方法中的参数name。

super关键字用于在子类中引用父类的成员变量、方法或构造函数。通常用于在子类中重写父类的方法时,调用父类的方法或调用父类的构造函数。例如:

public class Animal{
    protected String name;
    
    public Animal(String name){
        this.name = name;
    }
    
    public void eat(){
        System.out.println("Animal is eating.");
    }
}

public class Cat extends Animal{
    public Cat(String name){
        super(name);
    }
    
    @Override
    public void eat(){
        super.eat(); //调用父类的eat方法
        System.out.println("Cat is eating.");
    }
}

在上述代码中,super(name)调用了父类Animal的构造函数,而super.eat()调用了父类Animal的eat方法。

6.封装在继承中的使用

1.private 即只能在自己类中被访问,父类中private成员变量虽然在子类中不能直接访问,但是也继承到子类中了

2.default 即默认在同一个包内父类的default成员变量子类可以访问

3.protected 即在同一个包或者不同包的父类成员变量被protected修饰的子类可以访问

4.public 即都可以被访问

7.final的使用

在继承中,final关键字通常用于类、方法或属性上,用来表示其不能被子类继承或重写。

  1. 对于类,如果使用了final关键字修饰,则该类不能被其他类继承。

  2. 对于方法,如果使用了final关键字修饰,则该方法不能被子类重写。

  3. 对于属性,如果使用了final关键字修饰,则该属性不能在子类中被重新赋值。

使用final关键字有以下几个好处:

  1. 可以提高程序的安全性,避免子类对父类的重要方法或属性进行更改。

  2. 可以提高程序的性能,因为编译器可以对final修饰的方法或属性进行优化,减少运行时的开销。

  3. 可以使程序的设计更加灵活,因为final关键字可以限制子类的行为,从而保证代码的正确性和稳定性。 

8. 继承和组合

继承和组合是面向对象编程中常用的两种关系。它们的区别如下:

  1. 继承是一种“is-a”(是一个)的关系,即子类是父类的一种具体化,子类可以继承父类的属性和方法。而组合是一种“has-a”(拥有一个)的关系,即一个类拥有另一个类的对象作为自己的属性或成员。

  2. 继承是静态的关系,即子类在编译期已经确定了继承关系,而组合是动态的关系,即一个类可以在运行时动态地组合其他类的对象。

  3. 继承可以方便地实现代码的重用,减少了代码的冗余。但是过多的继承会导致类之间的耦合性增加,影响代码的灵活性。组合能够更灵活地组合各种对象,但是需要更多的代码来处理对象之间的关系。

  4. 继承可以直接访问父类的属性和方法,但是如果父类的实现发生改变,子类也需要相应地做出调整。组合需要通过调用对象的方法来访问其属性和方法,但是更容易适应变化。

三.多态

1.多态发生的前置条件

Java发生多态的条件包括:

  1. 继承:多态是通过父类和子类之间的继承关系实现的。

  2. 重写:子类必须重写父类的方法,才能实现多态。

  3. 向上转型:使用父类的引用指向子类的对象,从而实现多态。

  4. 运行时绑定:多态的方法调用在运行时进行绑定,而不是在编译时确定。这意味着程序在运行时才能确定调用的是哪个类的方法。

2.什么是向上转型呢

从上文中我们可以知道发生多态的条件之一就是发生向上转型,那什么是向上转移呢?

向上转型是指将一个子类对象转换为其父类对象的过程,即子类对象赋值给父类类型的变量。这种转型是安全的,因为子类对象具有父类对象所有的属性和方法,因此可以在父类类型的变量中使用。通常向上转型是多态性的基础之一。

举个例子,如果有一个动物类 Animal,和一个子类狗类 Dog,可以这样转型:

Animal animal = new Dog(); // 向上转型,将子类对象赋值给父类对象
//分解写就是
Dog dog = new Dog();
Animal animal = dog;

在这个例子中,Dog 对象 animal 实际上是一个 Animal 类型的变量,但是它仍然可以调用 Dog 类中定义的方法,因为 Dog 类继续了 Animal 类,所以 Dog 类对象拥有 Animal 类的所有属性和方法。

3.什么是重写

重写(override)是指在子类中实现一个与父类中同名、同参数列表的方法,并且这个方法的访问修饰符不能低于父类中的方法,目的是覆盖父类中的方法实现。在运行时,调用该方法时将优先执行子类中的实现。重写方法可以改变父类中的行为,实现多态性和动态绑定。

​class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /* 4.private*/ /* 1.final*/ /*2.static*/ public void eat() {
        System.out.println(this.name+"正在吃....");
    }
}
class Dog extends Animal {
    public Dog(String name,int age ) {
        super(name,age);
    }

    @Override//重写,建议加上@Override编译器就会检测是否符合重写的语法
    public void eat() {
        System.out.println(this.name+"正在吃狗粮....");
    }
}
class Bird extends Animal {
    public Bird(String name, int age) {
        super(name, age);
    }

    @Override//重写
    public void eat() {
        System.out.println(this.name + "正在吃鸟粮....");
    }
}
public class text {
    public static void func(Animal animal){
        animal.eat();
    }
    public static void main(String[] args) {
        func(new Dog("旺财",2));
        func(new Bird("布谷",1));

    }
}

4.多态,继承,封装的实现

// Animal 类定义
public class Animal {
    private String name;

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

    public void makeSound() {
        System.out.println("动物发出叫声");
    }
}

// Dog 类继承 Animal 类
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println("汪汪汪");
    }
}

// Cat 类继承 Animal 类
public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println("喵喵喵");
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("旺财");
        Animal cat = new Cat("咪咪");

        dog.makeSound(); // 输出:汪汪汪
        cat.makeSound(); // 输出:喵喵喵
    }
}

5.多态的一些注意事项

1.如果加上了方法上了关键字 final 就不可以发生重写

2.如果是被stastic 修饰的方法也不可以发生重写

3.被private修饰的方法也不可以被重写

4.注意被除private修饰的方法,子类的权限范围大于父类的权限范围

5.不要把构造方法中方法重写

6.重写,建议加上@Override编译器就会检测是否符合重写的语法

四.结语

在我们之后的学习中,封装,继承,多态有着许多的运用用途,面对对象的三巨头还需要我们在具体的项目中你就会慢慢发现这其中的妙用。

感谢阅读

 

你可能感兴趣的:(Java,java)