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

[Java]泛型(二)泛型方法

1.定义

在 Java 中,泛型方法是指在方法声明中使用泛型类型参数的一种方法。它使得方法能够处理不同类型的对象,而不需要为每种类型写多个方法,从而提高代码的重用性。

泛型方法与泛型类不同,泛型方法的类型参数仅仅存在于方法的范围内,而不是整个类的范围内。使用泛型方法时,可以在方法调用时指定实际的类型参数。

2.基本语法

泛型方法的语法结构与普通方法类似,只不过在方法返回类型前加上一个泛型参数列表(用尖括号<>表示)。泛型参数列表是类型参数(例如 <T>),可以是一个或多个。

public <T> 返回类型 方法名(参数列表) {// 方法体
}

例如: 

public <T> void methodName(T param) {// 方法实现
}

3.泛型方法的示例

3.1 示例:

3.1.1 示例1:打印任意类型的值

public class GenericMethodExample {// 泛型方法:打印任意类型的值public <T> void printValue(T value) {System.out.println(value);}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();example.printValue("Hello, World!");  // 输出:Hello, World!example.printValue(100);              // 输出:100example.printValue(3.14);             // 输出:3.14}
}
  • 这里的 <T> 是类型参数的声明,表示该方法可以接受任何类型的参数。
  • printValue 方法中,T 代表传递给方法的实际类型,在调用时根据实际传入的参数类型自动推导。

3.1.2 示例2:交换两个元素的位置

public class GenericMethodExample {// 泛型方法:交换两个元素的位置public <T> void swap(T[] array, int i, int j) {T temp = array[i];array[i] = array[j];array[j] = temp;}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 测试交换整数数组中的元素Integer[] intArray = {1, 2, 3, 4};example.swap(intArray, 0, 2);System.out.println(java.util.Arrays.toString(intArray));  // 输出:[3, 2, 1, 4]// 测试交换字符串数组中的元素String[] strArray = {"apple", "banana", "cherry"};example.swap(strArray, 0, 1);System.out.println(java.util.Arrays.toString(strArray));  // 输出:[banana, apple, cherry]}
}
  • 在这个例子中,swap 方法使用了泛型 T[] 数组和泛型类型 T,允许我们交换任何类型数组中的元素。
  • T[] 表示该方法可以接受任何类型的数组,并且 T 会在运行时根据传递的实际数组类型确定。

4.泛型方法的限制和注意事项

4.1 类型擦除

4.1.1 定义:

类型擦除(Type Erasure)是 Java 泛型的一项关键特性,它在编译时通过将泛型类型转换为原始类型(通常是 Object 或指定的边界类型)来实现泛型的类型安全,但在运行时丢失了对类型参数的具体信息。

4.1.2 为什么需要类型擦除?

Java 的泛型是 编译时的类型安全检查,而不是运行时的类型参数。因此,泛型类型的具体信息只存在于编译阶段,编译器会根据类型擦除机制将泛型转换成原始类型(通常是 Object)。这种做法可以在保证类型安全的同时,避免运行时因类型信息的传递导致的性能问题。

泛型的出现是为了增强代码的灵活性,同时 保持类型安全。但是,Java 的泛型并不支持在运行时保留类型信息,这是由于 Java的设计选择性能优化考虑。

4.2 类型擦除如何工作?

在 Java 编译器将泛型代码转换为字节码时,所有的泛型类型参数都会被替换为它们的 原始类型。对于不带类型边界的泛型,默认使用 Object 来替代类型参数。而对于有类型边界的泛型,编译器会将类型参数替换为边界类型。

示例:
public class Box<T> {private T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}
}

编译后,Box<T>会变成:

public class Box {private Object value;public Object getValue() {return value;}public void setValue(Object value) {this.value = value;}
}

所以 类型擦除的结果 是:

  • 泛型参数 T 被替换为 Object
  • 编译器会删除 T 的所有信息,只保留 Object 或者它的边界类型(如 Number)。
  • 你在使用泛型时,实际上操作的是 Object,即使在代码中看起来是 T

4.3  类型擦除的原因

类型擦除是 Java 设计的一种机制,其目的是确保 Java 的兼容性,同时增强泛型的灵活性:

  1. 向后兼容性

    • 在 Java 5 引入泛型之前,Java 已经有大量的代码和类库。为了让新版本的 Java 仍然能够兼容这些旧代码,泛型类型的具体信息必须在编译时被擦除。
    • 这样,即使老代码不支持泛型,新旧代码依然能够共存。
  2. 性能优化

    • 在 Java 中,泛型是 编译时的 类型检查,而不是 运行时的 类型参数。泛型的引入是为了提高代码的 类型安全,但同时为了避免在运行时进行类型检查和反射等耗费性能的操作,所有的类型信息会在编译后被擦除。
    • 运行时只有原始类型(如 Object),不再有泛型类型的负担,从而提高程序的性能。
  3. 简化实现

    • 由于在运行时不需要额外的类型信息,Java 只需要维护单一的原始类型(通常是 Object)的字节码结构。这简化了 Java 虚拟机(JVM)的实现,不需要考虑复杂的泛型类型。

4.4 类型擦除的具体实现细节

4.4.1 泛型的类型擦除

  • 编译器会用 Object 替换没有指定类型边界的泛型类型参数(如 T)。
  • 如果指定了类型边界(例如 T extends Number),编译器会用边界类型替代泛型类型参数。
示例:
public class Box<T> {public T value;public void setValue(T value) {this.value = value;}
}

类型擦除后的字节码

public class Box {public Object value;public void setValue(Object value) {this.value = value;}
}

4.4.2 具有边界的泛型

如果泛型带有边界,擦除时会使用边界类型。

public class Box<T extends Number> {public T value;public void setValue(T value) {this.value = value;}
}

类型擦除后的字节码

public class Box {public Number value;public void setValue(Number value) {this.value = value;}
}

4.4.3 为什么不能在运行时获取泛型类型信息?

  • 类型擦除后,泛型类型的具体信息被丢弃,JVM 在运行时只知道原始类型。这意味着你无法在运行时直接获取一个泛型类型参数的信息,例如通过 getClass()instanceof 等方法。这是因为在运行时,泛型参数已经被擦除为 Object 或指定的边界类型。

例如:

public <T> void printType(T value) {System.out.println(value.getClass().getName());  // 获取类型信息
}

调用 printType(new Integer(10)),输出 java.lang.Integer。但是,如果你使用 T 类型的 getClass(),它并不会返回 T 的类型,而是 Object,因为在运行时 T 已经被擦除。

4.5 泛型数组与类型擦除的冲突

在 Java 中创建泛型数组会导致问题,因为 类型擦除后的 T 被替换成了 Object,这使得编译器无法知道实际数组的类型。例如:

public <T> void example() {T[] array = new T[10];  // 编译错误:不能创建泛型数组
}

原因

  • 由于 T 在编译时被擦除为 Object,因此编译器无法确定 T[] 代表的实际类型。Java 无法知道该数组是 Integer[]String[] 还是其他类型的数组。
  • 数组的类型必须在运行时确定,因此无法通过泛型类型直接创建数组。

解决方法:使用反射或者使用 Object[] 来替代泛型数组。

4.6 类型擦除对集合类的影响

类型擦除影响最明显的地方是在集合类中,例如 List<T>,我们不能通过 List<T> 来确定元素的具体类型,因为泛型已经被擦除。

List<Integer> list = new ArrayList<>();

虽然我们创建了 List<Integer> 类型的集合,但在运行时,它其实是一个 List 类型的集合,元素类型已经变为 Object

4.7 如何解决类型擦除带来的问题

4.7.1 解决办法

为了绕开类型擦除的限制,可以使用以下几种方法:

  1. 反射(Reflection): 使用反射可以动态获取类型信息,比如 Array.newInstance() 可以在运行时创建泛型类型的数组。

  2. 传递 Class 对象: 通过传递 Class<T> 类型参数,我们可以在泛型方法中通过反射创建具体类型的数组。

  3. 使用 List 或其他集合类: 尽量避免使用数组,在需要泛型集合时,可以使用如 ArrayList<T>HashMap<K, V> 等通用集合类,它们对泛型有更好的支持,并且能够处理不同类型的数据。

4.7.2 注意事项

1.不能直接使用泛型数组

如之前所述,泛型数组在 Java 中是不被允许的,无法直接创建 T[] 类型的数组。需要使用 Object[] 或者通过反射等方式来实现。

2.类型参数的作用范围

泛型类型仅在方法体内有效。方法外部和其他类的泛型类型不会受到影响。

5.泛型方法的类型推导

5.1 定义

类型推导是指 Java 编译器根据实际传递给泛型方法的参数类型,自动推断出泛型类型参数的具体类型。这意味着你可以省略显式声明类型参数,编译器会在调用方法时根据传入的实参类型推导出泛型类型。

5.2 泛型方法类型推导的关键点

  • 编译器根据传入的实际类型来推导出泛型参数。
  • 你不需要显式指定泛型类型,编译器会根据方法调用的上下文进行推断。

5.3 类型推导的基本规则

在 Java 中,泛型方法的类型推导遵循以下基本规则:

  • 规则 1:根据方法调用时传递的参数类型自动推导泛型类型

    Java 编译器会根据传递给方法的实参的类型自动推导出泛型的实际类型。

  • 规则 2:类型推导基于方法调用时的参数类型

    传递给方法的参数类型将用于推导出泛型类型参数的类型。

  • 规则 3:如果方法调用的上下文不能唯一确定泛型类型,编译器会报错

    如果无法根据传入的参数明确推导出泛型类型,编译器会抛出错误。

5.4 泛型方法的类型推导示例:

5.4.1 示例1:简单的类型推导

public class GenericMethodExample {// 泛型方法,自动推导类型 Tpublic <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 传入 Integer 数组,编译器推导出 T 为 IntegerInteger[] intArray = {1, 2, 3, 4};example.printArray(intArray);// 传入 String 数组,编译器推导出 T 为 StringString[] strArray = {"apple", "banana", "cherry"};example.printArray(strArray);}
}
/*
输出:
1
2
3
4
apple
banana
cherry
*/

解释

  • printArray 方法中,类型参数 T 被推导为 Integer(在传递 Integer[] 时)和 String(在传递 String[] 时)。你无需显式指定类型参数,编译器会根据参数类型自动推导。

5.4.2 示例2:类型推导与多个参数

public class GenericMethodExample {// 泛型方法,接受多个参数public <T, U> void printPair(T first, U second) {System.out.println("First: " + first);System.out.println("Second: " + second);}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 传递 Integer 和 String,编译器推导出 T 为 Integer,U 为 Stringexample.printPair(1, "apple");// 传递 Double 和 Character,编译器推导出 T 为 Double,U 为 Characterexample.printPair(3.14, 'A');}
}
/*
输出:
First: 1
Second: apple
First: 3.14
Second: A
*/

解释

  • 在这个例子中,printPair 方法接受两个参数 firstsecond,分别是不同的类型。编译器根据传入的参数类型推导出泛型类型 TU 的具体类型。

5.5 类型推导的局限性与注意事项

虽然类型推导非常方便,但它也有一些局限性和需要注意的地方:

5.5.1 方法无法推导泛型类型时会报错

当 Java 编译器无法根据传递给泛型方法的参数推导出唯一的类型时,它会报错。例如,如果你传递了一个 null 值或其他无法确定类型的值,编译器就无法推导出类型。

public class GenericMethodExample {public <T> void printElement(T element) {System.out.println(element);}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 编译器无法推导出类型,因为传入的是 nullexample.printElement(null);  // 编译错误:null 值无法推导出具体类型}
}

解释

  • null 作为一个类型不确定的值,不能直接用于推导类型。在这种情况下,编译器无法确定泛型参数 T 的具体类型,因而报错。
5.5.2 类型推导失败时的明确类型声明

在无法自动推导出类型时,你可以显式地指定泛型类型参数。例如,使用 printElement(Integer) 来明确指定类型,而不是依赖推导。

public class GenericMethodExample {public <T> void printElement(T element) {System.out.println(element);}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 显式指定类型为 Integerexample.<Integer>printElement(10);}
}
 5.5.3 类型擦除与泛型类型推导(不能在泛型方法中直接创建数组)

即使你在方法中使用了泛型,Java 编译器在运行时会执行类型擦除,所有的泛型类型会在运行时被擦除为原始类型(通常是 Object)。因此,你无法在运行时直接通过泛型类型获得具体类型信息。

关于泛型方法中不能直接创建数组,因为类型擦除会把数组元素类型擦除,导致数组创建的时候u程序不知道要创建什么类型的数组,无法为数组分配空间,但是,有同学可能会有疑问:不是还有泛型类型推导吗,在使用泛型方法的时候不是将数组的类型传递进来了吗?为什么不能通过类型推导传递数组的数据类型,从而在泛型方法中创建数组呢?

这个问题涉及到 Java 泛型的 类型擦除机制,以及 数组的创建限制。尽管泛型类型可以通过方法的参数传递给方法,但是 数组的创建类型擦除 之间的关系使得无法直接推断出新建的泛型数组的类型。

5.5.3.1 为什么不能直接推断数组的类型?

类型擦除 是 Java 泛型的一大特性,它在编译时会将所有泛型类型擦除为 Object(或者在某些情况下是指定的边界类型),因此 在运行时并没有保留泛型类型的信息。具体到数组的创建,Java 不允许直接通过泛型类型来创建数组,因为在运行时,泛型类型 T 已经被擦除为 Object,而数组在运行时需要明确的类型。

详细解释:

  1. 泛型擦除与数组的创建

    • 当你在 Java 中定义了一个泛型方法:
      public <T> void example(T[] array) {T[] newArray = new T[10];  // 编译错误
      }
      

      你可能认为 T 是通过参数传递的,因此可以推断出 T 的类型并用它来创建一个新的数组。但问题是,在编译后,Java 编译器会将所有的泛型 T 替换为 Object(即发生了类型擦除),所以在运行时,T[] 就变成了 Object[]。这就导致了问题,因为 Java 不允许你直接通过 T 创建一个数组,因为在运行时 T 已经被擦除了。
  2. 泛型类型和数组的创建

    • 数组的创建与普通对象的创建不同。数组是一个 固定类型的数据结构,而且 Java 需要知道数组的元素类型,以便分配内存和进行类型安全检查。由于泛型类型在运行时没有保留,所以你无法通过泛型类型直接创建数组。例如,new T[10] 这样的写法会在编译时产生错误,原因是编译器无法确定 T 的实际类型。
    • 而且 Java 在运行时是通过 反射具体类型信息 来创建数组的,因此无法直接通过 T 来创建数组。

5.3.2 为什么传递类型参数后不能直接推断?

传递 T[] 类型的参数时,编译器已经能够根据方法调用来推断 T 的具体类型(如 IntegerString),但是在 方法内部创建数组时,编译器无法推断出 T[] 的具体类型,因为此时 Java 泛型类型已被擦除,运行时并没有存储类型信息。所以,即使你通过方法参数传递了类型,Java 仍然不知道如何通过泛型 T 来创建具体的数组。

举个例子:

假设你有一个泛型方法,并且你希望在方法内部创建一个泛型数组:

public <T> void example(T[] array) {T[] newArray = new T[10];  // 编译错误
}

这里,T[] 是一个泛型数组,你期望通过 T 创建一个数组。然而,由于 类型擦除T 会在编译时被擦除为 Object,所以 Java 不能确定在运行时应该创建什么类型的数组。换句话说,在运行时,T 就变成了 Object,所以无法创建 Object[] 类型的数组

5.5.4 如果一定要在泛型方法中创建一个数组,要怎么办?

1. 使用 Class 对象和反射来创建数组:

通过传递 Class<T> 类型参数,结合反射机制,可以动态创建泛型类型的数组。

import java.lang.reflect.Array;public class GenericMethodExample {public <T> void example(Class<T> clazz) {T[] newArray = (T[]) Array.newInstance(clazz, 10);  // 通过反射创建数组System.out.println(newArray.length);  // 输出:10}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();example.example(Integer.class);  // 创建 Integer 类型的数组example.example(String.class);   // 创建 String 类型的数组}
}
2. 使用 Object[] 数组:

一种简单的方式是,直接使用 Object[] 类型来存储泛型类型的元素,因为所有类型都会被转换为 Object 类型。

public <T> void example() {Object[] newArray = new Object[10];  // 使用 Object[]
}
3. 使用集合类(如 ArrayList)替代数组:

Java 泛型的使用主要是为了类型安全和灵活性。如果不需要严格使用数组,可以使用 ArrayList<T>,它是更通用的集合类型,能够处理不同类型的数据,并且不需要关注数组的大小。

import java.util.ArrayList;public <T> void example() {ArrayList<T> list = new ArrayList<>();  // 使用 ArrayListlist.add(someElement);  // 添加元素
}

5.6 泛型方法的多个类型参数

泛型方法不仅可以有一个类型参数,还可以有多个类型参数。这种情况下,你需要在方法声明中使用多个类型参数,并且在方法内部使用这些类型。

public class GenericMethodExample {// 泛型方法:接受多个类型参数public <T, U> void printPair(T first, U second) {System.out.println("First: " + first + ", Second: " + second);}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();// 使用不同类型的参数example.printPair("Hello", 100);  // 输出:First: Hello, Second: 100example.printPair(3.14, true);    // 输出:First: 3.14, Second: true}
}

在这个例子中,printPair 方法使用了两个泛型类型参数 TU,分别代表方法的两个不同参数类型。这样的方法可以灵活地处理不同类型的参数。 

6.泛型方法实际应用场景

1.最简单的泛型方法示例

public class GenericMethodExample {// 定义一个泛型方法,打印传入的参数public static <T> void print(T value) {System.out.println(value);}public static void main(String[] args) {// 调用泛型方法,传入不同类型的参数print("Hello, world!");   // 输出:Hello, world!print(123);               // 输出:123print(45.67);             // 输出:45.67}
}

在这个例子中,print 方法是一个泛型方法,<T> 表示方法可以接受任何类型的参数。我们调用 print 方法时,不需要指定类型,编译器会根据传入的参数类型推断出 T 的类型。

2.泛型方法的多重类型参数

public class GenericMethodExample {// 定义一个泛型方法,接受两个类型的参数public static <T, U> void printPair(T first, U second) {System.out.println("First: " + first);System.out.println("Second: " + second);}public static void main(String[] args) {printPair("Hello", 123);  // 输出 First: Hello  Second: 123printPair(45.67, true);    // 输出 First: 45.67  Second: true}
}

在这个例子中,<T, U> 表示泛型方法接受两个不同类型的参数。方法可以处理不同类型的传入数据。

3.泛型方法的规则

3.1 泛型方法与泛型类不同:泛型方法的类型参数只在方法内有效,而泛型类的类型参数在整个类内都有效。

3.2 类型推断:在调用泛型方法时,Java 编译器会自动推断类型参数。如果调用时没有显式指定类型,编译器会根据方法的参数自动推断。

3.3 多个类型参数:你可以为泛型方法定义多个类型参数(如 <T, U>)。

3.4 泛型方法可以是静态的:即使是静态方法,依然可以定义泛型类型参数。

3.5 类型安全:避免了类型强制转换,减少了运行时错误。

3.6 提高代码复用性:你可以在不同的情况下使用同一个方法,只需提供不同的类型参数。

3.7 简洁性:通过泛型方法,你不需要为每种类型写一个独立的方法,代码更加简洁。

3.8 通用的交换方法

public class GenericMethodExample {// 泛型方法,用于交换两个元素public static <T> void swap(T[] array, int i, int j) {T temp = array[i];array[i] = array[j];array[j] = temp;}public static void main(String[] args) {String[] names = {"Alice", "Bob", "Charlie"};swap(names, 0, 2);  // 交换 Alice 和 CharlieSystem.out.println(names[0]);  // 输出 CharlieSystem.out.println(names[2]);  // 输出 Alice}
}

泛型方法在集合中的应用

import java.util.List;public class GenericMethodExample {// 泛型方法,打印列表中的所有元素public static <T> void printList(List<T> list) {for (T item : list) {System.out.println(item);}}public static void main(String[] args) {List<String> list = List.of("Apple", "Banana", "Cherry");printList(list);}
}

相关文章:

[Java]泛型(二)泛型方法

1.定义 在 Java 中&#xff0c;泛型方法是指在方法声明中使用泛型类型参数的一种方法。它使得方法能够处理不同类型的对象&#xff0c;而不需要为每种类型写多个方法&#xff0c;从而提高代码的重用性。 泛型方法与泛型类不同&#xff0c;泛型方法的类型参数仅仅存在于方法的…...

如何监控ubuntu系统某个程序的运行状态,如果程序出现异常,对其自动重启。

在Ubuntu系统中&#xff0c;可以通过编写脚本结合cron或systemd来监控程序的运行状态&#xff0c;并在程序异常时自动重启。以下是具体步骤&#xff1a; 方法一&#xff1a;使用Shell脚本和Cron 编写监控脚本 创建一个Shell脚本来检查程序是否运行&#xff0c;并在程序异常时重…...

UE学习日志#15 C++笔记#1 基础复习

1.C20的import 看看梦开始的地方&#xff1a; import <iostream>;int main() {std::cout << "Hello World!\n"; } 经过不仔细观察发现梦开始的好像不太一样&#xff0c;这个import是C20的模块特性 如果是在VS里编写的话&#xff0c;要用这个功能需要新…...

CSS:跑马灯

<div class"swiper-container"><div class"swiper-wrapper"><!-- 第一组 --><div class"item" v-for"item in cardList" :key"first-item.id"><img :src"item.image" alt""…...

rust 自定义错误(十二)

错误定义&#xff1a; let file_content parse_file("test.txt");if let Err(e) file_content {println!("Error: {:?}", e);}let file_content parse_file2("test.txt");if let Err(e) file_content {match e {ParseFileError::File > …...

EWM 变更库存类型

目录 1 简介 2 配置 3 业务操作 1 简介 一般情况下 EWM 标准收货流程是 ROD&#xff08;Ready on Dock&#xff09; --> AFS&#xff08;Avaiable for Sale&#xff09;&#xff0c;对应 AG 001 --> AG 002&#xff0c;对应库存类型 F1 --> F2。 因业务需要反向进…...

AI大模型开发原理篇-9:GPT模型的概念和基本结构

基本概念 生成式预训练模型 GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型 是由 OpenAI 开发的基于 Transformer 架构的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;专门用于文本生成任务。它的设计理念在于通过大规模的预训练来学习语言模…...

MySQL数据库(二)

一 DDL (一 数据库操作 1 查询-数据库&#xff08;所有/当前&#xff09; 1 所有数据库&#xff1a; show databases; 2 查询当前数据库&#xff1a; select database(); 2 创建-数据库 可以定义数据库的编码方式 create database if not exists ax1; create database ax2…...

从0到1:C++ 开启游戏开发奇幻之旅(二)

目录 游戏开发核心组件设计 游戏循环 游戏对象管理 碰撞检测 人工智能&#xff08;AI&#xff09; 与物理引擎 人工智能 物理引擎 性能优化技巧 内存管理优化 多线程处理 实战案例&#xff1a;开发一个简单的 2D 射击游戏 项目结构设计 代码实现 总结与展望 游戏…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.18 逻辑运算引擎:数组条件判断的智能法则

1.18 逻辑运算引擎&#xff1a;数组条件判断的智能法则 1.18.1 目录 #mermaid-svg-QAFjJvNdJ5P4IVbV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QAFjJvNdJ5P4IVbV .error-icon{fill:#552222;}#mermaid-svg-QAF…...

EasyExcel写入和读取多个sheet

最近在工作中&#xff0c;作者频频接触到Excel处理&#xff0c;因此也对EasyExcel进行了一定的研究和学习&#xff0c;也曾困扰过如何处理多个sheet&#xff0c;因此此处分享给大家&#xff0c;希望能有所帮助 目录 1.依赖 2. Excel类 3.处理Excel读取和写入多个sheet 4. 执…...

LLM架构与优化:从理论到实践的关键技术

标题&#xff1a;“LLM架构与优化&#xff1a;从理论到实践的关键技术” 文章信息摘要&#xff1a; 文章探讨了大型语言模型&#xff08;LLM&#xff09;开发与应用中的关键技术&#xff0c;包括Transformer架构、注意力机制、采样技术、Tokenization等基础理论&#xff0c;以…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.22 形状操控者:转置与轴交换的奥秘

1.22 形状操控者&#xff1a;转置与轴交换的奥秘 目录 #mermaid-svg-Qb3eoIWrPbPGRVAf {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Qb3eoIWrPbPGRVAf .error-icon{fill:#552222;}#mermaid-svg-Qb3eoIWrPbPGRVAf…...

NLP模型大对比:Transformer >Seq2Seq > LSTM > RNN > n-gram

结论 Transformer 大于 传统的Seq2Seq 大于 LSTM 大于 RNN 大于 传统的n-gram n-gram VS Transformer 我们可以用一个 图书馆查询 的类比来解释它们的差异&#xff1a; 一、核心差异对比 维度n-gram 模型Transformer工作方式固定窗口的"近视观察员"全局关联的&q…...

DeepSeek部署教程(基于Ollama)

虽说在过年&#xff0c;但不能忘了学习。这几天科技圈最火的莫过于deepseek&#xff0c;我抽空也学习一下deepseek的部署过程&#xff0c;主要还是因为官方服务已经彻底瘫了[手动狗头]。 1、下载Ollama并安装 https://github.com/ollama/ollama/releases/latest/download/Oll…...

Java基础面试题总结(题目来源JavaGuide)

问题1&#xff1a;Java 中有哪 8 种基本数据类型&#xff1f;它们的默认值和占用的空间大小知道不&#xff1f; 说说这 8 种基本数据类型对 应的包装类型。 在 Java 中&#xff0c;有 8 种基本数据类型&#xff08;Primitive Types&#xff09;&#xff1a; 基本数据类型关键…...

WPS mathtype间距太大、显示不全、公式一键改格式/大小

1、间距太大 用mathtype后行距变大的原因 mathtype行距变大到底怎么解决-MathType中文网 段落设置固定值 2、显示不全 设置格式&#xff1a; 打开MathType编辑器点击菜单栏中的"格式(Format)"选择"间距(Spacing)"在弹出的对话框中调整"分数间距(F…...

宇宙大爆炸是什么意思

根据宇宙大爆炸学说&#xff0c;宇宙间的一切都在彼此远离&#xff0c;而且距离越远&#xff0c;远离的速度越快。我们只能在地球上观察这种现象&#xff0c;而我们观察到的速度符合如下公式&#xff0c;其中 为哈勃常数&#xff0c; 为距离&#xff0c; 为速度&#xff08;…...

MotionLCM 部署笔记

目录 依赖项 humanml3d&#xff1a; sentence-t5-large 下载数据&#xff1a; 报错&#xff1a;No module named sentence_transformers 继续报错&#xff1a;from transformers.integrations import CodeCarbonCallback 解决方法&#xff1a; GitHub - Dai-Wenxun/Moti…...

VLLM性能调优

1. 抢占 显存不够的时候&#xff0c;某些request会被抢占。其KV cache被清除&#xff0c;腾退给其他request&#xff0c;下次调度到它&#xff0c;重新计算KV cache。 报这条消息&#xff0c;说明已被抢占&#xff1a; WARNING 05-09 00:49:33 scheduler.py:1057 Sequence gr…...

ESP32-S3模组上跑通esp32-camera(39)

接前一篇文章:ESP32-S3模组上跑通esp32-camera(38) 一、OV5640初始化 2. 相机初始化及图像传感器配置 上一回继续对reset函数的后一段代码进行解析。为了便于理解和回顾,再次贴出reset函数源码,在components\esp32-camera\sensors\ov5640.c中,如下: static int reset…...

Linux《基础指令》

在之前的Linux《Linux简介与环境的搭建》当中我们已经初步了解了Linux的由来和如何搭建Linux环境&#xff0c;那么接下来在本篇当中我们就要来学习Linux的基础指令。在此我们的学习是包括两个部分&#xff0c;即指令和关于Linux的基础知识&#xff1b;因此本篇指令和基础知识的…...

9.进程间通信

9.进程间通信 **1. 进程间通信&#xff08;IPC&#xff09;概述****2. 无名管道&#xff08;Pipe&#xff09;****3. 有名管道&#xff08;FIFO&#xff09;****4. 信号通信&#xff08;Signal&#xff09;****5. 练习与作业****6. 信号的应用****7. 总结** 1. 进程间通信&…...

Windows中本地组策略编辑器gpedit.msc打不开/微软远程桌面无法复制粘贴

目录 背景 解决gpedit.msc打不开 解决复制粘贴 剪贴板的问题 启用远程桌面剪贴板与驱动器 重启RDP剪贴板监视程序 以上都不行&#xff1f;可能是操作被Win11系统阻止 最后 背景 远程桌面无法复制粘贴&#xff0c;需要查看下主机策略组设置&#xff0c;结果按WinR输入…...

供应链系统设计-供应链中台系统设计(十二)- 清结算中心设计篇(一)

概述 在之前的文章中&#xff0c;我们通过之前的两篇文章中&#xff0c;如下所示&#xff1a; 供应链系统设计-供应链中台系统设计&#xff08;十&#xff09;- 清结算中心概念片篇 供应链系统设计-供应链中台系统设计&#xff08;十一&#xff09;- 清结算中心概念片篇 说…...

Vue.js 单页应用(SPA)开发教程:从零开始构建你的第一个项目

单页应用&#xff08;SPA&#xff0c;Single Page Application&#xff09;是现代前端开发的主流模式。Vue.js 是一个非常适合构建 SPA 的框架&#xff0c;它通过 Vue Router 实现页面导航&#xff0c;通过组件化开发和状态管理实现复杂的交互功能。本篇教程将带你了解 SPA 的基…...

Linux C openssl aes-128-cbc demo

openssl 各版本下载 https://openssl-library.org/source/old/index.html#include <stdio.h> #include <string.h> #include <openssl/aes.h> #include <openssl/rand.h> #include <openssl/evp.h>#define AES_KEY_BITS 128 #define GCM_IV_SIZ…...

你了解哪些Java限流算法?

大家好&#xff0c;我是锋哥。今天分享关于【你了解哪些Java限流算法?】面试题。希望对大家有帮助&#xff1b; 你了解哪些Java限流算法? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Java 中常用的限流算法主要有以下几种&#xff0c;它们广泛应用于处理流量控…...

【漫话机器学习系列】065.梯度(Gradient)

梯度&#xff08;Gradient&#xff09; 在数学和机器学习中&#xff0c;梯度是一个向量&#xff0c;用来表示函数在某一点的变化方向和变化率。它是多变量函数的一阶偏导数的组合。 梯度的定义 设有一个标量函数 &#xff0c;它对 ​ 是可微的&#xff0c;则该函数在某一点的…...

BswM(基础软件管理)详解

BswM&#xff08;基础软件管理&#xff09;详解 BswM&#xff08;Basic Software Manager&#xff09; 是 AUTOSAR BSW 的核心模块之一&#xff0c;负责协调基础软件&#xff08;BSW&#xff09;各模块的行为&#xff0c;根据系统状态、规则或事件动态配置其他模块。其设计目标…...