类和对象的概念

什么是类


类(class):

  1. 定义

  2. 类是现实世界中某些具有共同属性和行为的事物的抽象。它定义了一组特定的属性(数据)和方法(操作这些数据的函数)。

  3. 蓝图

  4. 类可以看作是创建对象的蓝图或模板。它规定了对象的结构和行为。

  5. 封装

  6. 类通过将数据和操作这些数据的方法组合在一起,提供了封装。这意味着类的内部实现细节可以对外部隐藏,只通过定义的接口与外界交互。

  7. 继承

  8. 类可以继承其他类的属性和方法,这有助于代码复用和建立层次结构。

  9. 多态

  10. 类可以实现多态性,允许使用统一的接口来处理不同类型的对象。

什么是对象


对象

  1. 实例

  2. 对象是根据类的定义创建的实例。每个对象都是其类的一个具体表现。

  3. 状态

  4. 对象拥有自己的状态,这是通过其属性值来定义的。不同的对象可以有不同的状态,即使它们是同一个类的实例。

  5. 行为

  6. 对象可以执行类中定义的行为,即调用其方法。

  7. 身份

  8. 每个对象在内存中有自己的唯一地址,可以独立于其他对象存在。

  9. 交互

  10. 对象之间可以通过消息传递进行交互,一个对象可以请求另一个对象执行其方法或访问其属性。

举例说明

假设我们有一个名为Car的类,它定义了汽车的属性(如颜色、速度)和行为(如启动、停止、加速)。

javapublic class Car {
    // 属性
    private String color;
    private int speed;

    // 构造方法
    public Car(String color) {
        this.color = color;
        this.speed = 0;
    }

    // 方法
    public void start() {
        speed = 10; // 假设的初始速度
        System.out.println("Car started.");
    }

    public void stop() {
        speed = 0;
        System.out.println("Car stopped.");
    }

    // 其他方法和属性...
}

现在,如果我们想要创建一个具体的汽车对象,我们可以这样做:

java复制public class Main {
    public static void main(String[] args) {
        // 创建Car类的对象
        Car myCar = new Car("Red");

        // 使用对象的行为
        myCar.start(); // 输出: Car started.
        System.out.println("Car color: " + myCar.getColor()); // 假设有getColor方法
        myCar.stop();  // 输出: Car stopped.
    }
}

在这个例子中:

  • Car是一个类,它定义了汽车的结构和行为。
  • myCar是一个对象,它是Car类的一个实例,拥有自己的状态(颜色为"Red",初始速度为0)和行为(可以启动和停止)。

通过这个例子,我们可以看到类和对象在面向对象编程中是如何协同工作的。

成员变量


在面向对象编程中,成员变量(也称为属性或字段)是类的一部分,用于存储关于对象状态的信息。

成员变量的关键特点:

  1. 定义:成员变量是在类中定义的变量,它们与类的对象(实例)相关联。

  2. 作用域:成员变量的作用域是整个类体,这意味着类的任何方法都可以访问这些变量。

  3. 数据封装:成员变量通常被声明为私有(使用private关键字),以隐藏类的内部实现细节,并通过公共方法(如getter和setter)来访问和修改这些变量的值。

  4. 初始化:成员变量可以在声明时初始化,也可以在构造方法中初始化。

  5. 类型:成员变量可以是基本数据类型(如int、double、char等),也可以是对象类型(如另一个类的实例)。

  6. 作用:成员变量用于存储对象的状态信息,这些信息对于对象的行为是必要的。

成员变量的访问修饰符:

  • public:任何其他类都可以直接访问。
  • private:只能在定义它的类内部访问。
  • protected:可以在定义它的类及其子类中访问。
  • 默认(无修饰符):在同一个包中可以访问,但不同包的类不能访问。

示例:

public class Person {
    // 成员变量
    private String name; // 私有成员变量,只能通过getter和setter方法访问
    protected int age;   // 受保护的成员变量,可以在子类中访问
    public double height; // 公共成员变量,可以被任何其他类访问

    // 构造方法
    public Person(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    // getter和setter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 其他方法...
}

在这个Person类的例子中,nameageheight是成员变量,它们分别存储了一个人的姓名、年龄和身高。name成员变量是私有的,这意味着它不能被类的外部直接访问,只能通过公共的getNamesetName方法来访问和修改。age成员变量是受保护的,可以在类的子类中访问。height是公共的,可以被任何其他类访问。

成员变量是面向对象编程中实现数据封装和抽象的关键组成部分,它们允许对象保持自己的状态,并且可以在对象的生命周期内被其方法所操作。

成员方法


成员方法(也称为类方法或简单方法)是类的一部分,用于定义对象的行为。

成员方法的关键特点:

  1. 定义:成员方法是类中定义的函数,可以访问和操作类的成员变量。

  2. 作用域:成员方法的作用域是整个类体,这意味着它们可以访问类的所有成员变量和其它成员方法。

  3. 访问修饰符:与成员变量类似,成员方法也可以使用不同的访问修饰符来控制它们的可见性。

  4. 调用:成员方法可以通过对象实例调用,也可以在静态上下文中调用静态方法。

  5. 重载:类可以有多个同名的成员方法,只要它们的参数列表不同(方法重载)。

  6. 重写:子类可以重写(Override)父类的成员方法,以提供特定的实现。

  7. 构造方法:特殊的成员方法,用于初始化新创建的对象。它的名字必须与类名相同,并且没有返回类型。

  8. 静态方法:属于类的静态方法,可以通过类名直接调用,不需要创建对象实例。它们不能访问非静态成员变量或方法。

  9. 实例方法:非静态的成员方法,需要对象实例来调用,它们可以访问类的非静态成员变量和方法。

示例:

public class Car {
    // 成员变量
    private String color;
    private int speed;

    // 构造方法
    public Car(String color) {
        this.color = color;
        this.speed = 0;
    }

    // 实例方法
    public void start() {
        speed = 10; // 假设的初始速度
        System.out.println("Car started.");
    }

    // 实例方法,可以访问成员变量
    public void accelerate(int increment) {
        speed += increment;
        System.out.println("Car accelerated to " + speed + " km/h.");
    }

    // 实例方法,getter方法
    public String getColor() {
        return color;
    }

    // 实例方法,setter方法
    public void setColor(String color) {
        this.color = color;
    }

    // 静态方法,可以通过类名直接调用
    public static void printCarInfo() {
        System.out.println("Car info is available.");
    }
}

// 使用Car类
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car("Red"); // 创建Car对象实例
        myCar.start(); // 调用实例方法
        myCar.accelerate(5); // 调用实例方法并改变速度

        // 调用静态方法,不需要对象实例
        Car.printCarInfo();
    }
}

在这个Car类的例子中,startaccelerate是实例方法,它们可以访问和修改对象的状态(如speed)。getColorsetColor是实例方法,分别用于获取和设置color成员变量的值。printCarInfo是一个静态方法,它不依赖于任何对象实例,并且可以被类名直接调用。

成员方法是类定义对象行为的核心部分,它们使得对象能够执行动作和响应事件。

对象的实训化


构造器

默认构造器(无参)

默认构造器(Default Constructor),也称为无参构造器,是当程序员没有为类定义任何构造器时,编译器自动为该类生成的构造器。默认构造器没有参数,并且在创建类的实例时被调用,以初始化对象。

默认构造器特点:

  1. 自动生成:如果类中没有定义任何构造器,编译器会为该类提供一个无参的默认构造器。

  2. 无参数:默认构造器不接受任何参数。

  3. 初始化成员变量:它通常只是简单地初始化类的成员变量。如果成员变量有默认值,它们将被初始化为这些值;否则,它们将被初始化为类型的默认值(例如,对于整数是0,对于对象引用是null)。

  4. 调用父类的构造器:如果子类中的构造器没有显式地调用父类的构造器,Java会默认调用父类的无参构造器。

  5. 可以被覆盖:如果类中定义了其他构造器,编译器将不会生成默认构造器。

  6. 使用场景:当类的实例化不需要任何特定参数时,可以使用默认构造器。

示例:

假设我们有一个简单的Person类,没有定义任何构造器:

public class Person {
    private String name;
    private int age;

    // 其他方法...
}

在这个例子中,由于我们没有定义任何构造器,编译器将为Person类自动生成一个默认构造器。这个默认构造器将创建一个Person对象,其name属性被初始化为null,age属性被初始化为0(因为它们是引用类型和整型)。

如果我们创建Person类的实例:

public class Main {
    public static void main(String[] args) {
        Person person = new Person(); // 使用默认构造器创建实例
        // person.name 和 person.age 将分别被初始化为 null 和 0
    }
}

在这个Main类中,我们使用默认构造器创建了一个Person对象。由于没有显式定义构造器,编译器提供了一个无参构造器,该构造器将name初始化为null,将age初始化为0。

有参构造器

有参构造器(Parameterized Constructor)是类中定义的构造器,它接受一个或多个参数,用于在创建对象时初始化对象的状态。与默认构造器不同,有参构造器允许在实例化对象时提供具体的初始化数据。

有参构造器的特点:

  1. 初始化参数:有参构造器允许在创建对象时传递初始化参数,这些参数用于设置对象的状态。

  2. 重载:可以为类定义多个有参构造器,只要它们的参数列表不同(构造器重载)。

  3. 调用:创建对象时必须提供与构造器参数匹配的参数。

  4. 访问修饰符:有参构造器可以有访问修饰符,如publicprivate,以控制其可见性。

  5. 调用父类构造器:如果有参构造器需要调用父类的构造器,可以使用super关键字并传递相应的参数。

  6. 与默认构造器的关系:如果类中定义了有参构造器,编译器将不会自动生成默认构造器。如果需要无参构造器,必须显式定义。

示例:

假设我们有一个Person类,我们希望在创建Person对象时提供姓名和年龄:

public class Person {
    private String name;
    private int age;

    // 有参构造器
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 其他方法...
}

在这个例子中,Person类有一个有参构造器,它接受两个参数:nameage。当我们创建Person类的实例时,必须提供这两个参数:

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30); // 使用有参构造器创建实例
        // person 对象的 name 被初始化为 "Alice",age 被初始化为 30
    }
}

在这个Main类中,我们使用有参构造器创建了一个Person对象,并传递了姓名和年龄作为参数。这些参数被用来初始化新创建的Person对象的状态。

有参构造器是面向对象编程中初始化对象的常用方式,它使得对象在创建时就可以具有特定的属性值,从而避免了在对象创建后再单独设置每个属性的需要。

构造器重载

构造器重载(Constructor Overloading)是面向对象编程中的一个概念,它允许一个类拥有多个同名的构造器,但是它们的参数列表必须不同。这可以是不同的参数数量,不同的参数类型,或者两者的组合。构造器重载提供了创建具有不同初始化参数的对象的灵活性。

构造器重载的特点:

  1. 方法名相同:所有重载的构造器必须有相同的方法名,即类名。

  2. 参数列表不同:构造器的参数数量、类型或顺序至少有一项不同。

  3. 返回类型:构造器没有返回类型,甚至连void也没有。

  4. 访问修饰符:构造器可以有不同的访问修饰符,但通常默认为public

  5. 调用方式:根据提供的参数,调用相应的构造器来初始化对象。

  6. 编译器选择:编译时,编译器会根据提供的参数匹配相应的构造器。

  7. 与方法重载的关系:构造器重载与方法重载的原理相似,但构造器不涉及返回类型。

示例:

假设我们有一个Book类,我们想要提供几种不同的方式创建Book对象:

public class Book {
    private String title;
    private String author;
    private int year;

    // 无参构造器
    public Book() {
        this("Unknown Title", "Unknown Author", 0); // 默认值
    }

    // 有参构造器1:只提供书名和作者
    public Book(String title, String author) {
        this(title, author, 0); // 假设年份为0
    }

    // 有参构造器2:提供书名、作者和年份
    public Book(String title, String author, int year) {
        this.title = title;
        this.author = author;
        this.year = year;
    }

    // 其他方法...
}

在这个Book类的例子中,我们定义了三个构造器,它们都有相同的方法名Book,但参数列表不同:

  • 第一个构造器是无参构造器,使用默认值初始化Book对象。
  • 第二个构造器接受两个参数(书名和作者),并假设年份为0。
  • 第三个构造器接受三个参数(书名、作者和年份),用于完全初始化Book对象。

我们可以这样使用这些构造器:

public class Main {
    public static void main(String[] args) {
        Book book1 = new Book(); // 使用无参构造器
        Book book2 = new Book("1984", "George Orwell"); // 使用有参构造器1
        Book book3 = new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925); // 使用有参构造器2
    }
}

在这个Main类中,我们根据需要创建了三个不同的Book对象,每个对象都使用了不同的构造器。构造器重载使得Book类非常灵活,可以根据提供的信息创建出不同初始化状态的对象。

对象的使用


对象的使用是面向对象编程(OOP)的核心部分,它涉及到创建对象、访问对象的属性和调用对象的方法。

基本步骤和概念:

  1. 创建对象
    使用new关键字和类的构造器来创建对象。例如,如果你有一个Person类,你可以这样创建一个Person对象:

    Person person = new Person("Alice", 30);
    
  2. 访问对象属性
    通过对象引用和点(.)操作符来访问对象的属性。如果Person类有nameage属性,你可以这样访问它们:

    String name = person.name; // 如果name是public的
    int age = person.age;      // 如果age是public的
    
  3. 调用对象方法
    使用对象引用和点操作符来调用对象的方法。如果Person类有一个greet()方法,你可以这样调用它:

    person.greet(); // 假设greet()是一个public的实例方法
    
  4. 修改对象状态
    通过调用对象的setter方法来修改对象的状态。例如,如果Person类有一个setName(String name)方法,你可以这样修改name属性:

    person.setName("Bob");
    
  5. 对象作为参数传递
    对象可以作为参数传递给方法。例如:

    void displayPersonInfo(Person person) {
        System.out.println("Name: " + person.name);
        // ...
    }
    
  6. 对象作为返回值
    方法可以返回对象。例如,如果有一个方法返回Person对象:

    Person getPerson() {
        return new Person("Charlie", 25);
    }
    
  7. 对象的生命周期
    对象的生命周期从它被创建时开始,直到它不再被使用。在Java中,对象通常由垃圾收集器回收。

  8. 对象的封装
    对象通常封装了数据和行为,隐藏了内部实现细节,只暴露必要的接口。

  9. 对象的多态性
    对象可以被看作是多种形态的,可以通过接口或继承实现多态性。例如,一个方法可以接收不同类型的对象,只要它们都实现了相同的接口或继承自同一个类。

  10. 对象的集合
    对象可以存储在数组或集合中,以便进行批量操作。

示例:

假设我们有一个Car类,我们想要创建一个Car对象,使用它,并在适当的时候销毁它:

public class Car {
    private String model;
    private String color;

    public Car(String model, String color) {
        this.model = model;
        this.color = color;
    }

    public void start() {
        System.out.println(model + " starts.");
    }

    public void stop() {
        System.out.println(model + " stops.");
    }

    // 其他方法...
}

public class Main {
    public static void main(String[] args) {
        // 创建Car对象
        Car myCar = new Car("Toyota", "Red");

        // 使用Car对象
        myCar.start(); // 输出: Toyota starts.
        myCar.stop();  // 输出: Toyota stops.

        // 当不再需要Car对象时,它将被垃圾收集器回收
    }
}

在这个示例中,我们创建了一个Car对象,并调用了它的start()stop()方法。对象的使用涉及到创建、操作和销毁对象的整个生命周期。

对象的销毁


GC垃圾回收器

GC(Garbage Collection,垃圾回收)是许多编程语言中用于自动管理内存的机制,特别是在那些提供自动内存管理的语言中,如Java、C#、Python等。垃圾回收器的主要任务是识别和回收程序不再使用的对象,从而释放内存资源,防止内存泄漏。

垃圾回收器的特点:

  1. 自动内存管理:GC自动释放不再被引用的对象所占用的内存。

  2. 内存泄漏防护:通过定期清理不再使用的对象,GC有助于防止内存泄漏。

  3. 引用跟踪:GC通过跟踪对象引用来确定哪些对象仍然被程序所使用。

  4. 回收算法:不同的垃圾回收器使用不同的算法来识别和回收垃圾对象,如标记-清除、复制、标记-整理等。

  5. 性能影响:虽然GC可以减少内存管理的负担,但它也可能对程序性能产生影响,尤其是在GC运行期间。

  6. 暂停时间:某些GC算法可能会导致应用程序暂停,以便进行内存清理。

  7. 配置和调优:在某些语言中,开发者可以对GC的行为进行配置和调优,如设置堆大小或调整GC策略。

  8. 分代收集:许多GC实现采用分代收集策略,将对象分为新生代和老年代,并根据对象的生命周期特点采用不同的回收策略。

  9. 并发和并行:现代GC实现可能采用并发或并行的方式执行,以减少对应用程序性能的影响。

  10. 弱引用和软引用:GC还处理弱引用和软引用,这些引用不会阻止对象被回收,但可以延迟对象的回收。

示例:

在Java中,你不需要手动释放对象所占用的内存,因为JVM的GC会自动进行这项工作。以下是一个简单的Java示例,演示了对象的创建和GC的作用:

public class Main {
    public static void main(String[] args) {
        // 创建一个对象
        SomeObject obj = new SomeObject();

        // 当obj不再被引用时,它将成为GC的候选对象
        obj = null;

        // 此时,GC可能会在下一次运行时回收obj所占用的内存
    }
}

class SomeObject {
    // ...
}

在这个示例中,SomeObject的实例被创建并赋值给obj变量。当obj被赋值为null时,这个对象就不再有任何引用指向它,因此它变成了垃圾回收的候选对象。在某个时间点,JVM的GC会识别这个对象不再被使用,并释放它占用的内存。

开发者通常不需要直接与GC交互,但了解GC的工作原理和性能特性对于编写高效、稳定的应用程序是非常重要的。

匿名对象


匿名对象(Anonymous Objects)是在创建时没有明确名称的对象。在面向对象编程中,匿名对象通常用于临时使用对象,并且不需要长期存储引用的情况。

匿名对象的特点:

  1. 无名称:匿名对象在创建时没有名称,因此不能被长期存储或引用。

  2. 立即使用:匿名对象通常在创建后立即使用,然后被丢弃。

  3. 构造器调用:匿名对象的创建是通过调用其构造器完成的,但不会显式地使用new关键字和类名。

  4. 常用于回调:匿名对象经常用作回调,例如,在需要实现接口或继承类的匿名内部类中。

  5. 单次方法调用:匿名对象通常用于只需要单次调用的方法,例如,实现Runnable接口来创建一个线程。

  6. 简化代码:在某些情况下,使用匿名对象可以简化代码,避免创建额外的类。

  7. 生命周期短:匿名对象的生命周期通常很短,它们在执行完毕后就会被垃圾回收器回收。

  8. 不能被重新赋值:由于匿名对象没有名称,它们不能被重新赋值给其他引用。

示例:

示例1:使用匿名对象创建线程
// 创建并启动一个线程,使用匿名对象实现Runnable接口
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Thread is running!");
    }
});
thread.start();
示例2:使用匿名对象作为方法参数
// 使用匿名对象作为方法参数,例如,给某个按钮设置点击事件监听器
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        System.out.println("Button was clicked!");
    }
});

示例3:使用匿名对象调用方法

// 直接使用匿名对象调用方法,例如,打印一个简单的信息
new Object() {
    void printMessage() {
        System.out.println("Hello, World!");
    }
}.printMessage();

在这些示例中,我们没有显式地使用new关键字和类名来创建对象。相反,我们直接提供了构造器的参数,并在需要时立即调用对象的方法。这种方式在编写一次性使用的代码片段时非常有用,可以减少代码的复杂性。

posted @ 2024-08-01 10:50  墨澜  阅读(31)  评论(0编辑  收藏  举报