欢迎光临
我们一直在努力

深入理解Java的封装,继承以及多态

一、引言

    在我们面向对象的编程当中万物皆可对象,通过对象来组织和管理代码,而封装继承和多态则是其主要的核心思想,下面跟着我的节奏来让你深入理解。

二、封装

1、概念与目的

    封装的概念如字面意思一样,是要把某一个东西给他密封起来,但又不是完全密封举一个例子:我们在使用手机的时候,我们可以使用手机各种各样的功能,但是我们看不到手机内部是如何运作的也就是细节我们是看不到的我们只可以使用,所以封装也就是隐藏内部用于实现的细节,属性(相当于手机内部),仅仅暴露必要的接口或者方法给外部访问(我们可以使用手机的各种功能),这样做可以提高我们代码的一个安全性。

2、Java的实现

    为了实现封装Java提供了四个关键字分别是“private”,“default”,“protected”,“public”那么这四个关键字都有什么作用呢?下面我给大家列一个表格

private default protected public
同一个类里可以用 true true true true
同一个包里可以用 true true true
不同包的子类可以用 true true
所有的都可以用 true

private相当于是你自己的小秘密,default就是我们家庭的秘密,protected就是只有后代可以知道。

    需要注意的是我们在用private去修饰的时候我们要提供Get和Set方法

public class Person {
// 私有属性
private String name;
private int age;

// name属性的getter方法
public String getName() {
return name;
}

// name属性的setter方法
public void setName(String name) {
this.name = name;
}

// age属性的getter方法
public int getAge() {
return age;
}

// age属性的setter方法
public void setAge(int age) {
this.age = age;
}
}

如上代码所演示

3、封装的好处

    可以保护数据防止外部随意修改,内部可以自由更改而且不会影响外部的调用,使用的人只需要关注接口和方法即可。

三、继承

  1、继承的概念和目的

    继承顾名思义就是从上面得到的东西,比如从自己的父辈得到的东西,从祖上传下来的东西。我们就有子类和父类,子类就是继承的父类就是被继承的。这样一来我们就可以实现代码的复用,建立类之间的层次关系

  2、Java的实现机制

    为了实现继承Java为我们提供了extends关键字,具体要怎么使用呢?

// 父类
class Animal {
private String name;

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

public void eat() {
System.out.println(name + " is eating.");
}

public void sleep() {
System.out.println(name + " is sleeping.");
}
}

// 子类继承父类
class Dog extends Animal {
private String breed;

public Dog(String name, String breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}

public void bark() {
System.out.println("Woof! Woof!");
}

@Override
public void eat() {
super.eat(); // 调用父类方法
System.out.println("The dog is eating dog food.");
}
}

如上代码演示,从上面的代码我们看到了一个陌生的关键字super,那么这个关键字的作用是什么呢?首先根据上述代码我们发现了父类有一个带有参数构造方法,这个时候我们的子类在写构造方法的时候就必须要去调用父类的构造方法这个时候我们就要用super来调用,super是有一点类似于this的,如果父类有无参数构造方法的话我们直接super();就可以了。我们子类可以对父类的方法进行重写,那么我们之后通过子类来调用这个方法的时候我们就一定会使用子类重写后的方法,这个时候如果还想使用父类就如上所示通过super去进行调用就可以了。值得一提的是子类是不可以访问父类里被private修饰的属性只可以通过Get和Set方法。

  3、继承和组合

    继承相当于动物和猫狗的关系,组合则是汽车和轮胎发动机等的关系,下面用代码来演示

// 轮胎类
class Tire{
// …
}
// 发动机类
class Engine{
// …
}
// 车载系统类
class VehicleSystem{
// …
}
class Car{
private Tire tire; // 可以复用轮胎中的属性和方法
private Engine engine; // 可以复用发动机中的属性和方法
private VehicleSystem vs; // 可以复用车载系统中的属性和方法
// …
}
// 奔驰是汽车
class Benz extend Car{
// 将汽车中包含的:轮胎、发送机、车载系统全部继承下来
}

    继承和组合的应用场景类似,一般情况下都更建议使用组合。

四、多态

  1、多态的概念和目的

    多态是什么呢?举一个例子现在有一包纸巾,有三个人,一个人要拿纸巾去上厕所,一个人要拿来擦嘴巴,还有一个人要拿来擦桌子,那么三个人用的都是同一个东西,但是使用的目的都不一样,如此一来我们把多个子类继承同一个父类并且使用同一个方法但是实现的效果不一样这就是多态。多态可以提高我们代码的复用性、可扩展性,使代码更加灵活,同时还可以提升可维护性,简化代码的逻辑。

  2、Java的实现机制

    在Java当中我们要想实现多态可以对父类的方法进行方法的重载或者方法的重写,其中重载属于编译时的多态,重写是属于运行时的多态,那么这俩个有什么区别呢?

Dog dog=new Dog;
dog.eat();

    如果Dog是对父类的方法进行重载,那么在编译阶段编译器会检查Dog类是否有eat方法,有则通过,如果是重写的话JVM则会通过dog找到Dog对象,然后就会查找方法表找到eat,确定方法的版本。

  3、向上转型和动态绑定

    向上转型是什么?有点像往上走的那种意思,简单来说就是父类引用指向子类对象,那么要怎么去做呢?

// 父类定义
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

// 子类继承父类
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}

// 子类特有方法
public void fetch() {
System.out.println("Dog fetches the ball");
}
}

public class Main {
public static void main(String[] args) {
// 向上转型:子类对象赋值给父类引用
Animal myAnimal = new Dog();

// 调用重写方法(多态)
myAnimal.makeSound(); // 输出: Dog barks

// 无法调用子类特有方法
// myAnimal.fetch(); // 编译错误
}
}

这是直接赋值的一种方法,还有就是将父类作为作为一个方法的参数和将父类作为方法的返回类型来实现向上转型,下面用代码作为演示

// 父类
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

// 子类
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}

// 子类
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows");
}
}

// 测试类
public class Main {
// 方法参数使用父类类型,实现向上转型
public static void animalSound(Animal animal) {
animal.makeSound();
}

public static void main(String[] args) {
Animal myAnimal = new Animal();
Dog myDog = new Dog();
Cat myCat = new Cat();

// 向上转型:子类对象作为父类参数传递
animalSound(myAnimal); // 输出: Animal makes a sound
animalSound(myDog); // 输出: Dog barks
animalSound(myCat); // 输出: Cat meows
}
}

class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}

public void fetch() {
System.out.println("Dog fetches the ball");
}
}

class AnimalFactory {
// 方法返回类型为父类Animal,实际返回子类Dog对象
public Animal createAnimal() {
return new Dog(); // 向上转型
}
}

public class Main {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.createAnimal(); // 接收返回的Dog对象

animal.makeSound(); // 输出: Dog barks
// animal.fetch(); // 编译错误,Animal类没有fetch方法

}
}

如上我们注意到父类作为方法的返回类型时实际返回的是某个子类对象,在写代码的时候我们可以通过if来决定返回哪一个子类的对象。那么有向上转型就有向下转型,在向上转型当中我们无法使用子类特有的方法这个时候我们就可以用到向下转型了

class Animal {
void eat() {
System.out.println("Animal is eating");
}
}

class Dog extends Animal {
void bark() {
System.out.println("Dog is barking");
}
}

public class DowncastingExample {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型(隐式)

if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 向下转型(显式)
dog.eat(); // 继承自Animal的方法
dog.bark(); // Dog类特有方法
}
}
}

如上我们注意到在向下转型的过程当中我们要进行类型的转换,所以向下转型其实并不安全,万一转换失败就会抛出异常,为了向下转型的安全Java提供了instanceof 关键字如果返回true那么就可以安全转换除了上面的办法我们其实还可以

​
if (animal instanceof Dog dog) {
dog.bark(); // Dog类特有方法
}

​

如上演示我们可以在判断的时候就完成赋值这就是隐式向下转型,不过这只有从jdk16开始才有的之前的是没有的。

    动态绑定其实就是在运行的时候根据引用所指向的实际对象来决定调用哪个方法,我们多态其实就是一种动态绑定我们通过子类来调用的话就会调用被子类重写/重载过的方法。

  4、注意事项

    我们的属性是没有多态性的,当子类和父类的属性同名时,我们通过父类引用,只能来引用父类自己的属性,构造方法也是没有多态性的我们要避免在构造方法当中调用被重写的方法,我们的静态方法也是没有多态性的被rivate、final、static 修饰的方法是不可以被重写的。

五、总结

    那么来总结一下,封装:将数据和操作数据的方法绑定在一起,隐藏内部实现细节,仅暴露必要接口。通过访问修饰符(如private、public)控制可见性,提高代码安全性和可维护性。

继承:子类继承父类的属性和方法,实现代码复用。支持单继承(如Java)或多继承(如C++),通过extends或:语法实现。子类可扩展或重写父类功能。

多态:同一操作作用于不同对象时产生不同行为。通过方法重写(子类覆盖父类方法)或接口实现达成。分为编译时多态(如函数重载)和运行时多态(方法重写)

给大家总结一个口诀

封装:隐藏实现,暴露接口

继承:代码复用,层次关系

多态:同一接口,不同实现

那么到这里这篇文章也就结束了,下一期我会写接口和抽象类,说起来这一期也隔了好久了,主要也是寒假在打寒假工的原因,还有寒假自己有一点点懒啦。

赞(0)
未经允许不得转载:171主机测评 » 深入理解Java的封装,继承以及多态
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址