JAVA面向对象
继承
- 继承是面向对象编程的一个重要概念,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。这种机制允许你创建一个新的类,它可以重用已存在的类的代码,并且可以添加自己的属性和方法,或者覆盖父类的方法以改变其行为
- 基本语法
class 父类名 {
// 父类的属性和方法
}
class 子类名 extends 父类名 {
// 子类的属性和方法
}
- 注意以下内容
- 子类可以扩展父类的功能,添加新的属性和方法。
- 子类可以重写(覆盖)父类的方法,以改变方法的行为。为此,子类的方法必须具有与父类方法相同的名称、参数列表和返回类型。
- Java中不支持多继承,即一个类不能直接继承多个父类。但可以通过接口实现多继承的一部分功能。
- 使用关键字 super 可以在子类中调用父类的构造函数、属性和方法。
- 继承示例
class Animal {
String name;
public void eat() {
System.out.println(name + " is eating.");
}
}
class Dog extends Animal {
public void bark() {
System.out.println(name + " is barking.");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.name = "Buddy";
myDog.eat(); // 调用父类方法
myDog.bark(); // 调用子类方法
}
}
- 在上面的示例中,Dog 类继承了 Animal 类,因此它可以访问 Animal 类中的 name 属性和 eat() 方法,并且还添加了自己的 bark() 方法.
重写/重载
-
重写(override)和重载(overload)是两种不同的方法覆盖和定义方法的方式。它们用于实现多态性和方法的灵活性.
-
方法重载
- 方法重载是指在同一个类中定义多个方法,这些方法具有相同的名称但不同的参数列表。方法重载允许你在同一个类中创建多个具有相似功能但参数不同的方法.
- 规则
- 方法名称必须相同。
- 方法参数列表必须不同,要么参数个数不同,要么参数类型不同,或者两者都不同。
- 返回类型可以相同也可以不同,但仅根据返回类型无法区分方法重载
- 示例
class Calculator { int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } }
- 解释:上面的示例中,Calculator 类中定义了两个名为 add 的方法,一个接受两个整数参数,另一个接受两个浮点数参数.
-
方法重写
- 方法重写是指子类覆盖(重新定义)了父类中具有相同名称、参数列表和返回类型的方法。子类中的重写方法必须具有相同的方法签名(方法名称、参数列表和返回类型)
- 规则
- 子类方法的名称、参数列表和返回类型必须与父类方法相同.
- 子类方法的访问修饰符不能低于父类方法的修饰符(例如,如果父类方法是 public,子类方法可以是 public 或 protected,但不能是 private).
- 子类方法不能抛出比父类方法更宽泛的异常(如果父类方法抛出异常).
- 子类方法可以使用 @Override 注解来明确表示它是一个重写方法,这有助于提高代码的可读性.
- 示例
class Animal { void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void makeSound() { System.out.println("Dog barks"); } }
- 解释:Dog 类重写了 Animal 类的 makeSound 方法,改变了方法的行为.
-
总结
- 重载用于创建多个同名方法,根据参数不同调用不同的方法.
- 重写用于子类覆盖父类中具有相同签名的方法,以改变方法的行为.
多态
- 多态是面向对象编程的一个重要概念,它允许不同的对象对同一消息做出不同的响应。多态性主要体现为方法的多态性,它可以通过继承和接口实现.
- 方法的多态性
- 方法的多态性是指可以使用父类的引用变量来引用子类对象,并调用子类重写(覆盖)的方法,从而实现不同对象对同一消息的不同响应。这通常是通过方法重写(方法覆盖)来实现的.
class Animal { void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void makeSound() { System.out.println("Dog barks"); } } public class Main { public static void main(String[] args) { Animal myAnimal = new Dog(); // 使用父类引用指向子类对象 myAnimal.makeSound(); // 调用子类重写的方法 } }
- 解释:在上面的示例中,myAnimal 是一个 Animal 类型的引用变量,但它指向了一个 Dog 类的对象。当调用 makeSound 方法时,会调用 Dog 类中的版本.
- 接口的多态性
- 一个类可以实现一个或多个接口,然后可以使用接口的引用来引用实现了该接口的类的对象
interface Shape { void draw(); } class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle"); } } class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing a rectangle"); } } public class Main { public static void main(String[] args) { Shape shape1 = new Circle(); Shape shape2 = new Rectangle(); shape1.draw(); // 调用Circle类的draw方法 shape2.draw(); // 调用Rectangle类的draw方法 } }
- 解释:在上面的示例中,shape1 和 shape2 都是 Shape 接口类型的引用,但它们分别指向了 Circle 和 Rectangle 类的对象。通过接口多态性,可以调用不同类的 draw 方法.
抽象类
- Java中的抽象类(Abstract Class)是一种特殊的类,它不能被实例化,主要用于为其他类提供通用的属性和方法。抽象类可以包含抽象方法(没有方法体)和具体方法(有方法体),子类需要实现抽象方法.
- 声明抽象类: 使用关键字 abstract 来声明一个抽象类。抽象类可以包含抽象方法和非抽象方法
abstract class Animal { // 抽象方法 public abstract void makeSound(); // 非抽象方法 public void sleep() { System.out.println("Animal is sleeping."); } }
- 抽象方法: 抽象类中可以包含抽象方法,这些方法没有具体的实现,只有方法的声明,没有方法体。子类必须实现抽象方法.
- 子类实现:子类继承抽象类并实现其中的抽象方法,否则子类也必须声明为抽象类.
class Dog extends Animal {
// 实现抽象方法
public void makeSound() {
System.out.println("Dog barks.");
}
}
封装
- 封装是面向对象的一个基本原则,它指的是将一个对象的内部状态(数据成员)和行为(方法)捆绑在一起,并对外部隐藏对象的内部实现细节,只提供有限的接口供外部使用.
- 私有化数据成员(私有字段):将类的数据成员(字段)标记为私有(private),这意味着它们只能在类的内部访问,外部无法直接访问这些字段.
public class Person {
private String name;
private int age;
}
- 提供公有的访问方法(公有方法):为了允许外部代码访问和修改私有字段的值,类通常提供一组公有的访问方法,这些方法被称为 getter 和 setter 方法。Getter 方法用于获取字段的值,setter 方法用于设置字段的值.这些方法允许对字段进行控制和验证.
public class Person {
private String name;
private int age;
// Getter 方法
public String getName() {
return name;
}
// Setter 方法
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0) {
this.age = age;
}
}
}
- 访问控制: 使用访问修饰符(如 public、private、protected 和默认包访问级别)来限制类的成员的访问权限,以确保只有需要的方法和字段对外可见.
- 封装的好处包括
- 安全性: 封装可以防止外部代码直接访问和修改对象的内部状态,从而提高了数据的安全性和完整性.
- 隐藏实现细节: 封装可以隐藏对象的内部实现细节,使类的用户只关注如何使用类的接口,而不必关心内部实现.
- 维护性: 封装使得可以更容易修改类的内部实现,只要类的接口保持不变,外部代码不受影响.
- 代码重用: 封装有助于创建可重用的类,其他代码可以轻松地使用这些类的接口,而不必了解其内部工作原理.
接口
- 接口(Interface)是一种特殊的引用类型,它用于定义一组抽象方法,但不能包含字段(实例变量)。接口定义了一组方法的契约,而实现接口的类必须提供这些方法的具体实现.
- 声明接口
public interface MyInterface {
// 抽象方法
void doSomething();
// 可以包含常量
int MAX_VALUE = 100;
}
- 实现接口: 使用 implements 关键字来实现接口。一个类可以实现多个接口
public class MyClass implements MyInterface {
// 实现接口的抽象方法
public void doSomething() {
// 具体实现
}
}
- 接口方法: 接口中的方法默认为抽象方法(不包含方法体),子类必须提供方法的具体实现。在Java 8之后,接口也可以包含默认方法(有方法体)和静态方法(静态成员方法)
public interface MyInterface {
// 抽象方法
void doSomething();
// 默认方法(Java 8+)
default void doSomethingElse() {
// 具体实现
}
// 静态方法(Java 8+)
static void doStatic() {
// 具体实现
}
}
- 多继承: Java中的类只支持单继承,但一个类可以实现多个接口。这允许类获取多个接口的特性
- 接口的用途
- 定义规范和契约,确保实现类遵循一组特定的方法签名。
- 实现多态性,使得不同类的对象可以根据它们实现的接口类型进行通用操作。
- 创建回调机制,允许一个对象通知另一个对象特定事件的发生。
- 定义常量值
枚举
- 枚举(Enum)是一种特殊的数据类型,用于定义一组命名的常量值。枚举允许您将一组相关的常量组织在一起,以提高代码的可读性和维护性.
- 声明枚举:使用关键字 enum 来声明一个枚举类型.
enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
- 枚举常量: 枚举中的每个常量都是枚举类型的实例,它们是不可改变的,通常用大写字母表示。在上面的例子中,Day 枚举有七个常量.
- 访问枚举常量: 可以通过枚举常量的名称来访问它们.
Day today = Day.MONDAY;
- 枚举方法: 枚举可以包含方法。每个枚举常量可以有自己的方法实现.
enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
public boolean isWeekend() {
return this == SATURDAY || this == SUNDAY;
}
}
- 遍历枚举 : 您可以使用 values() 方法来获取枚举中的所有常量,然后遍历它们.
for (Day day : Day.values()) {
System.out.println(day);
}
- 枚举的比较 : 枚举常量之间可以使用 == 运算符进行比较,因为它们是单一实例.
Day today = Day.MONDAY;
if (today == Day.MONDAY) {
System.out.println("It's Monday!");
}
包
- 包(Package)是一种用于组织和管理类和其他资源的机制。包可以包含类、接口、枚举、子包等。包的主要目的是帮助组织和管理大型项目中的类和避免命名冲突.
- 声明包: 在Java文件的顶部,使用 package 关键字来声明类所属的包.这将把当前类置于 com.example.myproject 包下.
package com.example.myproject;
- 包结构: 包是有层次结构的,可以包含子包,形成包的层次结构。例如,
com.example.myproject
是一个包,com.example.myproject.util
可以是其子包. - 包的命名约定: 包名通常是小写字母,多个单词可以使用驼峰命名法(
camelCase
)或全部小写字母加下划线(snake_case
)。通常使用反向域名(reverse domain name
)来避免包名冲突,如com.example.myproject
- 导入包: 在Java源文件中,可以使用 import 关键字导入其他包中的类,以便在代码中使用这些类.
import java.util.ArrayList;
- 包访问权限: 类可以有包级别的访问权限,即只能在同一个包内访问。不使用 public、private 或 protected 修饰符的类和成员默认具有包访问权限.
- 包的组织和管理: 使用包可以将相关的类组织在一起,帮助管理项目的结构。这对于大型项目非常重要,因为它可以减少命名冲突,提高代码的可维护性.
- 可见性控制: 包也用于控制类和成员的可见性。包内的类可以访问包内的其他类和成员,但对于不在同一个包中的类,需要使用 public、protected、包私有或私有访问修饰符来控制可见性.
- 包的部署: 在Java应用程序部署时,包的结构通常会反映在目录结构中,每个包对应一个目录。这有助于组织和管理项目的部署.
- 标准包: Java提供了许多标准包,如 java.util、java.io 等,它们包含了各种常用的类和工具。您可以通过导入这些包来使用它们的类.
读万卷书,行万里路,方能回到内心深处。