文章目录
一、前言
本文章适合有一定面向对象基础的读者阅读。如果你对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);
}
}
}