Theme Preview

Hue:

You are using an outdated browser that does not support OKLCH colors. The color setting will not take effect.

这才是Java对象的正解

3k words

前言:Java对象的理解

在Java中,”对象” 和 “实例”是面向对象编程(Object-Oriented Programing,OOP)中两个相关但稍有不同的概念。

什么是对象?

对象(Object)是内存中分配的实际数据结构,它包含了数据和方法。在 Java 中,对象是类的一个实例,可以是具体类(例如 Child)的实例,也可以是抽象类或接口的实现类的实例。对象是具体的实体,它具有特定的属性和行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package test;

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

public void run(String model){
System.out.println(model + "启动");
}

public static void main(String[] args){
//创建Car的实例
Car car1 = new Car("本田","汽车1");
Car car2 = new Car("宝马","汽车2");
Car car3 = new Car("奔驰","汽车3");
}
}

在这个例子中car1、car2、car3就是Car类的三个对象,是三辆不同的车,是三个不同的实例。但是他们都是来自于一个类模板。

由于实例化的过程是在JVM运行时进行的。所以我们可以看一下这三个实例对象的模板信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args){
//创建Car的实例
Car car1 = new Car("本田","汽车1");
Car car2 = new Car("宝马","汽车2");
Car car3 = new Car("奔驰","汽车3");

System.out.println(car1.getClass());
System.out.println(car2.getClass());
System.out.println(car3.getClass());

}

//输出
class test.Car
class test.Car
class test.Car

上面的getClass方法获取的是Car类运行时Class模板反射对象(Class carClass = Car.class;),改对象存储了Car类的元信息(方法、字段、常量等等)。在运行时我们就是通过这个去操作类中的属性方法,通过这个Class对象去new 出一个实例。

注意:Class和class的区别。

实例(Instance)是什么?

  • 实例是指类的具体实现,即类的一个具体的对象。
  • 当你使用关键字 new 来实例化一个类时,你就创建了这个类的一个实例。
  • 实例化(Instance)是指一个对象被创建出来并分配了内存空间的过程。这个对象可以是某个类的实例,也可以是子类的实例。实例化是创建对象的过程。

==看完上面的内容你是不是觉得对象和实例是一样的东西?==

是的,你的理解没有问题:在讨论面向对象编程的语境下,通常情况下”对象”和”实例”被用作同义词,表示类的具体实现。然而,在某些上下文中,人们可能会强调它们之间的微小差异。(我认为对于新手java来说这个区别完全可以忽略,避免混淆)

比如:

这里假设我们有一个抽象的动物类和一个具体的猫类:

1
2
3
4
5
6
7
8
9
10
11
abstract class Animal {
abstract void makeSound();
}

class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow");
}
}

创建实例:

1
2
Animal aniObject = new Cat();
Cat catIntance = new Cat();

在这里 aniObject时指向Cat对象的一个引用;而catIntance则是Cat类的一个具体实例(后半句是完全结合前面所讲的,这里是没有问题的,前半句通过下面理解)。

aniObject 是指向Cat对象的引用,从内存的角度来讲,这个引用指向了Cat类的实例。但是由于我们声明的类型是Animal,在某些上下文中,人们就更愿意称aniObjectAnimal类型的对象,强调它是抽象类的一个实例。

catIntance 是直接声明为 Cat 类型的实例,没有涉及到抽象类的层面,因此直接称为 Cat 类的实例。

总结:在这种情况下,从代码的角度来看,animalObjectcatInstance 都是 Cat 类的实例,但在一些讨论中,人们可能更倾向于将 animalObject 视为 Animal 类的对象,强调其类型的抽象层面。这种区别在特定的语境下可能会有所体现。

==如果上面的例子不足以让你理解,就再看一下==

再举个例子:

1
Person example = new Person();

在这个例子中,我们使用 new 关键字,在内存堆中创建了一个 Person 对象,而 example 是这个 Person 对象的引用变量。在这里,我们可以说 example 这个引用变量对应的对象是 Person 类的一个实例。

在这样的上下文中,实例和对象通常可以互换使用的概念。

再来看一个例子,以更好理解 Java 对象:

1
2
// Child extends Person
Person example1 = new Child();

在这行代码中,我们使用 new 关键字创建了一个 Child 类的实例(对象),并将这个 Child 对象赋值给了 example1 引用变量。因为 childPerson 的子类,所以这里可以将 Child 类的值赋值给 Person 类的引用变量。

关键点在于,尽管 example1Person 类的引用,但实际上它引用的是 Child 类的对象。这意味着 example1 可以访问 Person 类中的属性和方法,但不能访问 Child 类中特有的属性和方法,除非进行类型转换。

因此,实例化过程(new Child())创建了一个对象,并将其分配给一个引用变量,但这并不意味着对象包含了所有的属性和方法,而是取决于引用变量的类型和对象的实际类型。在代码示例中,example1Person 类的引用,但引用的是 Child 的对象,这就反映了多态性的概念,其中一个引用可以引用不同类型的对象,从而在调用相同的方法时产生不同的行为。

==从内存的角度去理解new实例化的过程==

在JVM内存中,jvm拿着ClassLoader生成的Classu对象,在程序运行时去执行 Car car1 = new Car(“本田”,”汽车1”);这样的代码,然后再堆区生成改实例的具体信息,包括里面的属性方法,在栈区生成对应的变量引用。

Comments