1. 什么是类?
类(Class)是蓝图或者模板。它定义了对象的属性和行为。
- 类就是一种抽象的模板,你可以通过它创建多个对象。
- 类定义了对象的属性(变量)和行为(方法)。
- 我们可以把类理解成是一种文字一种方法,通过将这个方法具体应用可以完成很多同类型的具体的事件。这个方法我们叫做类,将这个方法具体应用的过程我们叫做类的实例化,着一个个具体的同类型的按照这个方法操作的事件我们叫做对象。注意:(不是Java里的那个方法,就是我们生活中用来解决问题的方法,此处只是打比方,便于理解)
类的结构:
// 类的定义
class Animal{
// 属性(成员变量)String name;int age;public Animal(String name){this.name = name;}// 行为(方法)void bark() {System.out.println(name + " says woof!");}void eat(){System.out.println(name + "is eating food~");}void sleep(){System.out.println(name + "is sleeping~");}}class Main{public static void main(String args[]){Animal dog = new Animal("dog");dog.bark();dog.eat();dog.sleep();}
}
在这个例子中:
Dog
是类的名称。name
和age
是属性(变量)。bark()
是方法,它定义了Dog
对象能做的事情。
2. 什么是对象?
对象是类的实例。你可以把类当做工厂或模板,使用它来生产对象。
猫爪冰棍模具 = 猫爪冰棍类;
用猫爪冰棍模具做出来的冰棍 = 猫爪冰棍对象。
模具只有一个,但是可以做出很多个冰棍,即一个类可以产生很多对象。
- 对象就是通过类创建出来的具体实体,它拥有类中定义的属性和行为。
- 类是一个模板,它描述了所有同类型对象共有的属性和行为。
- 对象是类的实例,它具体化了类中定义的属性和行为。
创建对象的方式:
public class Main {public static void main(String[] args) {// 创建一个 Dog 类的对象Dog myDog = new Dog();// 赋值给对象的属性myDog.name = "Buddy";myDog.age = 3;// 调用对象的方法myDog.bark(); // 输出:Buddy says woof!}
}
在这个例子中:
myDog
是一个 对象,它是Dog
类的一个实例。myDog.name
和myDog.age
是对象的属性。myDog.bark()
是对象的行为。
3. 如何创建对象?
(类的实例化就是创建对象,把猫爪冰棍模具变成能吃的猫爪冰棍)
3.1 创建对象的语法格式:
new
关键字在 Java 中用于创建对象,创建对象时会调用类的构造方法(Constructor)。- 每次创建对象时,
new
会在内存中分配一块空间给对象。
Dog myDog = new Dog(); // 创建一个 Dog 类型的对象无需向类的构造函数传参的时候的定义格式
类名 对象名 = new 类名();需要通过类的构造函数传递参数的时候给实例对象的成员传参的时候的定义格式
类名 对象名 = new 类名(参数列表);
3.2 创建对象的具体过程:
3.2.1 声明类类型的变量:
声明一个类类型的变量,就是告诉编译器你要使用该类的对象。例如,假设有一个 Dog
类:
class Dog {String name;// 构造方法public Dog(String name) {this.name = name;}// 方法public void bark() {System.out.println(name + " says Woof!");}
}
声明一个Dog类型的变量:
Dog myDog;
此时,myDog
只是一个变量,指向 Dog
类型的对象,但并没有指向具体的实例。
3.2.2 使用new关键字创建对象
为了实际创建一个 Dog
类的对象,并让 myDog
变量指向这个对象,你需要使用 new
关键字:
myDog = new Dog("Buddy");
这行代码的作用是:
new Dog("Buddy")
创建了一个新的Dog
类的实例,并调用了构造方法Dog(String name)
来为这个新对象的name
属性赋值为"Buddy"
。myDog
变量被指向了新创建的Dog
对象。
3.2.3 调用构造方法
new
关键字不仅创建对象,还会调用类的构造方法来初始化对象。构造方法通常用于设置对象的初始状态,比如给属性赋值。
完整的创建对象过程(示例)
class Dog {String name;// 构造方法public Dog(String name) {this.name = name;}// 方法public void bark() {System.out.println(name + " says Woof!");}
}public class Main {public static void main(String[] args) {// 创建 Dog 类的一个对象,并将其赋值给 myDogDog myDog = new Dog("Buddy");// 调用对象的方法myDog.bark(); // 输出: Buddy says Woof!}
}
关键点总结:
- 声明变量:
Dog myDog;
声明了一个Dog
类型的变量myDog
,但是它还没有指向任何对象。 - 使用
new
创建对象:new Dog("Buddy")
创建了一个新的Dog
对象,并通过构造方法初始化了对象的属性。 - 调用构造方法:构造方法
Dog(String name)
设置了name
属性的初始值。 - 通过对象调用方法:
myDog.bark()
调用了Dog
类的bark()
方法。
4. 对象的属性(成员变量)
属性是定义在类中的变量,它描述了对象的状态。每个对象都有自己的属性值。
class Dog {String name; // name 是属性int age; // age 是属性
}
在创建对象时,我们可以赋值给这些属性:
Dog myDog = new Dog();
myDog.name = "Buddy";
//通过 对象名.成员变量名 可以用对象里的共有成员变量,给成员变量赋值或者初始化或者改变其值
myDog.age = 3;//也可以通过 对象名.成员方法名(有参数需要传递的话就写,没参数就不用写) 来使用成员方法
5. 对象的方法(成员方法)
方法是定义在类中的函数,描述了对象的行为。方法可以操作对象的属性,也可以执行某些操作。
class Dog {String name;int age;// 方法:行为void bark() {System.out.println(name + " says woof!");}
}
调用方法时,可以通过对象来访问它:
Dog myDog = new Dog();
myDog.name = "Buddy";
myDog.bark(); // 输出:Buddy says woof! 通过 对象名.成员方法名 调用对象的成员方法
6. 构造方法
6.1 定义:
构造方法(Constructor)是 Java 中一种特殊的方法,用于在创建对象时对对象进行初始化。构造方法的主要作用是确保对象在创建时的正确初始化,并且可以为对象设置初始状态。它在创建对象时被自动调用,用于传入参数,用来初始化对象的状态。构造方法的名称必须与类名相同。
6.2 构造方法的特点:
- 名称与类名相同:构造方法的名称必须与类名相同。
- 没有返回类型:构造方法没有返回值类型(也不需要写
void
)。 - 自动调用:当你创建对象时,构造方法会自动调用。
- 自动提供默认构造方法:如果你不定义构造方法,Java 会自动提供一个默认的隐式的无参构造方法。
- 构造方法没有返回类型,并且是对象在创建的时候会被自动调用,且是先于对象中的类的任何方法的。
6.3 构造方法的分类:
6.3.1 默认构造方法:
如果你没有显式定义构造方法,Java 会自动提供一个默认构造方法。默认构造方法没有参数,它什么也不做,仅仅是初始化一个空对象。如果你定义了一个带参数的构造方法,Java 将不再自动提供默认构造方法。
class Dog {String name;int age;// void Dog(){// //}
//这里有一个什么都没有的构造方法的,系统自己给这个类的,
//但是它是隐式的,平时我们写代码的时候如果不特意写出来的话,
//系统也会默认我们有这个,只是没有显示出来而已
}// 默认构造方法:没有参数
Dog myDog = new Dog(); // 创建对象时,会调用默认构造方法
class Dog {String name;// 定义带参数的构造方法public Dog(String name) {this.name = name;}
}public class Main {public static void main(String[] args) {// Dog dog = new Dog(); // 编译错误,默认构造方法没有提供Dog dog = new Dog("Buddy"); // 正确,调用带参数的构造方法System.out.println(dog.name); // 输出: Buddy}
}
解释:
- 因为
Dog
类中已经显式定义了带参数的构造方法Dog(String name)
,Java 不会自动生成默认构造方法。 - 如果没有显式定义任何构造方法,Java 会自动生成一个无参的默认构造方法。
6.3.2 自定义构造方法:
你也可以定义带参数的构造方法来初始化对象:
class Dog {String name;// 构造方法public Dog(String name) {this.name = name; // 初始化对象的实例变量}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy"); // 创建对象时调用构造方法System.out.println(dog.name); // 输出: Buddy}
}
6.4 构造方法重载: (有多个自定义的构造方法)
构造方法是可以重载的,即在同一个类中,可以定义多个构造方法,只要它们的参数列表不同。重载的构造方法允许用不同的参数来初始化对象。
class Dog {String name;int age;// 默认构造方法public Dog() {this.name = "Unknown";this.age = 0;}// 带参数的构造方法public Dog(String name, int age) {this.name = name;this.age = age;}public void displayInfo() {System.out.println("Name: " + name + ", Age: " + age);}
}public class Main {public static void main(String[] args) {Dog dog1 = new Dog(); // 调用默认构造方法dog1.displayInfo(); // 输出: Name: Unknown, Age: 0Dog dog2 = new Dog("Buddy", 3); // 调用带参数的构造方法dog2.displayInfo(); // 输出: Name: Buddy, Age: 3}
}
解释:
Dog()
是一个默认构造方法,没有参数,默认将name
设置为"Unknown"
,age
设置为0
。Dog(String name, int age)
是一个带参数的构造方法,用来通过外部提供的值来初始化name
和age
。- 在
main
方法中,创建了两个Dog
对象,分别调用了不同的构造方法。
构造方法的重载可以让你为对象提供不同的初始化方式,增强代码的灵活性和可重用性。
6.5 构造方法的调用规则:
- 自动调用:每次通过
new
关键字创建对象时,构造方法会被自动调用。
// 类的定义
class Animal{
// 属性(成员变量)String name;int age;public Animal(String name){this.name = name;System.out.println("构造方法被调用");}void bark(){System.out.println(name + "can bark");}
}class Main{public static void main(String args[]){Animal dog = new Animal("dog");
//在创建对象的时候就会第一时间调用构造方法,
//如果有多个构造方法则程序会根据传入的参数的情况确定要调用哪个构造方法,
//反正只要创建对象就一定会调用构造方法dog.bark();}
}/*
输出:
构造方法被调用
dog can bark
*/
7. 对象初始化:
输出结果:
- 默认初始化:当对象创建时,实例变量会被自动初始化为默认值,比如
int
类型的变量默认为0
,boolean
默认为false
,引用类型的变量默认为null
。 - 显式初始化:在构造方法中,可以显式地初始化实例变量。
- 就地初始化:在实例变量声明时直接进行初始化。
class Dog {// 1. 就地初始化(直接在声明时赋值)String name = "Unknown"; // 默认值为 "Unknown"// 2. 默认初始化(没有赋值的实例变量会自动初始化)int age; // 默认值为 0// 3. 显式初始化(在构造方法中初始化实例变量)boolean isAdopted;// 构造方法:显式初始化实例变量public Dog(String name, int age, boolean isAdopted) {this.name = name; // 显式初始化this.age = age; // 显式初始化this.isAdopted = isAdopted; // 显式初始化}// 打印信息public void displayInfo() {System.out.println("Name: " + name);System.out.println("Age: " + age);System.out.println("Adopted: " + isAdopted);} }public class Main {public static void main(String[] args) {// 使用构造方法初始化Dog dog1 = new Dog("Buddy", 3, true);dog1.displayInfo();// 输出:// Name: Buddy// Age: 3// Adopted: true// 使用默认构造方法,name 使用就地初始化,age 使用默认初始化,isAdopted 使用默认初始化Dog dog2 = new Dog("Max", 0, false);dog2.displayInfo();// 输出:// Name: Max// Age: 0// Adopted: false} }
解释:
-
就地初始化:
String name = "Unknown";
这是在实例变量声明时直接赋值,称为就地初始化。即在定义变量时就给它一个初始值。
-
默认初始化:
int age;
这行代码声明了一个int
类型的变量,但没有给它显式赋值。在 Java 中,所有的实例变量都会有默认值。对于int
类型,默认值是0
。因此,即使没有给age
赋值,它在对象创建时也会自动初始化为0
。
- 当我们创建
dog1
对象时,构造方法会显式初始化实例变量,因此会使用传入的值"Buddy"
,3
,true
来初始化name
,age
和isAdopted
。 - 当我们创建
dog2
对象时,由于构造方法中为age
传入了0
,而name
使用了就地初始化的值"Max"
,isAdopted
使用默认初始化值false
。 -
显式初始化:
- 在构造方法中,使用
this.name = name;
,this.age = age;
,this.isAdopted = isAdopted;
进行了显式初始化。这种初始化方式通常在构造方法中进行,通过外部传入的值来设置实例变量的值。
- 在构造方法中,使用
8. this 关键字
8.1 定义:
在 Java 中,this
关键字是一个引用,指向当前对象的实例。this
可以用在类的实例方法、构造方法以及内部类中,它有许多用途,主要是区分局部变量和实例变量、引用当前对象、调用构造方法等。
8.2 理解:
8.2.1 区分实例变量和局部变量(或参数)
有时,在方法中,局部变量(或方法参数)和类的实例变量同名,导致代码中看起来不清楚到底是操作局部变量还是实例变量。此时,this
关键字就可以帮助我们区分。
class Dog {String name; // 实例变量1// 构造方法,参数和实例变量名相同public Dog(String name) {this.name = name; // this.name 表示实例变量,name 表示构造方法参数
// this.name 指的是当前对象的实例变量,也就是Dog类中注释实例变量1处的变量name,
//而this.name = name;等号右边的name是传参进来的变量name,
//当传入的参数的名字和类中原本定义的变量名字一样的时候我们就会使用到this来区分传入的参数和类本身就有的参数,否则有两个name将会无法区分,代码会报错}public void displayName() {System.out.println("The dog's name is: " + this.name); // this.name 引用的是实例变量}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");dog.displayName(); // 输出: The dog's name is: Buddy}
}
解释:
- 在
Dog
类的构造方法中,name
既是构造方法的参数,也是实例变量。 this.name
指的是类中的实例变量name
,而name
单独写时指的是构造方法的参数。- 使用
this
可以明确地告诉编译器我们要修改的是实例变量。
8.2.2 引用当前对象
this
关键字还可以用于引用当前对象。也就是说,它表示当前类的对象实例。这对于在实例方法中传递当前对象或返回当前对象时非常有用。
示例:
class Dog {String name;public Dog(String name) {this.name = name;}public Dog getCurrentObject() {
//getCurrentObject() 方法返回的是当前对象,即 this 关键字所代表的对象return this; // 返回当前对象}public void displayName() {System.out.println("The dog's name is: " + name);}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");dog.displayName(); // 输出: The dog's name is: BuddyDog anotherDog = dog.getCurrentObject(); // 获取当前对象anotherDog.displayName(); // 输出: The dog's name is: Buddy}
}
解释:
- 在上述代码中,
this
在getCurrentObject()
方法中返回的是当前对象的引用。当你调用dog.getCurrentObject()
时,实际上this
返回的是dog
本身,并且将其赋值给anotherDog
。这两者dog
和anotherDog
指向同一个对象。
8.2.3 在构造方法中调用其他构造方法(构造方法的链式调用)
this
关键字还可以在构造方法中调用同一个类的其他构造方法。这称为构造方法链式调用。通过这种方式,我们可以在多个构造方法中复用代码,避免重复代码。
示例:
class Dog {String name;int age;// 默认构造方法public Dog() {this("Unknown", 0); // 调用另一个构造方法,如果还有其他的构造方法,会根据参数确定在中国默认的构造方法中使用this去再调用哪个方法}// 带参数的构造方法public Dog(String name, int age) {this.name = name;this.age = age;}public void displayInfo() {System.out.println("Name: " + name + ", Age: " + age);}
}public class Main {public static void main(String[] args) {Dog dog1 = new Dog(); // 调用默认构造方法dog1.displayInfo(); // 输出: Name: Unknown, Age: 0Dog dog2 = new Dog("Buddy", 3); // 调用带参数的构造方法dog2.displayInfo(); // 输出: Name: Buddy, Age: 3}
}
解释:
- 在
Dog
类的默认构造方法Dog()
中,使用this("Unknown", 0)
调用了另一个带参数的构造方法。 - 这就避免了重复的代码:
name
和age
的赋值只需要写在带参数的构造方法中,其他构造方法可以通过this()
调用进行复用。
8.2.4 作为内部类引用外部类的实例
在 Java 中,内部类如果需要访问外部类的实例变量或方法时,可以使用 this
来引用外部类的实例。
示例:
class OuterClass {String name = "OuterClass";class InnerClass {String name = "InnerClass";public void printNames() {System.out.println("Outer class name: " + OuterClass.this.name); // 访问外部类的变量System.out.println("Inner class name: " + this.name); // 访问内部类的变量}}public static void main(String[] args) {OuterClass outer = new OuterClass();OuterClass.InnerClass inner = outer.new InnerClass();inner.printNames();}
}
解释:
OuterClass.this.name
用来引用外部类OuterClass
的name
变量。this.name
直接引用内部类InnerClass
的name
变量。OuterClass.this
是引用外部类实例的方式,通过它可以访问外部类的成员。
9. 类和对象的生命周期
9.1 类的生命周期
类的生命周期从它的加载开始,到它的卸载结束。在 Java 中,类是由 JVM(Java 虚拟机)加载、管理和卸载的。类的卸载指的是类从 JVM(Java Virtual Machine) 内存中被移除的过程。这是一个由 JVM 类加载器(ClassLoader) 管理的过程,当类不再被使用时,JVM 会将它从内存中卸载,以释放资源。这个过程和类的加载一样,通常是自动管理的,程序员无法直接控制。
类加载(Class Loading)
- 当一个类首次被使用时,JVM 会加载它。
- 类的加载由 类加载器(ClassLoader) 负责。类加载的过程包括:
- 加载:JVM 查找并加载类的字节码文件(.class 文件)。
- 链接:类加载后的字节码会被链接到 JVM 内存中。链接包括验证、准备和解析。
- 初始化:类的静态变量和静态代码块会被初始化。
类的卸载
- 类的生命周期结束时,JVM 会卸载它。
- 一般情况下,类会在类加载器不再使用时被卸载,但类的卸载通常由 JVM 自动管理,开发者无需手动干预。
9.2 对象的生命周期
对象的生命周期是指对象从创建到销毁的过程。Java 中的对象生命周期由 堆内存(Heap Memory) 和 垃圾回收机制(Garbage Collection) 控制。
对象的创建(Instantiation)
- 当你使用
new
关键字时,会在 堆内存 中分配空间来创建对象。每次调用new
都会创建一个新的对象实例。 - 对象的构造方法会在创建时自动调用,以初始化对象的字段。
示例:对象的创建
class Dog {String name;// 构造方法Dog(String name) {this.name = name;}
}public class Main {public static void main(String[] args) {// 创建一个对象Dog dog = new Dog("Buddy"); // Dog 类的对象在堆内存中创建}
}
对象的使用(Reference)
- 创建对象后,你可以通过引用变量(如
dog
)来访问对象的属性和方法。对象的生命周期管理是由引用变量控制的。 - 如果有多个引用指向同一个对象,那么该对象仍然存在,直到没有任何引用指向它为止。
对象的销毁(Garbage Collection)
- 在 Java 中,垃圾回收(GC)负责回收不再使用的对象。对象会在以下情况下被销毁:
- 没有引用指向它:当对象不再被任何引用变量引用时,GC 会自动回收它。
- 垃圾回收器:Java 会自动运行垃圾回收器来清理没有引用的对象,这个过程是自动的,开发者不需要手动销毁对象。
示例:对象的销毁
public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy"); // 创建对象// 当 dog 变量不再引用该对象时,Buddy 对象将变成垃圾等待被回收dog = null; // 取消引用对象,垃圾回收器会销毁该对象}
}
垃圾回收(GC)详细描述
- 在 Java 中,垃圾回收器(GC)会自动查找和回收无用的对象,释放内存空间。
- 当对象不再有任何引用指向它时,JVM 会标记该对象为 垃圾,并在下一次垃圾回收时销毁它。
9.3 类和对象生命周期的对比
生命周期阶段 | 类 | 对象 |
---|---|---|
加载/创建 | 类在第一次使用时加载到内存 | 使用 new 创建对象,分配内存 |
使用 | 类在内存中一直存在,直到程序结束 | 对象在内存中存在,直到没有引用指向它 |
销毁 | 类在程序结束时卸载 | 对象通过垃圾回收机制被销毁 |
9.4 总结
-
类的生命周期:从类加载开始,到类卸载结束。类的生命周期由类加载器控制,类的静态变量和静态方法在内存中存在,直到类卸载。
-
对象的生命周期:从对象创建开始,到对象被垃圾回收结束。对象的生命周期由引用变量控制,垃圾回收机制负责销毁不再使用的对象。
10. 类和对象的区别总结
- 类是一个模板,用来创建对象,它描述了对象的属性和行为。
- 对象是类的实例,是通过类创建出来的具体实体。
总结
- 类是描述一组对象共有特征的模板。
- 对象是通过类创建出来的实例,拥有类中定义的属性和行为。
- 创建对象时,使用
new
关键字,调用构造方法。 - 对象的属性描述它的状态,方法描述它的行为。
- 通过构造方法初始化对象的状态,可以用
this
关键字来区分实例变量和局部变量。