当前位置: 首页 > news >正文

Java基础知识(五)

1. 面向对象编程 (OOP) 基础

Java 是一种面向对象的编程语言,核心思想包括:

  • 封装:将数据和操作数据的方法捆绑在一起
  • 继承:允许创建基于现有类的新类
  • 多态:允许不同类的对象对同一消息做出响应

2. 类 (Class) 的定义

类是对象的模板或蓝图,定义了对象将具有的属性 (变量) 和行为 (方法)。

类的基本结构

访问修饰符 class 类名 {// 成员变量(属性)数据类型 变量名1;数据类型 变量名2;// 构造方法访问修饰符 类名(参数列表) {// 初始化代码}// 成员方法(行为)访问修饰符 返回值类型 方法名(参数列表) {// 方法体}
}

示例:定义一个 Person 类

public class Person {// 成员变量String name;int age;String gender;// 构造方法public Person(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}// 成员方法public void introduce() {System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");}public void birthday() {age++;System.out.println("Happy birthday! Now I'm " + age + " years old.");}
}

3. 对象 (Object) 的创建与使用

对象是类的实例,是具体存在的实体。

创建对象

使用new关键字创建对象:

类名 对象名 = new 类名(参数);

使用对象

通过.运算符访问对象的属性和方法:

对象名.属性名;    // 访问属性
对象名.方法名();  // 调用方法

示例:使用 Person 类创建对象

public class Main {public static void main(String[] args) {// 创建Person对象Person person1 = new Person("Alice", 25, "Female");Person person2 = new Person("Bob", 30, "Male");// 访问对象属性System.out.println(person1.name);  // 输出: Alice// 调用对象方法person1.introduce();  // 输出: Hello, my name is Alice, I'm 25 years old.person2.birthday();   // 输出: Happy birthday! Now I'm 31 years old.}
}

4. 构造方法 (Constructor)

在 Java 中,构造方法(Constructor)是一种特殊的方法,用于在创建对象时初始化对象。它在对象被实例化(使用new关键字)时自动调用,主要作用是为对象的成员变量赋初始值。

构造方法的特点:

  1. 方法名与类名完全相同
    包括大小写,例如public class Person的构造方法必须命名为Person()

  2. 没有返回值类型
    与普通方法不同,构造方法不声明返回值(包括void)。

  3. 自动调用
    创建对象时通过new关键字自动调用,无法像普通方法一样手动调用。

  4. 默认构造方法
    如果类中没有显式定义构造方法,编译器会自动生成一个无参构造方法(没有参数)。

构造方法的分类:

  1. 无参构造方法
    没有参数的构造方法,用于创建对象时不需要传入初始值的场景。

    public class Person {// 无参构造方法public Person() {// 初始化操作}
    }
    
  2. 有参构造方法
    带有参数的构造方法,用于创建对象时直接为成员变量赋值。

    public class Person {private String name;private int age;// 有参构造方法public Person(String name, int age) {this.name = name; // 为成员变量赋值this.age = age;}
    }
    

构造方法的重载:

在 Java 中,构造方法的重载(Overloading)是指在同一个类中定义多个构造方法,它们具有相同的方法名(与类名一致),但参数列表不同(参数的数量、类型或顺序不同)。

构造方法的重载允许我们通过不同的参数组合来创建对象,提供了灵活的对象初始化方式。

构造方法重载的规则:

  1. 方法名必须相同(与类名一致)。
  2. 参数列表必须不同
    • 参数数量不同
    • 参数类型不同
    • 参数顺序不同(当参数类型不同时)
  3. 与返回值无关(构造方法本身没有返回值)。
  4. 与访问修饰符无关(可以是publicprivate等)。

构造方法重载示例:

下面以Student类为例,展示不同参数组合的构造方法重载:

public class Student {private String name;private int age;private String major;// 1. 无参构造方法public Student() {// 初始化默认值this.name = "未知姓名";this.age = 0;this.major = "未知专业";}// 2. 只有姓名的构造方法(1个参数)public Student(String name) {this.name = name;this.age = 0;this.major = "未知专业";}// 3. 姓名+年龄的构造方法(2个参数)public Student(String name, int age) {this.name = name;this.age = age;this.major = "未知专业";}// 4. 姓名+年龄+专业的构造方法(3个参数)public Student(String name, int age, String major) {this.name = name;this.age = age;this.major = major;}// 5. 参数顺序不同的构造方法(年龄+姓名)public Student(int age, String name) {this.name = name;this.age = age;this.major = "未知专业";}// 打印学生信息public void showInfo() {System.out.println("姓名:" + name + ",年龄:" + age + ",专业:" + major);}public static void main(String[] args) {// 调用不同的构造方法创建对象Student s1 = new Student();Student s2 = new Student("张三");Student s3 = new Student("李四", 20);Student s4 = new Student("王五", 21, "计算机科学");Student s5 = new Student(22, "赵六"); // 调用参数顺序不同的构造方法s1.showInfo(); // 姓名:未知姓名,年龄:0,专业:未知专业s2.showInfo(); // 姓名:张三,年龄:0,专业:未知专业s3.showInfo(); // 姓名:李四,年龄:20,专业:未知专业s4.showInfo(); // 姓名:王五,年龄:21,专业:计算机科学s5.showInfo(); // 姓名:赵六,年龄:22,专业:未知专业}
}

构造方法重载的优势:

  1. 灵活性:允许根据不同场景选择合适的参数初始化对象,无需每次都传入所有参数。
  2. 简洁性:避免创建多个类似的类来处理不同的初始化需求。
  3. 可读性:通过参数列表直观了解初始化所需的信息。

注意事项:

  • 避免重复代码:可以使用this(参数)在一个构造方法中调用同类的其他构造方法,减少代码冗余:

    public Student() {this("未知姓名", 0, "未知专业"); // 调用3个参数的构造方法
    }public Student(String name) {this(name, 0, "未知专业"); // 调用3个参数的构造方法
    }
    

  • 参数顺序不同的重载需谨慎:如果参数类型相同,仅顺序不同,可能导致调用时混淆(编译器能区分,但可读性差)。
  • 如果定义了有参构造,建议显式定义无参构造:避免使用new 类名()创建对象时编译报错。

构造方法的重载是 Java 中实现多态的一种体现,合理使用可以让类的设计更加灵活和易用。

构造方法的使用示例:

public class Person {private String name;private int age;// 无参构造方法public Person() {this.name = "默认姓名";this.age = 0;}// 有参构造方法public Person(String name, int age) {this.name = name;this.age = age;}public void showInfo() {System.out.println("姓名:" + name + ",年龄:" + age);}public static void main(String[] args) {// 调用无参构造方法创建对象Person p1 = new Person();p1.showInfo(); // 输出:姓名:默认姓名,年龄:0// 调用有参构造方法创建对象Person p2 = new Person("张三", 20);p2.showInfo(); // 输出:姓名:张三,年龄:20}
}

注意事项:

  • 如果显式定义了构造方法(无论有参还是无参),编译器不会再生成默认的无参构造方法。如果需要无参构造,必须手动定义。
  • 构造方法可以重载(Overload),即一个类中可以有多个参数列表不同的构造方法,方便通过不同方式初始化对象。
  • 可以通过this(参数)在一个构造方法中调用同类的其他构造方法,简化代码:

    public Person(String name) {this(name, 18); // 调用有参构造方法Person(String, int)
    }
    

构造方法是 Java 面向对象编程中初始化对象的核心机制,合理使用可以确保对象在创建时就处于有效状态。

5. 成员变量与局部变量

在 Java 中,变量根据定义位置和作用范围的不同,可分为成员变量局部变量,二者在定义位置、作用域、初始化方式等方面有显著区别。

1. 成员变量(Member Variable)

成员变量是定义在类中、方法之外的变量,用于描述类的属性(特征)。

特点:
  • 定义位置:在类中,所有方法(包括构造方法)之外。
  • 作用域:整个类中都可访问(取决于访问修饰符,如publicprivate等)。
  • 默认值:未手动赋值时,会有默认初始化值(不同类型默认值不同):
    • 数值类型(intdouble等):默认00.0
    • 布尔类型(boolean):默认false
    • 引用类型(如String、数组):默认null
  • 内存位置:随对象创建存储在堆内存中,对象被回收时一同释放。
  • 分类
    • 实例变量(非static修饰):属于对象,每个对象有独立副本。
    • 类变量(static修饰):属于类,所有对象共享同一份,可通过类名直接访问。
示例:

public class Person {// 成员变量(实例变量)private String name; // 字符串类型,默认nullprivate int age;     // 整数类型,默认0// 成员变量(类变量)public static String species = "人类"; // 所有对象共享// 方法中可以访问成员变量public void introduce() {System.out.println("姓名:" + name + ",年龄:" + age);}
}

2. 局部变量(Local Variable)

局部变量是定义在方法内、构造方法内、代码块内的变量,用于临时存储数据。

特点:
  • 定义位置:方法参数、方法体内部、构造方法、代码块(如iffor块)中。
  • 作用域:仅在定义它的代码块(或方法)内有效,出了范围则无法访问。
  • 默认值没有默认值,必须手动初始化后才能使用,否则编译报错。
  • 内存位置:存储在栈内存中,当方法或代码块执行完毕后自动释放。
  • 修饰符:不能使用访问修饰符(publicprivate等),也不能用static修饰。
示例:

public class Calculator {// 成员变量private int result;public int add(int a, int b) { // a、b是方法参数(局部变量)int sum; // 方法内的局部变量sum = a + b; // 必须初始化才能使用return sum;}public void printRange() {for (int i = 0; i < 5; i++) { // i是循环体内的局部变量System.out.println(i);}// System.out.println(i); // 报错:i超出作用域}
}

3. 核心区别对比

对比项成员变量局部变量
定义位置类中,方法外方法内、参数、代码块内
作用域整个类(取决于修饰符)仅在定义它的代码块内
默认值有默认值(按类型)无默认值,必须手动初始化
内存位置堆内存(实例变量)/ 方法区(类变量)栈内存
修饰符可使用访问修饰符、static不能使用访问修饰符和static
生命周期随对象 / 类的生命周期随方法 / 代码块的执行周期

 注意事项

  • 同名变量的优先级:如果局部变量与成员变量同名,在局部变量的作用域内,局部变量会覆盖成员变量。如需访问成员变量,需用this关键字(实例变量)或类名(类变量):

    public class Demo {private int num = 10; // 成员变量public void show() {int num = 20; // 局部变量(与成员变量同名)System.out.println(num); // 输出20(局部变量)System.out.println(this.num); // 输出10(成员变量)}
    }
    

  • 局部变量的作用域限制:避免在嵌套代码块中定义与外部块同名的变量,可能导致逻辑混乱。

理解成员变量和局部变量的区别,有助于合理设计类的属性和方法,避免变量作用域相关的错误。

6. 封装-访问修饰符

在 Java 中,封装(Encapsulation) 是面向对象编程(OOP)的三大核心特性之一(另外两个是继承和多态),它指的是将对象的状态(成员变量)和行为(方法)捆绑在一起,并对外部隐藏对象的内部实现细节,仅通过公共接口与对象交互。

简单来说,封装的核心思想是:隐藏细节,暴露接口

封装的实现方式

  1. 使用访问修饰符限制成员变量的访问权限
    通常将成员变量声明为private(私有),阻止外部直接访问。

  2. 提供公共的访问方法(getter)和修改方法(setter)
    通过public(公共)方法间接操作私有成员变量,在方法中可以添加逻辑控制(如数据验证)。

封装的示例代码

public class Person {// 私有成员变量(隐藏细节)private String name;  // 姓名private int age;      // 年龄// 公共的getter方法(获取姓名)public String getName() {return name;}// 公共的setter方法(设置姓名)public void setName(String name) {// 可以添加验证逻辑if (name != null && !name.isEmpty()) {this.name = name;} else {System.out.println("姓名不能为空!");}}// 公共的getter方法(获取年龄)public int getAge() {return age;}// 公共的setter方法(设置年龄)public void setAge(int age) {// 年龄必须在合理范围内(0-150)if (age >= 0 && age <= 150) {this.age = age;} else {System.out.println("年龄必须在0-150之间!");}}// 公共方法(对外暴露的行为)public void introduce() {System.out.println("我叫" + name + ",今年" + age + "岁。");}
}

使用封装类的示例

public class TestPerson {public static void main(String[] args) {Person person = new Person();// 不能直接访问私有成员变量(编译报错)// person.name = "张三"; // person.age = -5;// 通过公共方法操作成员变量person.setName("张三");person.setAge(25);  // 合法年龄person.introduce(); // 输出:我叫张三,今年25岁。// 测试非法数据person.setName(""); // 输出:姓名不能为空!person.setAge(200); // 输出:年龄必须在0-150之间!}
}

封装的优势

  1. 数据安全性
    阻止外部直接修改成员变量,通过 setter 方法可以验证数据的合法性,确保对象始终处于有效状态(如年龄不能为负数)。

  2. 隐藏实现细节
    外部只需关注如何使用对象(调用公共方法),无需了解内部实现,降低了代码的耦合度。

  3. 便于维护和修改
    当类的内部实现需要修改时(如修改验证逻辑),只要公共接口不变,外部代码无需调整。

  4. 提高代码复用性
    封装后的类可以作为独立组件在不同场景中复用。

总结

封装通过私有化成员变量提供公共方法,实现了对数据访问的控制,既保护了对象的内部状态,又提供了安全、灵活的外部交互方式。它是面向对象编程中实现代码模块化、安全性和可维护性的基础。

7. 静态成员 (static)

在 Java 中,static关键字用于修饰成员变量、方法、代码块或内部类,被修饰的成员称为静态成员。静态成员属于类本身,而非类的某个实例(对象),因此可以直接通过类名访问,无需创建对象。

1. 静态成员变量(类变量)

静态成员变量是被static修饰的成员变量,属于类的所有实例共享,在内存中只有一份副本。

特点:
  • 不属于某个对象:所有对象共享同一份静态变量,修改它会影响所有对象。
  • 访问方式:可通过类名.变量名直接访问,也可通过对象访问(不推荐)。
  • 初始化时机:在类加载时初始化,早于对象的创建。
  • 默认值:与成员变量一样,有默认初始化值。
示例:

public class Student {private String name; // 实例变量(每个对象独有)public static String school; // 静态变量(所有对象共享)public Student(String name) {this.name = name;}public void showInfo() {System.out.println("姓名:" + name + ",学校:" + school);}
}// 使用示例
public class Test {public static void main(String[] args) {// 直接通过类名访问静态变量Student.school = "阳光中学";Student s1 = new Student("张三");Student s2 = new Student("李四");s1.showInfo(); // 姓名:张三,学校:阳光中学s2.showInfo(); // 姓名:李四,学校:阳光中学// 修改静态变量,所有对象都会受影响Student.school = "希望中学";s1.showInfo(); // 姓名:张三,学校:希望中学}
}

2. 静态方法(类方法)

静态方法是被static修饰的方法,属于类本身,可直接通过类名调用。

特点:
  • 不能访问非静态成员:静态方法中不能直接访问实例变量和非静态方法(因为它们属于对象,而静态方法调用时可能没有对象)。
  • 可以访问静态成员:静态方法中可以直接访问静态变量和其他静态方法。
  • 没有this关键字this代表当前对象,而静态方法属于类,不依赖对象存在。
  • 常用场景:工具类方法(如Math.random())、工厂方法等。
示例:

public class MathUtil {// 静态方法:计算两数之和public static int add(int a, int b) {return a + b;}// 静态方法:计算两数之积public static int multiply(int a, int b) {return a * b;}
}// 使用示例
public class Test {public static void main(String[] args) {// 直接通过类名调用静态方法,无需创建对象int sum = MathUtil.add(3, 5);int product = MathUtil.multiply(2, 4);System.out.println("和:" + sum); // 8System.out.println("积:" + product); // 8}
}

3. 静态代码块

静态代码块是被static修饰的代码块,用于初始化静态变量,在类加载时执行,且只执行一次。

特点:
  • 执行时机:类第一次被加载时自动执行,早于构造方法。
  • 执行顺序:多个静态代码块按定义顺序执行。
  • 作用:初始化静态资源(如加载配置文件、初始化静态变量等)。
示例:

public class DatabaseConfig {public static String url;public static String username;public static String password;// 静态代码块:初始化数据库配置static {System.out.println("加载数据库配置...");url = "jdbc:mysql://localhost:3306/test";username = "root";password = "123456";}public DatabaseConfig() {System.out.println("创建DatabaseConfig对象");}
}// 使用示例
public class Test {public static void main(String[] args) {// 第一次使用类时,静态代码块执行DatabaseConfig config1 = new DatabaseConfig();// 再次创建对象,静态代码块不再执行DatabaseConfig config2 = new DatabaseConfig();System.out.println("URL: " + DatabaseConfig.url);}
}/* 输出结果:
加载数据库配置...
创建DatabaseConfig对象
创建DatabaseConfig对象
URL: jdbc:mysql://localhost:3306/test
*/

4. 静态成员的注意事项

  • 生命周期:静态成员随类的加载而创建,随类的卸载而销毁,生命周期长于对象。
  • 内存位置:静态成员存储在方法区的静态区,而非堆内存。
  • 避免滥用:过度使用静态成员会增加代码耦合度,不利于面向对象的封装性。
  • 静态内部类:被static修饰的内部类称为静态内部类,可直接通过外部类名访问,不依赖外部类对象(常用于工具类)。

总结

static关键字的核心作用是将成员与类绑定,而非与对象绑定。合理使用静态成员可以简化代码(如工具类)、共享资源(如全局配置),但需注意其生命周期长、耦合度高的特点,避免设计上的不合理。

在 Java 中,当涉及父类与子类静态成员(静态属性、静态代码块)实例成员(实例属性、实例代码块) 和构造方法时,它们的执行顺序遵循严格的规则。核心原则是:静态内容先于非静态内容,父类内容先于子类内容

一、执行顺序总览

  1. 类加载阶段(只执行一次)
    当类第一次被使用时(如创建对象、调用静态成员),会加载类并执行静态相关内容,顺序为:
    父类静态属性初始化 → 父类静态代码块 → 子类静态属性初始化 → 子类静态代码块

  2. 对象实例化阶段(每次创建对象时执行)
    当通过new创建对象时,执行非静态相关内容,顺序为:
    父类实例属性初始化 → 父类实例代码块 → 父类构造方法 → 子类实例属性初始化 → 子类实例代码块 → 子类构造方法

二、详细说明

1. 静态内容(类加载时执行,仅一次)
  • 静态属性:被static修饰的成员变量,初始化语句在类加载时执行。
  • 静态代码块:被static修饰的代码块,用于初始化静态资源,在类加载时执行。
  • 执行规则
    • 父类静态内容 先于 子类静态内容执行(因为子类依赖父类)。
    • 同一类中,静态属性初始化和静态代码块 按定义顺序 执行。
2. 非静态内容(对象实例化时执行,每次创建对象都执行)
  • 实例属性:非static修饰的成员变量,初始化语句在对象创建时执行。
  • 实例代码块:无static修饰的代码块(直接用{}包裹),用于初始化实例资源。
  • 构造方法:用于对象初始化的特殊方法,最后执行。
  • 执行规则
    • 父类非静态内容 先于 子类非静态内容执行(子类构造方法会隐式调用父类构造方法)。
    • 同一类中,实例属性初始化和实例代码块 按定义顺序 执行,且都在构造方法之前执行。

第一次创建Child对象:
父类静态属性初始化
父类静态代码块执行
子类静态属性初始化
子类静态代码块执行
父类实例属性初始化
父类实例代码块执行
父类构造方法执行
子类实例属性初始化
子类实例代码块执行
子类构造方法执行第二次创建Child对象:
父类实例属性初始化
父类实例代码块执行
父类构造方法执行
子类实例属性初始化
子类实例代码块执行
子类构造方法执行

  1. 第一次创建对象时

    • 触发类加载,执行父类静态内容(静态属性→静态代码块),再执行子类静态内容(静态属性→静态代码块)。
    • 然后执行对象实例化:父类实例内容(实例属性→实例代码块→构造方法),再执行子类实例内容(实例属性→实例代码块→构造方法)。
  2. 第二次创建对象时

    • 类已加载,静态内容不再执行。
    • 仅重复执行对象实例化过程(父类实例内容→子类实例内容)。

关键注意点

  1. 静态内容唯一性:静态属性和静态代码块仅在类第一次加载时执行一次,与创建多少对象无关。
  2. 构造方法的隐含调用:子类构造方法中会隐含调用super()(父类无参构造),因此父类构造方法一定在子类构造方法之前执行。
  3. 定义顺序影响:同一类中,静态属性与静态代码块、实例属性与实例代码块的执行顺序,完全取决于它们在代码中的定义顺序。
  4. 继承的依赖性:子类的加载依赖父类,因此父类的所有初始化(静态 + 实例)都先于子类。

http://www.dtcms.com/a/348287.html

相关文章:

  • 南科大C++ 第二章知识储备
  • 电脑深度清理软件,免费磁盘优化工具
  • Shell脚本-如何生成随机数
  • 设置接收超时(SO_RCVTIMEO)
  • 8月精选!Windows 11 25H2 【版本号:26200.5733】
  • 牛市阶段投资指南
  • ffmpeg强大的滤镜功能
  • SingleFile网页保存插件本地安装(QQ浏览器)
  • 【图像处理基石】如何把非笑脸转为笑脸?
  • ffmpeg 问答系列-> mux 部分
  • 启动Flink SQL Client并连接到YARN集群会话
  • Node.js自研ORM框架深度解析与实践
  • 柱状图中最大的矩形+单调栈
  • STM32 入门实录:macOS 下从 0 到点亮 LED
  • Java全栈开发面试实录:从基础到实战的深度探讨
  • 微服务-19.什么是网关
  • 【论文阅读】AI 赋能基于模型的系统工程研究现状与展望
  • Redis--day12--黑马点评--附近商铺用户签到UV统计
  • Excel 表格 - 合并单元格、清除单元格格式
  • 包裹堆叠场景漏检率↓79%!陌讯多目标追踪算法在智慧物流的实践优化
  • EXCEL实现复制后倒序粘贴
  • 暗影哨兵:安全运维的隐秘防线
  • 深度学习部署实战 Ubuntu24.04单机多卡部署ERNIE-4.5-VL-28B-A3B-Paddle文心多模态大模型(详细教程)
  • 用墨刀开发能碳管理系统 —— 从流程图到设计稿全流程拆解
  • EAM、MES和CRM系统信息的整理
  • c语言指针学习
  • C文件编译
  • IQC、IPQC、PQC、FQC、OQC在ERP/MES/WMS中的系统协同
  • 【SBP】Unity 打包构建管线原理解析于对比
  • 什么是服装企业管理软件?