java基础之面向对象
面向对象是一种编程范式,它将程序中的数据和操作封装在对象中,并通过这些对象进行交互和通信。下面是一些面向对象的主要内容:
类和对象:
类是一个模板或蓝图,用于定义对象的属性(数据)和行为(方法)。
对象是类的实例,具有自己的状态(属性值)和行为(方法调用)。
封装:私有化
在 Java 中,封装是一种面向对象编程的基本概念,它指的是将数据和方法包装在一个类中,并对外部世界隐藏其实现细节,只暴露出一些公共接口供其他类进行访问。这样可以有效地保护数据,防止外部对象直接访问和修改类中的属性和方法,提高程序的安全性和可维护性。同时也使得代码更加模块化,易于扩展和重构。
Java 中的封装主要通过访问修饰符来实现,常用的有 private、protected、public 和默认访问修饰符。其中,private 访问修饰符表示只能在当前类中访问该属性或方法,其他类无法访问;protected 访问修饰符表示只能在当前类和其子类中访问该属性或方法;public 访问修饰符表示可以在任何地方访问该属性或方法;默认访问修饰符表示只能在同一个包中访问该属性或方法。
以下是一个简单的 Java 类,演示了如何使用封装:
public class Car {
private String brand;
private String color;
private int speed = 0;
public Car(String brand, String color) {
this.brand = brand;
this.color = color;
}
public void accelerate(int acceleration) {
speed += acceleration;
}
public void brake(int deceleration) {
speed -= deceleration;
}
public int getSpeed() {
return speed;
}
}
// 创建一个Car对象
Car myCar = new Car("Toyota", "Red");
// 封装的属性可以通过对象访问
System.out.println(myCar.getBrand()); // 输出:Toyota
System.out.println(myCar.getColor()); // 输出:Red
// 封装的方法也可以通过对象调用
myCar.accelerate(20);
System.out.println(myCar.getSpeed()); // 输出:20
myCar.brake(10);
System.out.println(myCar.getSpeed()); // 输出:10
在上述示例中,Car 类封装了三个私有属性:brand(品牌)、color(颜色)和 speed(速度),并提供了公共的方法来访问和操作这些属性。其他类无法直接访问 Car 类的私有属性,只能通过公共方法进行访问和修改。
封装的好处包括:
提高了代码的安全性和可维护性。
隐藏了实现细节,使得对外部的影响降到最小。
保护了数据的完整性和一致性,防止数据被误用或篡改。
使代码更加模块化,易于扩展和重构。
继承:关键词extends
继承是一种机制,允许一个类继承另一个类的属性和方法。
子类继承父类的特性,同时可以添加自己的特定特征。
继承提供了代码重用和层次化组织的能力。
继承是面向对象编程中的一种重要概念,它允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法。通过继承,子类可以重用父类的代码,并且可以在此基础上添加新的属性和方法,实现代码的复用和扩展。
以下是一个简单的 Java 示例,演示了如何使用继承:
// 定义一个父类 Animal
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
}
// 定义一个子类 Dog,继承自 Animal
class Dog extends Animal {
public Dog(String name) {
super(name);
}
public void bark() {
System.out.println("Woof woof!");
}
}
// 创建一个 Dog 对象,并调用继承的方法和子类中的方法
Dog myDog = new Dog("Buddy");
myDog.eat(); // 输出:Buddy is eating.
myDog.bark(); // 输出:Woof woof!
在上述示例中,Animal 类是父类,Dog 类是子类。Dog 类通过使用 extends 关键字继承了 Animal 类,从而获得了父类中的属性和方法。子类可以通过调用 super() 方法来调用父类的构造函数,以初始化继承的属性。
通过继承,Dog 类可以调用 Animal 类中的 eat() 方法,并且还可以添加自己独有的 bark() 方法。这样,我们既可以重用父类的代码,又可以根据子类的特殊需求进行代码扩展。
继承的主要好处包括:
代码复用:子类可以继承父类的属性和方法,避免了重复编写相同的代码。
继承层级:可以通过继承构建类的层级结构,使得代码更加有组织性和易于理解。
支持多态:通过继承,可以实现多态性,即不同子类对象可以以相同的方式被处理。
需要注意的是,Java 中只支持单继承,即一个类只能继承自一个父类。但是,Java 提供了接口(interface)来实现多继承的某些功能。此外,当子类继承父类时,子类可以覆盖(重写)父类的方法,以实现自己的特定行为。
多态:子类对象指向
多态指的是同一个方法可以在不同的对象上产生不同的行为。
多态提供了灵活性,使得不同类型的对象可以以相同的方式进行操作。
多态通过方法的重写和方法的重载来实现。
在面向对象编程中,多态是指相同的操作作用于不同的对象上会产生不同的行为。具体来说,在Java中,多态性可以通过继承和方法重写来实现。下面是一个简单的Java示例,演示了多态的概念:
// 定义一个父类 Animal
class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}
// 定义子类 Dog,覆盖父类的 makeSound 方法
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Bark!");
}
}
// 定义子类 Cat,覆盖父类的 makeSound 方法
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.makeSound(); // 输出:Bark!
myCat.makeSound(); // 输出:Meow!
}
}
在这个例子中,我们定义了一个父类Animal,以及两个继承自Animal的子类Dog和Cat。在父类Animal中,定义了一个makeSound方法,然后在子类Dog和Cat中分别重写了这个方法。在Main类的main方法中,我们创建了一个Dog对象和一个Cat对象,并将它们赋值给Animal类型的引用。然后分别调用了它们的makeSound方法。
由于Java中的动态绑定机制,虽然myDog和myCat都是Animal类型的引用,但它们实际指向的是不同的子类对象。因此,当调用makeSound方法时,实际上调用的是对应子类的重写方法,从而产生了不同的行为。
这就是多态的体现:相同的操作(调用makeSound方法)作用于不同的对象(Dog和Cat),产生了不同的行为(Bark和Meow)。这种灵活的行为表现形式使得程序更易于扩展和维护。
接口:关键词:implements
接口定义了一组抽象方法,描述了对象所支持的操作。
类可以实现一个或多个接口,通过实现接口中的方法来定义自己的行为。
接口提供了代码的松耦合性,使得不同类之间可以进行交互和通信。
在面向对象编程中,接口是一种定义了一组方法签名的抽象类型。接口可以被类实现,从而使得类能够遵循接口定义的行为规范。以下是一个简单的Java示例,演示了接口的概念:
// 定义一个接口Animal
interface Animal {
void makeSound();
}
// 定义一个类Dog,实现Animal接口
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark!");
}
}
// 定义一个类Cat,实现Animal接口
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.makeSound(); // 输出:Bark!
myCat.makeSound(); // 输出:Meow!
}
}
在这个例子中,我们定义了一个接口Animal,其中声明了一个方法makeSound。然后,我们分别创建了两个类Dog和Cat,并且它们都实现了Animal接口,并实现了makeSound方法。
在Main类的main方法中,我们创建了一个Dog对象和一个Cat对象,并将它们赋值给Animal类型的引用。然后调用它们的makeSound方法。
通过接口的使用,我们可以实现多态性。尽管myDog和myCat都是Animal类型的引用,但它们实际上指向了不同的对象。然而,由于它们都实现了Animal接口,并且遵循了makeSound方法的规范,因此可以调用makeSound方法,产生不同的行为。
接口的好处包括:
定义契约:接口定义了一组方法签名,作为类之间的契约,使得不同的类可以实现相同的接口,从而保证了一致的行为。
实现多继承:通过实现多个接口,一个类可以具有多个接口的特性,实现了某种程度上的多继承。
代码解耦:通过依赖接口而非具体实现类,可以将代码解耦,提高代码的灵活性和可维护性。
需要注意的是,接口中的方法默认是公共和抽象的,因此在实现接口时必须实现接口中声明的所有方法。同时,一个类可以实现多个接口,但只能继承一个父类。
抽象类:关键词:abstract
抽象类是一种不能实例化的类,它定义了一组抽象方法。
抽象方法没有具体的实现,需要在子类中进行实现。
抽象类可以包含具体的方法,子类可以直接继承和使用。
在面向对象编程中,抽象类是一种不能实例化的类,用于定义一组相关类的公共行为和属性。抽象类可以包含抽象方法和具体方法,并且可以被子类继承和扩展。以下是一个简单的Java示例,演示了抽象类的概念:
// 定义一个抽象类Animal
abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
// 定义一个抽象方法makeSound
public abstract void makeSound();
}
// 定义一个具体类Dog,继承自Animal
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Bark!");
}
}
// 定义一个具体类Cat,继承自Animal
class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog("Doggy");
Animal myCat = new Cat("Kitty");
System.out.println(myDog.getName() + " says:");
myDog.makeSound(); // 输出:Bark!
System.out.println(myCat.getName() + " says:");
myCat.makeSound(); // 输出:Meow!
}
}
在这个例子中,我们定义了一个抽象类Animal,其中包含了一个抽象方法makeSound和一个具体方法getName。抽象类Animal还有一个私有属性name,以及一个构造方法用于初始化name。
然后,我们定义了两个具体类Dog和Cat,它们都继承自Animal类,并实现了makeSound方法。这些具体类必须实现抽象类Animal中的所有抽象方法。
在Main类的main方法中,我们创建了一个Dog对象和一个Cat对象,并将它们赋值给Animal类型的引用。通过这种方式,我们可以访问抽象类Animal中定义的方法和属性。
通过抽象类的使用,我们可以实现代码的重用和扩展。抽象类提供了一种模板或基类的概念,可以定义通用的行为和属性,而具体类则可以根据需要进行进一步的定制和扩展。
需要注意的是,抽象类不能被实例化,只能作为基类被其他类继承。同时,如果一个类继承了抽象类,它必须实现抽象类中的所有抽象方法,除非该类本身也是一个抽象类。
设计模式:
设计模式是一套解决常见问题的经验总结和最佳实践。
它们提供了在特定情境下的可重用解决方案,提高了代码的可维护性和可扩展性。
常见的设计模式包括单例模式、工厂模式、观察者模式等。
设计模式是一种经过实践证明的、被广泛采用的面向对象编程技巧。以下是三个常见的设计模式示例:
单例模式
单例模式是一种保证一个类只有一个实例,并提供全局访问点的设计模式。以下是一个简单的Java示例,演示了单例模式的概念:
// 定义一个单例类Singleton
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2); // 输出:true
}
}
在这个例子中,我们定义了一个单例类Singleton,其中包含一个私有静态属性instance和一个私有构造方法。getInstance方法通过检查instance是否为空来返回Singleton的唯一实例。
在Main类的main方法中,我们创建了两个Singleton对象s1和s2,并比较它们的引用是否相等。由于Singleton类只有一个实例,因此s1和s2实际上是同一个对象。通过使用单例模式,我们可以保证某些类只有一个实例,从而避免了重复创建对象的开销和可能的线程安全问题。
工厂模式
工厂模式是一种将对象的创建和使用分离的设计模式。以下是一个简单的Java示例,演示了工厂模式的概念:
// 定义一个接口Shape
interface Shape {
void draw();
}
// 定义具体类Circle、Rectangle和Square,实现Shape接口
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing circle...");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing rectangle...");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing square...");
}
}
// 定义一个工厂类ShapeFactory,用于创建Shape对象
class ShapeFactory {
public static Shape getShape(String type) {
if (type.equalsIgnoreCase("circle")) {
return new Circle();
} else if (type.equalsIgnoreCase("rectangle")) {
return new Rectangle();
} else if (type.equalsIgnoreCase("square")) {
return new Square();
} else {
return null;
}
}
}
public class Main {
public static void main(String[] args) {
Shape circle = ShapeFactory.getShape("circle");
Shape rectangle = ShapeFactory.getShape("rectangle");
Shape square = ShapeFactory.getShape("square");
circle.draw();
rectangle.draw();
square.draw();
}
}
在这个例子中,我们定义了一个接口Shape,其中包含一个抽象方法draw。然后,我们定义了三个具体类Circle、Rectangle和Square,它们都实现了Shape接口,并实现了draw方法。
接着,我们定义了一个工厂类ShapeFactory,它包含一个静态方法getShape来创建Shape对象。根据传入的参数type,ShapeFactory可以创建不同类型的Shape对象。
在Main类的main方法中,我们使用ShapeFactory来创建Circle、Rectangle和Square对象,并调用它们的draw方法。通过使用工厂模式,我们可以将对象的创建和使用分离,从而使得代码更加灵活和易于维护。
观察者模式
观察者模式是一种在对象之间定义一对多的依赖关系,使得当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新的设计模式。以下是一个简单的Java示例,演示了观察者模式的概念:
// 定义一个接口Observer
interface Observer {
void update(int value);
}
// 定义具体类BinaryObserver、OctalObserver和HexObserver,实现Observer接口
class BinaryObserver implements Observer {
@Override
public void update(int value) {
System.out.println("Binary string: " + Integer.toBinaryString(value));
}
}
class OctalObserver implements Observer {
@Override
public void update(int value) {
System.out.println("Octal string: " + Integer.toOctalString(value));
}
}
class HexObserver implements Observer {
@Override
public void update(int value) {
System.out.println("Hex string: " + Integer.toHexString(value));
}
}
// 定义一个主题Subject,包含一个列表observers,用于存储观察者对象
class Subject {
private List<Observer> observers = new ArrayList<>();
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
notifyObservers();
}
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(value);
}
}
}
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
Observer binaryObserver = new BinaryObserver();
Observer octalObserver = new OctalObserver();
Observer hexObserver = new HexObserver();
subject.attach(binaryObserver);
subject.attach(octalObserver);
subject.attach(hexObserver);
System.out.println("First state change: 15");
subject.setValue(15);
subject.detach(hexObserver);
System.out.println("\nSecond state change: 10");
subject.setValue(10);
}
}
在这个例子中,我们定义了一个接口Observer,其中包含一个抽象方法update。然后,我们定义了三个具体类BinaryObserver、OctalObserver和HexObserver,它们都实现了Observer接口,并实现了update方法。
接着,我们定义了一个主题Subject,它包含一个列表observers,用于存储观察者对象。Subject类还包含setValue方法,用于设置value属性并通知所有观察者对象进行更新。
在Main类的main方法中,我们创建了一个Subject对象subject,并分别创建了三个Observer对象binaryObserver、octalObserver和hexObserver。然后,我们将这些观察者对象注册到主题subject中,并设置了value属性的值。当value属性发生变化时,所有观察者对象都会收到通知并更新自己的状态。
通过使用观察者模式,我们可以实现对象之间的松耦合,从而使得代码更加灵活和易于扩展。主题Subject和观察者Observer之间没有直接的依赖关系,它们之间只通过一个共同的接口进行通信,从而使得代码更加易于维护和测试。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)