java类与对象

3721 字
10 分钟

We know our weakness. Now what will we do? We’ll get stronger! We’ll get up and fight! — Natsu Dragneel from Fairy Tail

类(Class)

定义对象的蓝图,包括属性和方法。就像是一个自定义的数据类型,你仅仅进行定义,没有创建实际的变量。

一个典型类如下:

public class Car{

}

类的组成

1. 成员变量

定义:用于存储对象状态的数据。它声明在类中、方法体之外,每个对象都会拥有自己的一份副本。

定义方法:[ ]中的内容可以省略

[访问修饰符] 数据类型 变量名 [= 初始值]

语法:[访问修饰符] 数据类型 变量名 [= 初始值];

  • 访问修饰符:public, private, protected, 默认 (package-private),控制成员变量的访问权限。
  • 数据类型:int, float, String, boolean, 以及自定义的类类型等。
  • 变量名: 遵循 Java 变量命名规则。
  • 初始值 (可选): 在声明时为变量赋初始值。如果没有显式赋值,则会使用默认值(例如,数值类型默认为 0,布尔类型默认为 false,引用类型默认为 null)
public class Car {
    public String color;       // 颜色
    private int speed;         // 速度
    protected String model;   // 型号
    boolean isRunning = false; // 是否正在运行
}

2. 构造方法

定义:特殊的方法,用于创建对象并初始化对象的成员变量。也就是在创建对象的时候自动调用的函数。

定义方法:

[访问修饰符] 类名(参数列表) 
{
 // 方法体 
}

构造方法的名字需于类名完全相同。

特点:

  • 没有返回值
  • 每个类至少有一个构造方法(多个构造方法涉及方法的重载)
  • 若没有显示指定构造方法,编译器会自动生成一个无参默认构造方法
  • 构造方法的访问修饰符决定了哪些类可以创建该类的实例。
访问修饰符构造方法访问级别
public任何类都可以创建该类的实例
protected同一个包中的类和子类可以创建该类的实例
private只能在该类内部创建该类的实例
默认只有同一个包中的类可以创建该类的实例
public class Car {
    public String color;
    private int speed;

    // 默认构造方法
    public Car() {
        this.color = "white";
        this.speed = 0;
    }

    // 带参数的构造方法
    public Car(String color, int speed) {
        this.color = color;
        this.speed = speed;
    }
}

3. 成员方法

定义:定义对象的行为,可以执行特定的操作

定义方法:

[访问修饰符] [static] [返回类型] 方法名(参数列表) [throws 异常列表] 
{ 
    // 方法体 
}

static (可选): 表示静态方法,属于类本身,而不是类的实例。通过static声明的方法,无需创建对象实例就可以直接使用,反之,未用static声明的方法。只能由创建后的实例调用。

public class Car {
    public String color;
    private int speed;

    public void accelerate(int increment) {
        this.speed += increment;
    }

    public int getSpeed() {
      return this.speed;
    }
}

4. 静态成员

定义:使用 static 关键字修饰的成员变量和方法。它们属于类本身,而不是类的实例。

  • 特点:
    • 可以通过类名直接访问,无需创建对象。
    • 所有该类的实例共享同一个静态成员的副本。
    • 静态方法不能直接访问非静态成员(实例变量和方法),因为静态方法不属于任何特定的对象。
public class Car {
    public static int carCount = 0; // 静态变量,用于记录创建的汽车数量

    public Car() {
      carCount++; // 每次创建对象,静态变量加一
    }
    public static int getCarCount() {
      return carCount; // 静态方法,可以访问静态变量
    }
}

5. 内部类

定义:在类内部定义的类。

  • 分类:

    • 成员内部类: 与类的成员变量类似,在类中直接定义。
    • 静态内部类: 使用 static 关键字修饰的内部类。
    • 局部内部类: 在方法或代码块中定义的类。
    • 匿名内部类: 在创建对象时定义的没有名字的类。
  • 特点:

    • 内部类可以访问外部类的所有成员,包括私有成员。
    • 声明内部类的外部类也可以访问内部类的的所有成员,包括私有成员。
public class HelloWorld {
    private class Car{
        private static String car = "This is a car";
    }
    public static void main(String[] args) {
        System.out.println("Hello World"); // 输出 Hello World
        System.out.println(Car.car);
    }
}

运行结果为:

1737171840563

以上就是一个完整的Java类通常包含的要素。

对象(Object)

对象的是类的实例,是创建的实际变量,分配实际内存空间后的实例,具有状态和行为。

典型创建实例如下:

Car myCar = new Car();

若自定义了构造方法,则可以在括号中传入对应参数,应用于实例的初始化。

假设我们自定义一个类如下:

class Car {
    public String color;
    public static int myCarCount = 0;
    public Car(String color){
        this.color = color;
        myCarCount++;		//静态变量直接访问,在类中
    }
    public void changeColor(String color){
        this.color = color;
    }
} 

在类中,我们可以通过this关键字来表示创建后的实例,每个实例中的this都互不影响,只表示自己实例中的值。但是对于类中的静态变量(static修饰)来说,并不能通过this来访问,静态变量不属于任何实例,所有该类的实例共享一个静态变量。

实例化对象:

Car myCar = new Car("Blue");

访问对象中的变量:

myCar.color
System.out.println("my car's color is " + myCar.color);//打印出来

访问对象中的方法:

myCar.changeColor("green");

访问类中的静态变量和方法:

Car.myCarCount;	//直接通过类名访问
System.out.println("I have " + Car.myCarCount + " cars");

给出如下程序:

public class HelloWorld {
    public static void main(String[] args) {
        Car myCar = new Car("Blue");
        System.out.println("my car's color is " + myCar.color);
        myCar.changeColor("green");
        System.out.println("my car's color is " + myCar.color);
        System.out.println("I have " + Car.myCarCount + " cars");
    }
}

运行结果如下:

1737255232853

静态代码块与非静态代码块(构造块)

静态代码块

静态代码块属于类,而不是实例,会在类加载时自动执行一次,用于初始化静态变量或做类级别的准备工作。

class Parent {
    static {
        System.out.println("父类静态代码块");
    }
}

非静态代码块/构造块

非静态代码块属于实例,每次创建实例对象时都会执行。用于初始化实例变量。或执行一些实例级别的准备逻辑。

  • 编译器会将非静态代码块的内容自动插入到构造方法的前面。
class Parent {
    {
        System.out.println("父类构造块");
    }
}

当有如下的子类与父类时:

class Parent {
    static {
        System.out.println("① 父类静态代码块");
    }

    {
        System.out.println("③ 父类构造块");
    }

    public Parent() {
        System.out.println("④ 父类构造方法");
    }
}

class Child extends Parent {
    static {
        System.out.println("② 子类静态代码块");
    }

    {
        System.out.println("⑤ 子类构造块");
    }

    public Child() {
        System.out.println("⑥ 子类构造方法");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child();
    }
}

运行顺序如下:

① 父类静态代码块
② 子类静态代码块
③ 父类构造块
④ 父类构造方法
⑤ 子类构造块
⑥ 子类构造方法