Bootstrap

[Javase]封装、继承、多态与异常处理

一、前言

本文章适合有一定面向对象基础的读者阅读。如果你对Java编程尚不熟悉,建议先转向传送门,阅读之前的入门文章,以便更好地理解后续内容。


二、封装

1、封装的思想

封装是面向对象编程(OOP)的一个核心概念,它的主要思想是隐藏对象的内部细节,只暴露必要的接口供外部访问和操作。通过封装,我们可以确保对象的内部状态不被外部随意修改,从而保护对象的完整性。同时,封装还可以提供灵活的接口,使得对象的行为可以根据需要进行调整而不会影响其内部结构。

封装的核心在于 “信息隐藏” 和 “抽象” 。信息隐藏意味着将对象的内部状态(即其属性和方法)封装起来,只通过公共接口与外部进行交互。抽象则是指将对象的复杂性和细节隐藏起来,只展示其最本质的特征和功能。

2、封装代码层面的体现

在Java编程语言中,封装这一面向对象编程的核心概念,主要通过运用访问修饰符(具体包括private、protected、public以及默认的访问权限)以及getter和setter方法这两大手段得以实现。

  • private:表示私有,仅类内部可以访问和修改,实现了最大程度的封装和隐藏。
  • protected:表示受保护,子类以及同一个包内的其他类可以访问。提供了一定程度的封装,同时允许子类继承访问。
  • public:表示公共,任何地方都可以访问。虽然不符合封装原则中的信息隐藏,但在需要对外提供接口时必不可少。
  • 默认访问级别:没有修饰符,表示类、方法或变量可以被同一个包内的其他类访问。这提供了一定程度的封装,但仅限于包内。
public class Person {    
    //私有属性,外部无法直接访问  
    private String name;  
    private int age;  
    
    //构造方法  
    public Person(String name, int age) {    
        this.name = name;    
        this.age = age;    
    }

    //Setter方法,用于设置属性值
	public void setName(String name) {
        this.name = name;
    }
      
    //Getter方法,用于获取属性值  
    public String getName() {    
        return name;    
    }  
      
    //Setter方法,用于设置属性值,并包含简单的验证逻辑  
    public void setAge(int age) {    
        if (age > 0) {    
            this.age = age;    
        } else {    
            throw new IllegalArgumentException("年龄不能小于零");  
        }  
    }  
      
    //Getter方法,用于获取年龄属性(注意:虽然在此示例中未直接展示,但通常也会为age属性提供getter方法)  
    public int getAge() {    
        return age;    
    }  
}

在这个示例中,我们将Person类的name和age属性设置为私有,从而限制了外部直接访问这些属性的能力。然后,我们通过提供公共的getter和setter方法来允许外部代码以受控的方式访问和修改这些属性的值。这种封装机制不仅保护了对象的内部状态,还使得我们能够在setter方法中添加额外的验证逻辑,以确保对象的状态始终保持有效和一致。


三、继承

1、继承的概念和好处

类是对具有相似属性和方法的对象的抽象,而继承则是对具有层级或 “是一种” 关系的类之间的进一步抽象。通过继承,子类可以继承父类的属性和方法,从而简化代码,提高代码的可重用性和可维护性。

请添加图片描述

2、继承代码层面的体现

继承的好处是,子类不用重复定义某些东西。

//父类  
class Animal {  
    private String name;
    private int age;
  
    public void eat() {  
        System.out.println(name + "觅食");  
    }

    public void call() {
        System.out.println(name + "大叫");
    }
}  
  
//子类  
class Dog extends Animal {  
    public void special() {  
        System.out.println(name + "在看家");  
    }

    //对不满意的方法进行重写
    public void call() {
        System.out.println(name + "汪~汪叫");
    }
}  
  
public class InheritanceDemo {  
    public static void main(String[] args) {  
        Dog dog = new Dog();  
        dog.name = "小汪";  
        dog.eat();//继承自父类的方法  
        dog.special();//子类自己的方法
        dog.call();//重写的方法
    }  
}

在这个例子中,Dog类继承了Animal类,并添加自己的方法。Dog对象可以调用从Animal类继承的方法,以及自己添加的方法。


四、多态

1、多态的概念

多态是面向对象编程的一个重要特性,它允许我们使用父类类型的引用来指向子类对象。通过这种方式,我们可以在运行时动态地确定要调用哪个类的方法,而不是在编译时确定。

2、多态的好处和三要素

多态提高了代码的灵活性和可扩展性,简化了代码结构,并实现了接口与实现的分离,使我们能够轻松添加新子类而无需修改现有代码,同时用统一接口调用不同实现。

  • 继承:多态的前提是存在继承关系。
  • 重写:子类需要重写父类中的方法,以实现多态的行为。
  • 父类引用指向子类对象:这是多态的实现方式,允许我们在不知道具体子类类型的情况下调用方法。

2、多态代码层面的体现

多态跟属性无关,多态指的是方法的多态,而不是属性的多态。

//父类  
class Animal {  
    public void sound() {  
        System.out.println("Some generic animal sound");  
    }  
}  
  
//子类1  
class Dog extends Animal {  
    public void sound() {  
        System.out.println("Woof! Woof!");  
    }  
}  
  
//子类2  
class Cat extends Animal {  
    public void sound() {  
        System.out.println("Meow! Meow!");  
    }  
}  
  
public class PolymorphismDemo {  
    public static void main(String[] args) {
        //父类引用指向子类对象
        Animal myDog = new Dog();
        Animal myCat = new Cat();  
  
        myDog.sound();//调用Dog类的sound方法  
        myCat.sound();//调用Cat类的sound方法  
    }  
}

在这个例子中,myDog和myCat都是Animal类型的引用,但它们分别指向Dog和Cat对象。当我们调用sound方法时,Java虚拟机在运行时确定要调用哪个类的方法,从而实现多态。


五、异常处理

1、try-catch-finally结构详解

try块里放的是可能会出错的代码,一旦出错,就会跳到catch块去处理这个错误。而finally块,不管出没出错,它都会执行,常常用来做一些收尾工作,比如关掉打开的文件或释放资源。

public class test {
    public static void main(String[] args) {
        try {
            int num1 = 12;
            int num2 = 0;
            System.out.println(num1 / num2);
        } catch(Exception ex) {
            //捕获异常并处理
            System.out.println("程序异常");
        } finally {
            System.out.println("无论是否出异常都执行");
        }
    }
}

2、throw\throws

throw用于显式抛出异常对象,中断当前方法执行并传递给调用者,其后必须是Throwable实例。而throws是方法声明中的关键字,用于指明方法可能抛出的异常类型,调用者需对此进行处理,或继续向上层抛出。

public class test {
    public static void main(String[] args) {
        //调用者需要对可能抛出异常的方法进行处理(也可继续抛出)
        try {
            dev();
        } catch(Exception ex) {
            System.out.println("程序异常");
        }
    }

    //这是一个可能抛出异常的函数(使用throws声明)  
    public static void dev() throw Exception {
        int num1 = 13;
        int num2 = 0;
        if (num2 == 0) {
            throw new Exception();//显式地创建并抛出一个异常对象
        } else {
            System.out.println(num1 / num2);
        }
    }
}

;