跳到主要内容

代码块与动态数组

代码块

在Java中,代码块用于组织和控制代码的执行顺序。根据使用场景的不同,Java提供了四种类型的代码块:

普通代码块

普通代码块用于在方法内部定义一段代码,这些代码在方法被调用时执行。它们有助于控制变量的作用域和生命周期。

构造代码块

构造代码块是在类中直接定义的代码块,每当创建类的一个新实例时,这些代码块都会被执行。它们通常用于初始化对象的状态。

静态代码块

静态代码块使用 static 关键字定义,在类加载时执行一次,无论创建多少个实例。它们常用于初始化静态变量。

同步代码块

同步代码块用于控制多线程环境下对共享资源的访问,确保线程安全。通过 synchronized 关键字实现。

示例代码

以下示例展示了不同类型代码块的执行顺序和作用:

package com.oop;

public class Test10 {
public static void main(String[] args) {
CodeBlock codeBlock = new CodeBlock();
/*
* 执行顺序
* 1. 静态代码块
* 2. 构造代码块
* 3. 构造方法
* 4. 普通代码块
* 5. test 方法
* 6. 同步代码块
*/
}
}
package com.oop;

public class CodeBlock {
{
// 构造代码块:每次实例化对象时执行
System.out.println("构造代码块");
}

static {
// 静态代码块:类加载时执行一次
String name = "静态代码块";
System.out.println(name);
}

public CodeBlock() {
System.out.println("构造方法");
test();
}

public void test() {
String testName = "test";
{
// 普通代码块:控制变量作用域
String blockName = "普通代码块";
System.out.println(blockName);
System.out.println(testName);
}
// 无法访问 blockName
// System.out.println(blockName);

Person myTest = new Person();

synchronized (myTest) {
// 同步代码块:确保线程安全
System.out.println("同步代码块");
}
}
}

代码详解

  1. Test10 类
    Test10 类的 main 方法创建了一个 CodeBlock 对象。创建对象时,不同类型的代码块按照特定顺序执行。

  2. CodeBlock 类

    • 静态代码块:在类加载时执行,只运行一次。
    • 构造代码块:每次创建对象时执行。
    • 构造方法:初始化对象的主要属性,并调用 test 方法。
    • 普通代码块:在 test 方法中定义,控制变量的作用域。
    • 同步代码块:在多线程环境中使用,确保对共享资源的安全访问。

注意事项

  • 代码块的顺序
    理解不同类型代码块的执行顺序对于正确初始化对象和管理资源至关重要。

  • 变量作用域
    使用普通代码块可以限制变量的作用域,防止变量名冲突和意外修改。

  • 线程安全
    在多线程环境中,合理使用同步代码块可以避免数据竞争和不一致性问题。

动态数组

数组在Java中是一种基本的数据结构,用于存储固定大小的元素集合。然而,数组的长度在定义时确定后无法更改,这限制了其在需要动态调整大小的场景中的应用。为了解决这个问题,动态数组被引入,用于在运行时动态调整数组的大小。

动态数组的特点

动态数组具有以下特点:

  • 可变长度:可以根据需要动态增加或减少元素的数量。
  • 自动扩展:当数组容量不足时,动态数组会自动扩展其容量以容纳更多元素。
  • 高效访问:提供类似于普通数组的快速随机访问能力。

示例代码

以下示例展示了如何实现和使用一个简单的动态数组:

package com.oop;

import java.util.Arrays;

public class Test12 {
public static void main(String[] args) {
DynamicArray dynamicArray = new DynamicArray(5);
dynamicArray.push(1);
dynamicArray.push(1);
dynamicArray.push(1);
dynamicArray.push(1);
dynamicArray.push(9);
dynamicArray.push(9);
dynamicArray.push(9);
dynamicArray.push(9);
dynamicArray.push(9);
dynamicArray.push(9);

System.out.println(Arrays.toString(dynamicArray.getArray()));
}
}
package com.oop;

import java.util.Arrays;

public class DynamicArray {
private int[] array;
private int count;

public DynamicArray() {
this.array = new int[3];
this.count = 0;
}

public DynamicArray(int size) {
this.array = new int[size > 0 ? size : 3];
this.count = 0;
}

public int push(int num) {
if (count >= array.length) {
// 扩展数组容量
array = Arrays.copyOf(array, array.length * 3 / 2 + 1);
}
array[count++] = num;
return count;
}

public int[] getArray() {
return Arrays.copyOf(array, count);
}
}

代码详解

  1. Test12 类
    Test12 类的 main 方法创建了一个 DynamicArray 对象,初始容量为5。通过多次调用 push 方法向数组中添加元素,动态数组根据需要自动扩展其容量。最后,使用 Arrays.toString 方法打印数组的内容。

  2. DynamicArray 类

    • 属性

      • array:内部存储数组,用于保存元素。
      • count:当前元素的数量。
    • 构造方法
      提供了无参构造方法和带参构造方法,允许初始化数组的初始容量。

    • push 方法
      向动态数组中添加元素。如果当前数组已满,使用 Arrays.copyOf 方法扩展数组容量。然后,将新元素添加到数组中,并递增 count

    • getArray 方法
      返回当前动态数组中实际存储的元素,避免返回包含默认值的整个内部数组。

注意事项

  • 数组扩展策略
    动态数组在扩展时应选择合适的扩展因子,以平衡性能和内存使用。例如,上述示例中使用 array.length * 3 / 2 + 1 作为扩展因子。

  • 数据封装
    内部数组 array 被声明为 private,通过公共方法 pushgetArray 进行访问和修改,确保数据的封装性和安全性。

  • 性能考虑
    虽然动态数组提供了灵活性,但频繁的扩展操作可能影响性能。在设计时应根据预期的使用情况合理设置初始容量和扩展策略。

  • 线程安全
    上述实现并未考虑多线程环境下的线程安全问题。如果需要在多线程环境中使用,应引入同步机制或使用线程安全的数据结构。

注意事项

在使用代码块和动态数组时,应根据具体的应用场景和需求选择合适的实现方式。合理组织代码块可以提高代码的可读性和维护性,而动态数组的使用则可以在需要灵活数据存储时提供便利。确保理解每种代码块的执行顺序和作用范围,有助于编写高效、健壮的Java程序。