第一章 类和对象
1. 面向对象的介绍
-
面向对象编程的核心思想:将现实世界的事物抽象为程序中的类和对象,强调数据和行为的封装。
-
面向对象与面向过程的对比:
-
面向过程关注 “过程” 和 “步骤”,适合简单任务。
-
面向对象关注 “对象” 和 “行为”,更贴合现实世界建模。
-
-
面向对象的三大特性:封装、继承、多态。
2. 类和对象
2.1 类 (实体类) _class
-
定义:
类是对一类事物的抽象,描述其共有的属性和行为。
定义类的基本语法:public class ClassName {// 属性 (成员变量)数据类型 属性名;// 方法返回类型 方法名(参数列表) {// 方法体} }
-
类的组成部分:
- 属性(成员变量):描述这一类事物的特性。
- 定义位置:类中,方法外。
- 作用范围:作用于当前类的所有非静态方法和代码块。
- 定义格式:
数据类型 变量名;
- 默认值:
- 整数类型:
0
- 浮点类型:
0.0
- 字符类型:
'\u0000'
- 布尔类型:
false
- 引用类型:
null
- 整数类型:
- 行为(成员方法):描述这一类事物可以执行的操作。
- 定义方法的方式:去掉方法中的
static,其余保持不变。 - 构造器:用于创建对象并初始化属性。
- 内部类:定义在类内部的类,可以分为静态内部类和非静态内部类。
- 静态成员:使用
static
修饰的属性或方法,可以直接通过类名访问。
- 属性(成员变量):描述这一类事物的特性。
2.2 对象
1. 概述
对象是类的实例化,是类的具体体现。一个类可以通过创建多个对象,每个对象都拥有类定义的属性和行为。
2. 如何创建对象
创建对象的语法格式:
类名 对象名 = new 类名();
例如:
Person person = new Person(); // 创建一个 Person 类的对象
3. 使用对象
-
成员访问:
使用对象名 +.
来访问对象的成员(属性和方法):对象名.成员变量; 对象名.方法名();
例如,创建一个
Person
对象,并访问其成员:person.name = "Hello Java !"; // 访问并修改属性 person.age = 24; person.method01(); // 调用方法method01 person.method02(); // 调用方法method02
4. 类和对象的关系
- 类:是对一类事物的抽象,定义了该类事物的属性和行为。
- 对象:是类的实例化,每个对象都具有类定义的属性和行为。
5. 导包
- 如果两个类在同一个包下,互相使用成员时不需要导包。
- 如果两个类不在同一个包下,想要使用对方的成员,需要导包。可以通过
import
语句导入类:import 包名.类名;
- 特殊包:
java.lang
包中的类(如String
、System
等)不需要显式导入。
6. 代码示例
同一包内的两个类
① Java类: Person.java
// Person类:定义了属性和行为
public class Person {// 属性(成员变量)String name;int age;// 行为(成员方法)public void method01() {System.out.println("行为一");}public void method02() {System.out.println("行为二");}
}
② Java类: DemoPerson.java
// DemoPerson类:用来创建Person对象并调用其成员
public class DemoPerson {public static void main(String[] args) {// 创建一个 Person 对象Person person = new Person();// 访问并打印属性值(默认值)System.out.println(person.name); // nullSystem.out.println(person.method02); // 0// 修改属性值person.name = "Hello Java !";person.age = 24;// 打印修改后的属性值System.out.println(person.name); // Hello Java !System.out.println(person.age); // 24// 调用对象的方法person.method01(); // 行为一person.method02(); // 行为二}
}
3. 匿名对象的使用
定义:匿名对象是没有引用变量指向的对象,常用于一次性调用。
(1)什么是匿名对象?
匿名对象是指在 Java 中没有显式声明对象变量的对象。换句话说,匿名对象就是没有名字的对象,只在创建时立即使用。与普通对象不同,匿名对象通常没有引用变量来存储对象的引用,因此它们不能被多次引用或访问。
匿名对象的创建通常通过 new
关键字来实例化类,但没有给它指定变量名。
new 类名(); // 匿名对象的创建
(2) 匿名对象的示例
假设我们有一个 Person
类:
public class Person {String name;int age;// 方法:展示个人信息public void showInfo() {System.out.println("Name: " + name + ", Age: " + age);}
}
使用匿名对象来创建并直接调用 showInfo()
方法:
public class Test {public static void main(String[] args) {// 创建匿名对象并直接调用方法new Person().showInfo();}
}
在这个例子中,我们没有为 Person
对象指定变量名,而是直接在创建对象后调用了 showInfo()
方法。匿名对象直接用在方法调用中,创建之后立刻使用,并且在使用完之后就会被销毁。
(3)匿名对象的使用场景
匿名对象常见于以下几种场景:
- 简化代码:当不需要反复引用对象时,可以使用匿名对象来减少代码量。
- 仅用于方法调用:如果对象只是为了调用某个方法,且无需后续使用,可以直接使用匿名对象。
- 临时对象:匿名对象在程序中只使用一次,一旦方法调用完成,对象就没有任何引用,因此它会被垃圾回收。
① 匿名对象用于方法调用
匿名对象可以用在方法参数中,传递给方法,避免了为对象创建额外的变量。
public class Test {public static void main(String[] args) {// 传递匿名对象给方法printPerson(new Person());}public static void printPerson(Person person) {person.showInfo();}
}
在这个例子中,new Person()
是匿名对象,它被传递给 printPerson
方法。无需在主方法中声明一个变量来存储该对象。
② 匿名对象用于事件监听器
匿名对象常常用于事件监听器的实现。例如,在图形界面编程(如 Swing)中,我们可以直接在事件源(如按钮)上使用匿名对象来处理事件:
import java.awt.*;
import java.awt.event.*;public class ButtonTest {public static void main(String[] args) {Frame frame = new Frame("匿名对象示例");Button button = new Button("点击我");// 使用匿名对象处理按钮点击事件button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("按钮被点击了");}});frame.add(button);frame.setSize(300, 200);frame.setVisible(true);}
}
在这个例子中,我们没有为 ActionListener
创建一个单独的类或对象,而是直接创建了一个匿名对象来处理按钮点击事件。
(4)匿名对象的优缺点
① 优点
- 减少代码量:使用匿名对象可以避免声明和定义不必要的变量,代码更简洁。
- 提高代码可读性:当对象只使用一次时,直接使用匿名对象能使代码更直观,减少冗余。
- 提高开发效率:在不需要对象引用的情况下,使用匿名对象能快速实现某些操作,避免了多余的类和变量定义。
② 缺点
- 不可重复使用:由于匿名对象没有显式的引用变量,它们只能在创建时使用一次,不能重复引用。如果需要多次操作该对象,必须重新创建对象。
- 难以调试:匿名对象没有名称,这使得在调试时追踪对象和其状态可能更加困难。
(5)匿名对象与普通对象的比较
特点 | 普通对象 | 匿名对象 |
---|---|---|
是否有名称 | 有名称 | 无名称 |
使用方式 | 可通过变量名多次访问 | 只能访问一次 |
代码清晰度 | 需要额外的变量声明 | 代码简洁,减少不必要的声明 |
内存占用 | 需要存储变量的引用 | 不需要存储引用,直接创建并销毁 |
(6) 结论
匿名对象是 Java 中不需要命名的对象,通常通过 new
关键字创建,适用于临时任务或方法调用。它们简化代码,特别是当对象只使用一次时。常见的应用场景包括事件监听和方法调用。匿名对象能有效减少代码量、提高开发效率。但由于无法重复使用且调试较为困难,实际开发中应根据具体情况权衡使用。
⭐匿名对象无法重复使用,适合简单逻辑
4. 一个对象的内存图
在 Java 中,每次创建一个对象时,JVM 会在 堆内存 中为该对象分配空间。每个对象的内存分配包含多个部分:
- 对象头:存储对象的元数据(如类型信息、GC 信息等)。
- 实例数据:对象的实例变量(属性),这些值根据类的定义不同而有所不同。
- 对齐填充:根据虚拟机的要求,内存中的某些字段可能需要填充一定的字节数,以保持内存对齐。
内存图示例
假设我们有一个简单的 Person
类,其中有两个成员变量:name
和 age
。
public class Person {String name;int age;
}
当我们创建一个 Person
对象时,内存分布如下所示:
+--------------------+
| 对象头 | <- 存储该对象的元信息(如对象类型、GC信息等)
+--------------------+
| name(引用类型) | <- 这里存储的是 `name` 的引用(即指向 `name` 对象的内存地址)
+--------------------+
| age (基本类型) | <- 这里存储的是 `age` 的值
+--------------------+
对象的生命周期:
- 当对象创建时,JVM 会在堆内存中分配一块内存空间。
- 当对象不再被使用时,垃圾回收器会回收这块内存空间,释放资源。
5. 两个对象的内存图
如果我们创建多个对象,每个对象都会在堆内存中独立分配内存空间。即使它们属于同一个类,每个对象都有自己的实例数据。
假设我们创建两个 Person
对象:
Person person1 = new Person();
Person person2 = new Person();
内存图将如下所示:
+--------------------+ +--------------------+
| 对象头 | | 对象头 |
+--------------------+ +--------------------+
| name(引用类型) | | name(引用类型) |
+--------------------+ +--------------------+
| age (基本类型) | | age (基本类型) |
+--------------------+ +--------------------+person1 person2
在这种情况下,person1
和 person2
是两个独立的对象,它们各自拥有自己独立的内存区域,存储着不同的 name
和 age
数据。
6. 两个对象指向同一块内存空间
如果我们让两个对象引用同一个对象实例,内存图就会有所不同。在这种情况下,两个变量会共享同一块堆内存区域。
Person person1 = new Person();
Person person2 = person1; // person2 引用 person1,指向同一个对象
内存图如下所示:
+--------------------+
| 对象头 | <- 共享的对象头,两个引用指向同一个对象
+--------------------+
| name (引用类型) |
+--------------------+
| age (基本类型) |
+--------------------+| || |
person1 person2
此时,person1
和 person2
都指向同一个 Person
对象,它们共享相同的内存空间。因此,修改 person1
的属性,person2
也会看到这些变化。
代码示例
让我们通过一些简单的代码示例来加深理解。
一个对象的内存图:
public class Person {String name;int age;
}public class Test {public static void main(String[] args) {Person person1 = new Person(); // 创建一个对象person1.name = "Alice";person1.age = 25;}
}
两个对象的内存图:
public class Test {public static void main(String[] args) {Person person1 = new Person(); // 创建第一个对象Person person2 = new Person(); // 创建第二个对象person1.name = "Alice";person2.name = "Bob";}
}
两个对象指向同一块内存:
public class Test {public static void main(String[] args) {Person person1 = new Person(); // 创建一个对象Person person2 = person1; // person2 引用 person1 指向同一个对象person1.name = "Alice";System.out.println(person2.name); // 输出 Alice,因为 person2 和 person1 是同一个对象}
}
第二章. 成员变量和局部变量的区别
在 Java 编程中,成员变量和局部变量是两种常见的变量类型。它们在作用范围、内存分配和生命周期等方面有很大不同。理解这些区别对编写高效、清晰的代码至关重要。
1. 定义位置
- 成员变量:定义在类中方法外部,属于类的实例或静态类。
- 局部变量:定义在方法内部或者方法的参数列表中,仅在方法内部有效。
public class Example {// 成员变量int memberVar;public void method() {// 局部变量int localVar = 10;}
}
2. 初始化值
- 成员变量:有默认值。例如,
int
类型的成员变量默认值为0
,boolean
类型的成员变量默认值为false
,Object
引用类型的成员变量默认值为null
。 - 局部变量:没有默认值,必须在使用前显式赋值,否则编译器会报错。
public class Example {// 成员变量int memberVar; // 默认值为 0public void method() {// 局部变量int localVar; // 没有默认值,必须赋值才能使用// System.out.println(localVar); // 编译错误,localVar 未初始化}
}
3. 作用范围
- 成员变量:作用于整个类,可以被该类的所有方法访问。
- 局部变量:只在其所在的方法或构造函数中有效,方法执行完毕后,局部变量会被销毁,其他方法无法访问。
public class Example {// 成员变量int memberVar;public void method1() {// 局部变量int localVar = 10;System.out.println(localVar); // 可用}public void method2() {// System.out.println(localVar); // 编译错误,localVar 在 method2 中不可用}
}
4. 内存位置
- 成员变量:存储在堆内存中,随着对象的创建而存在,随着对象的消失而消失。
- 局部变量:存储在栈内存中,随着方法的调用而存在,方法调用结束后即被销毁。
在上面的代码中,memberVar
存储在堆内存中,而 localVar
存储在栈内存中。
public class Example {// 成员变量int memberVar;public void method() {// 局部变量int localVar = 10;}
}
5. 生命周期
- 成员变量:在对象创建时被分配内存,并且随着对象的生命周期而存在。当对象销毁时,成员变量也会被销毁。
- 局部变量:在方法被调用时创建,在方法调用结束时销毁。局部变量的生命周期仅限于方法调用期间。
在这个例子中,memberVar
会随着 Example
类的对象创建和销毁而存在,而 localVar
只在 method()
方法执行时存在。
public class Example {// 成员变量int memberVar;public void method() {// 局部变量int localVar = 10;}
}
6. 结论
- 定义位置:成员变量定义在类中,局部变量定义在方法中。
- 初始化值:成员变量有默认值,局部变量没有默认值。
- 作用范围:成员变量在整个类中可见,局部变量只在方法中可见。
- 内存位置:成员变量在堆内存中,局部变量在栈内存中。
- 生命周期:成员变量的生命周期与对象相同,局部变量的生命周期与方法相同。