类和对象
1.面向对象与面向过程
面向对象(Object Oriented Programming, OOP)与面向过程(Procedure Oriented Programming, POP)是两种不同的编程范式,它们在编程思想、特点、优势及应用场景等方面存在显著差异。
一、编程思想
- 面向过程:
- 以过程为中心,关注于“做什么”,即解决问题的步骤。它将问题分解成一系列详细的步骤,然后通过函数或过程来实现这些步骤,并依次调用。
- 面向对象:
- 以对象为中心,关注于“谁来做”,即对象在解决问题中的角色和行为。它将构成问题的事物分解成各个对象,通过对象之间的调用和协作来解决问题。
二、特点
- 面向过程:
- 适合解决简单问题,不需要过多的协作和抽象。
- 关注问题的解决步骤而不是问题的本质。
- 代码复用性低,扩展性差,不易维护。
- 只有封装,没有继承和多态。
- 面向对象:
- 适合解决复杂问题,需要多方的协作和抽象。
- 关注问题的本质,通过对象来描述和解决问题。
- 代码复用性高,扩展性好,易于维护。
- 具有封装、继承、多态三大特性,提供高度的灵活性、可维护性和扩展性。
三、优势
- 面向过程:
- 性能较好,因为类调用时需要实例化,开销较大。
- 在某些对性能要求极高且逻辑相对简单的场景(如单片机、嵌入式开发)中更为适用。
- 面向对象:
- 易于理解和维护,因为对象模型更接近现实世界,使得代码更加直观。
- 易于复用和扩展,通过封装、继承和多态等特性,可以实现代码的模块化、通用化和可重用性。
- 提高了开发效率和质量,降低了维护成本。
四、应用场景
- 面向过程:
- 更适合于那些逻辑相对简单、不需要过多抽象和协作的场景。例如,一些小型工具软件或脚本程序。
- 面向对象:
- 更适合于大型软件系统、GUI应用程序、游戏开发等复杂场景。在这些场景中,通过面向对象的方法可以构建出更加清晰、模块化和易于维护的系统结构。
五、总结
面向对象和面向过程是两种不同的编程范式,各有其优势和适用场景。在实际开发中,应根据项目的具体需求和特点来选择合适的编程范式。随着软件规模和复杂度的不断增加,面向对象的方法因其高度的灵活性和可维护性而逐渐成为主流。
2.类与对象的概念
2.1.类与对象的定义
在Java中,类和对象是面向对象编程(OOP)的核心概念。它们之间的关系可以理解为“蓝图”和“实例”的关系。
类(Class)
类是对象的蓝图或模板,它定义了对象应该有的属性和方法。类是一种抽象的数据类型,它描述了具有相同属性和方法的一组对象的集合。通过类,我们可以创建具有特定属性和行为的对象。
类的定义
在Java中,使用class
关键字来定义类。类的定义包括类名、属性(也称为字段或变量)和方法。类名通常是大写字母开头的驼峰命名法(CamelCase)。
class Person {
// 属性
String name;
int age;
// 方法
void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
对象(Object)
对象是类的实例。每个对象都是类的一个具体实体,具有类定义的属性和方法。对象之间的属性可以不同,但它们的行为(方法)是相同的。
创建对象
在Java中,使用new
关键字来创建对象。new
关键字后面跟着类名,并且需要调用构造器(constructor)来初始化对象。构造器是一种特殊的方法,它的名字与类名相同,没有返回类型(包括void
)。
Person person1 = new Person();
person1.name = "Alice";
person1.age = 30;
person1.introduce(); // 输出:Hello, my name is Alice and I am 30 years old.
// 如果类中有构造器,可以直接在创建对象时初始化属性
class PersonWithConstructor {
String name;
int age;
// 构造器
PersonWithConstructor(String name, int age) {
this.name = name;
this.age = age;
}
void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
PersonWithConstructor person2 = new PersonWithConstructor("Bob", 25);
person2.introduce(); // 输出:Hello, my name is Bob and I am 25 years old.
- 类是对象的蓝图,定义了对象的属性和方法。
- 对象是类的实例,具有类定义的属性和方法。
- 使用
class
关键字定义类,使用new
关键字和构造器创建对象。 - 类和对象的关系是“蓝图”和“实例”的关系。
2.2.成员变量与成员方法
在Java中,成员变量(也称为属性或字段)和成员方法(也称为函数或行为)是类的重要组成部分,它们共同定义了类的状态和行为。
成员变量
成员变量是类中定义的变量,用于存储类的状态信息。成员变量可以是任何数据类型,包括基本数据类型(如int、float、char等)和引用数据类型(如String、自定义类类型等)。成员变量在类的所有实例之间共享其声明(但不共享其值,除非它们是静态的),但每个实例(即对象)都有自己独立的成员变量副本。
成员变量的特点:
- 成员变量在类内部定义,但在方法外部。
- 它们可以是任何合法的数据类型。
- 成员变量有默认值,这取决于它们的数据类型(例如,int的默认值是0,boolean的默认值是false)。
- 可以通过创建类的对象来访问和修改非静态成员变量的值。
- 静态成员变量(使用
static
关键字声明的)属于类本身,而不是类的任何特定实例,因此所有实例共享同一个静态成员变量的值。
成员方法
成员方法是类中定义的函数,用于执行特定的操作或任务。成员方法可以访问类的成员变量,也可以被其他方法调用。方法定义了如何执行某些操作,包括接收输入参数(如果有的话)、执行操作以及返回结果(如果有的话)。
成员方法的特点:
- 成员方法在类内部定义,它们可以访问类的成员变量。
- 方法可以接收输入参数,这些参数在方法体内部作为局部变量使用。
- 方法可以返回一个值给调用者,但这不是强制性的(即,方法可以有void返回类型,表示不返回任何值)。
- 成员方法可以被类的其他方法调用,也可以被类的对象调用。
- 静态方法(使用
static
关键字声明的)属于类本身,而不是类的任何特定实例。它们可以直接通过类名调用,而无需创建类的实例。
示例
public class Person {
// 成员变量
String name;
int age;
// 成员方法
void setName(String name) {
this.name = name; // 使用this关键字引用当前对象的成员变量
}
void setAge(int age) {
this.age = age;
}
void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
// 静态成员方法
public static void main(String[] args) {
Person person = new Person();
person.setName("Alice");
person.setAge(30);
person.introduce(); // 输出:Hello, my name is Alice and I am 30 years old.
}
}
在这个例子中,Person
类有两个成员变量name
和age
,以及三个成员方法setName
、setAge
和introduce
。main
方法是一个特殊的静态成员方法,它是程序的入口点。注意,尽管main
方法是静态的,但它仍然可以创建Person
类的实例并调用其非静态成员方法。
与静态变量和静态方法的区别
静态变量、静态方法与成员变量、成员方法在Java中存在显著的区别,主要体现在它们的定义、作用域、访问方式以及生命周期等方面。以下是对这些区别的详细阐述:
静态变量与成员变量的区别
静态变量 | 成员变量 | |
---|---|---|
定义 | 使用static 关键字修饰的变量 |
类中定义的普通变量,不需要static 修饰 |
作用域 | 属于类本身,不属于任何对象实例 | 属于类的实例,每个对象实例都有自己的一份拷贝 |
访问方式 | 可以通过类名直接访问,也可以通过对象实例访问 | 必须通过对象实例来访问 |
生命周期 | 在类加载到JVM时创建,随着类的卸载而销毁 | 在创建对象实例时创建,随着对象实例的销毁而销毁 |
内存分配 | JVM只为静态变量分配一份内存空间,所有对象实例共享这份内存 | 每个对象实例都会为成员变量分配独立的内存空间 |
示例 | public static int count = 0; |
public int age; |
静态方法与成员方法的区别
静态方法 | 成员方法 | |
---|---|---|
定义 | 使用static 关键字修饰的方法 |
类中定义的普通方法,不需要static 修饰 |
作用域 | 属于类本身,与类的实例无关 | 属于类的实例 |
访问方式 | 可以通过类名直接调用,也可以通过对象实例调用(但后者会隐藏类名调用) | 必须通过对象实例来调用 |
访问权限 | 与成员变量的访问权限相同,可以使用public、private、protected修饰 | 同样可以使用public、private、protected修饰 |
访问范围 | 只能访问类的静态成员变量和静态方法,不能直接访问非静态成员变量和非静态方法 | 可以访问类的所有成员变量和方法(包括静态和非静态) |
示例 | public static void showMessage() {...} |
public void displayInfo() {...} |
总结
- 静态变量和静态方法:它们属于类本身,与类的实例无关。静态变量在类加载时初始化,只分配一份内存空间,所有对象实例共享。静态方法可以通过类名直接调用,无需创建对象实例。静态方法只能访问静态成员变量和静态方法。
- 成员变量和成员方法:它们属于类的实例。每个对象实例都有自己独立的成员变量拷贝,成员方法必须通过对象实例来调用。成员方法可以访问类的所有成员变量和方法(包括静态和非静态)。
这些区别使得静态成员(变量和方法)在不需要对象实例时就能被访问和使用,而成员变量和方法则依赖于对象实例的存在。
2.3.对象的实例化
在Java中,对象的实例化是指创建类的实例(即对象)的过程。这个过程涉及到为对象分配内存空间,并可以初始化其成员变量的值。实例化对象通常通过new
关键字来完成,它会在堆内存中为对象分配足够的空间,并返回该对象的引用。
对象实例化的步骤
- 声明引用变量:首先,你需要声明一个与类类型相匹配的引用变量。这个变量将用于引用类的对象。
- 使用
new
关键字创建对象:通过new
关键字调用类的构造器(constructor)来创建对象。构造器是一种特殊的方法,它用于初始化新创建的对象。如果类中没有显式定义构造器,则Java编译器会自动提供一个无参的默认构造器。 - 将对象的引用赋值给引用变量:
new
关键字调用构造器后,会返回新创建对象的引用。这个引用可以赋值给之前声明的引用变量。
示例
假设我们有一个名为Person
的类,它有两个成员变量name
和age
,以及相应的构造器和introduce
方法。
public class Person {
String name;
int age;
// 构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法
public void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
public class Main {
public static void main(String[] args) {
// 步骤1:声明引用变量
Person person;
// 步骤2&3:使用new关键字创建对象,并将引用赋值给变量
person = new Person("Alice", 30);
// 使用对象调用成员方法
person.introduce(); // 输出:Hello, my name is Alice and I am 30 years old.
}
}
在这个示例中,Person
类的实例是通过new Person("Alice", 30)
创建的,并将返回的引用赋值给了person
变量。然后,我们就可以通过person
变量来访问和修改Person
对象的成员变量,或者调用它的成员方法了。
注意事项
- 在Java中,引用变量和对象本身是分开的。引用变量只是一个指向对象的指针(或者说是一个地址)。
- 如果引用变量没有被显式地指向一个对象,那么它的默认值是
null
。尝试在引用变量为null
的情况下调用对象的成员方法或访问成员变量会导致NullPointerException
。 - 对象存储在堆内存中,而引用变量(以及局部变量和基本数据类型变量)通常存储在栈内存中。但是,这种内存分配方式对于Java程序员来说是透明的,你不需要(也不应该)直接操作内存。
2.4.对象的使用
在Java中,对象的使用是面向对象编程(OOP)的核心部分。对象是基于类的实例,它们具有状态(成员变量)和行为(成员方法)。以下是Java中对象使用的一些基本步骤和概念:
2.4.1. 定义类
首先,你需要定义一个类,它描述了对象的结构。类包含成员变量(属性)和成员方法(行为)。
public class Person {
String name; // 成员变量
int age;
// 构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法
public void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
2.4.2. 创建对象
使用new
关键字和类的构造器来创建类的实例(即对象)。new
关键字会调用构造器来初始化对象,并返回对象的引用。
java复制代码
Person person = new Person("Alice", 30);
这里,person
是一个引用变量,它引用了新创建的Person
对象。
2.4.3. 访问成员变量和方法
通过对象引用,你可以访问对象的成员变量(通常通过getter和setter方法)和调用其成员方法。
直接访问成员变量(不推荐,因为破坏了封装性)
java复制代码
System.out.println(person.name); // 直接访问,但通常不推荐这样做
使用getter和setter方法访问和修改成员变量
// 假设有getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 使用getter方法
System.out.println(person.getName());
// 使用setter方法
person.setName("Bob");
调用成员方法
java复制代码
person.introduce(); // 调用introduce方法
2.4.4. 对象的生命周期
对象的生命周期从它被创建开始,到它不再被任何引用变量引用,且垃圾回收器回收其占用的内存时结束。
2.4.5. 对象的比较
在Java中,对象之间的比较通常不是通过==
操作符完成的,因为==
比较的是引用变量的值(即它们是否指向堆内存中的同一个对象)。要比较两个对象的内容是否相等,你需要覆盖equals
方法(和hashCode
方法,以保持一致性)。
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
2.4.6. 对象的克隆
如果你需要创建一个与现有对象内容相同但引用不同的新对象,你可以实现Cloneable
接口并重写clone
方法。
结论
Java中对象的使用是面向对象编程的基础。通过定义类、创建对象、访问成员变量和方法,你可以构建出功能丰富、易于维护和扩展的程序。同时,了解对象的生命周期、比较和克隆也是编写高质量Java代码的重要部分。
2.5.对象的销毁
在Java中,对象的销毁不是由程序员直接控制的,而是由Java的垃圾回收机制(Garbage Collection, GC)自动管理的。当对象不再被任何引用变量所引用时,即没有任何指向该对象的引用时,该对象就被视为垃圾(垃圾对象),并会在某个不确定的时间点被垃圾回收器回收,从而释放其所占用的内存空间。
垃圾回收的基本概念
- 可达性分析:Java使用可达性分析算法来判断对象是否存活。从一系列称为“GC Roots”的对象(如静态属性引用的对象、活跃线程中的局部变量等)作为起始点,从这些节点开始向下搜索,所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(即从GC Roots到这个对象不可达)时,则证明此对象是不可用的。
- 垃圾回收时机:Java的垃圾回收器会在JVM的堆内存不足时自动运行,但也可以手动请求JVM进行垃圾回收(通过调用
System.gc()
或Runtime.getRuntime().gc()
),但需要注意的是,这仅仅是一个建议,JVM可以忽略这个请求。 - 垃圾回收方式:Java提供了多种垃圾回收算法,如标记-清除(Mark-Sweep)、复制(Copying)、标记-整理(Mark-Compact)、分代收集(Generational Collection)等,不同的垃圾回收器可能会采用不同的算法。
对象销毁的注意事项
- 避免内存泄漏:虽然Java有垃圾回收机制,但如果不当使用(如长生命周期的对象持有短生命周期对象的引用),仍然可能导致内存泄漏。内存泄漏指的是程序中已分配的内存由于某种原因程序未释放或无法释放,造成内存的浪费,导致程序运行速度减慢甚至系统崩溃。
- 显式释放资源:对于非内存资源(如文件描述符、数据库连接等),Java的垃圾回收机制无法自动回收。因此,在不再需要这些资源时,应该显式地释放它们,通常是通过调用资源提供者的
close()
或dispose()
等方法。 - finalize()方法:在Java中,
Object
类提供了一个finalize()
方法,该方法在垃圾回收器决定回收某对象之前被调用。但是,finalize()
方法的使用已经被弃用(在Java 9中),因为它会增加垃圾回收的复杂性和不确定性,而且性能较差。因此,不推荐使用finalize()
方法进行资源的清理工作。
结论
在Java中,对象的销毁是由垃圾回收机制自动完成的,程序员不需要(也不应该)直接干预这个过程。但是,程序员需要关注内存泄漏问题,并确保在不再需要时显式释放非内存资源。同时,也要注意避免使用已被弃用的finalize()
方法。
2.6.匿名对象
在Java中,匿名对象(Anonymous Object)是指在创建对象时不显式地将其引用赋值给变量,而是直接使用该对象的方法或属性。由于这种对象没有引用变量与之关联,因此它们只能被使用一次,并且在当前表达式结束后就会被垃圾回收器回收。
匿名对象通常用于只需要对象一次调用的场景,这样可以避免创建不必要的引用变量,减少内存占用。
匿名对象的创建
匿名对象的创建方式很简单,就是在使用new
关键字创建对象的同时,直接调用该对象的方法或访问其属性,而不是将对象的引用赋值给一个变量。
示例
假设我们有一个Person
类,它有一个introduce
方法:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void introduce() {
System.out.println("Hello, my name is " + name);
}
}
使用匿名对象的方式如下:
java复制代码
new Person("Alice").introduce(); // 创建一个Person对象并立即调用其introduce方法
在这个例子中,我们没有将new Person("Alice")
的返回值(即新创建的Person
对象的引用)赋值给任何变量。相反,我们直接调用了该对象的introduce
方法。一旦introduce
方法执行完毕,由于没有引用变量指向这个Person
对象,它就无法再被访问,并且很快就会被垃圾回收器回收。
匿名对象的用途
匿名对象主要用于以下几种情况:
- 单次调用:当你只需要使用对象一次时,使用匿名对象可以避免创建不必要的引用变量。
- 简化代码:在某些情况下,使用匿名对象可以使代码更加简洁。
- 传递参数:当需要将新创建的对象作为参数传递给方法时,如果不需要在方法外部引用该对象,可以使用匿名对象。
然而,需要注意的是,过度使用匿名对象可能会使代码的可读性降低,特别是当对象创建过程中涉及复杂的初始化逻辑时。因此,在决定是否使用匿名对象时,需要权衡代码的可读性和简洁性。
标签:Java,变量,对象,成员,实例,方法,中类,name From: https://www.cnblogs.com/tubby233/p/18336010