[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 的兼容性,同时增强泛型的灵活性:
-
向后兼容性:
- 在 Java 5 引入泛型之前,Java 已经有大量的代码和类库。为了让新版本的 Java 仍然能够兼容这些旧代码,泛型类型的具体信息必须在编译时被擦除。
- 这样,即使老代码不支持泛型,新旧代码依然能够共存。
-
性能优化:
- 在 Java 中,泛型是 编译时的 类型检查,而不是 运行时的 类型参数。泛型的引入是为了提高代码的 类型安全,但同时为了避免在运行时进行类型检查和反射等耗费性能的操作,所有的类型信息会在编译后被擦除。
- 运行时只有原始类型(如
Object
),不再有泛型类型的负担,从而提高程序的性能。
-
简化实现:
- 由于在运行时不需要额外的类型信息,Java 只需要维护单一的原始类型(通常是
Object
)的字节码结构。这简化了 Java 虚拟机(JVM)的实现,不需要考虑复杂的泛型类型。
- 由于在运行时不需要额外的类型信息,Java 只需要维护单一的原始类型(通常是
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 解决办法
为了绕开类型擦除的限制,可以使用以下几种方法:
-
反射(Reflection): 使用反射可以动态获取类型信息,比如
Array.newInstance()
可以在运行时创建泛型类型的数组。 -
传递
Class
对象: 通过传递Class<T>
类型参数,我们可以在泛型方法中通过反射创建具体类型的数组。 -
使用
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
方法接受两个参数first
和second
,分别是不同的类型。编译器根据传入的参数类型推导出泛型类型T
和U
的具体类型。
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
,而数组在运行时需要明确的类型。
详细解释:
-
泛型擦除与数组的创建:
- 当你在 Java 中定义了一个泛型方法:
public <T> void example(T[] array) {T[] newArray = new T[10]; // 编译错误 }
你可能认为T
是通过参数传递的,因此可以推断出T
的类型并用它来创建一个新的数组。但问题是,在编译后,Java 编译器会将所有的泛型T
替换为Object
(即发生了类型擦除),所以在运行时,T[]
就变成了Object[]
。这就导致了问题,因为 Java 不允许你直接通过T
创建一个数组,因为在运行时T
已经被擦除了。
- 当你在 Java 中定义了一个泛型方法:
-
泛型类型和数组的创建:
- 数组的创建与普通对象的创建不同。数组是一个 固定类型的数据结构,而且 Java 需要知道数组的元素类型,以便分配内存和进行类型安全检查。由于泛型类型在运行时没有保留,所以你无法通过泛型类型直接创建数组。例如,
new T[10]
这样的写法会在编译时产生错误,原因是编译器无法确定T
的实际类型。 - 而且 Java 在运行时是通过 反射 或 具体类型信息 来创建数组的,因此无法直接通过
T
来创建数组。
- 数组的创建与普通对象的创建不同。数组是一个 固定类型的数据结构,而且 Java 需要知道数组的元素类型,以便分配内存和进行类型安全检查。由于泛型类型在运行时没有保留,所以你无法通过泛型类型直接创建数组。例如,
5.3.2 为什么传递类型参数后不能直接推断?
传递 T[]
类型的参数时,编译器已经能够根据方法调用来推断 T
的具体类型(如 Integer
或 String
),但是在 方法内部创建数组时,编译器无法推断出 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
方法使用了两个泛型类型参数 T
和 U
,分别代表方法的两个不同参数类型。这样的方法可以灵活地处理不同类型的参数。
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 中,泛型方法是指在方法声明中使用泛型类型参数的一种方法。它使得方法能够处理不同类型的对象,而不需要为每种类型写多个方法,从而提高代码的重用性。 泛型方法与泛型类不同,泛型方法的类型参数仅仅存在于方法的…...

如何监控ubuntu系统某个程序的运行状态,如果程序出现异常,对其自动重启。
在Ubuntu系统中,可以通过编写脚本结合cron或systemd来监控程序的运行状态,并在程序异常时自动重启。以下是具体步骤: 方法一:使用Shell脚本和Cron 编写监控脚本 创建一个Shell脚本来检查程序是否运行,并在程序异常时重…...

UE学习日志#15 C++笔记#1 基础复习
1.C20的import 看看梦开始的地方: import <iostream>;int main() {std::cout << "Hello World!\n"; } 经过不仔细观察发现梦开始的好像不太一样,这个import是C20的模块特性 如果是在VS里编写的话,要用这个功能需要新…...

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 自定义错误(十二)
错误定义: 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(Ready on Dock) --> AFS(Avaiable for Sale),对应 AG 001 --> AG 002,对应库存类型 F1 --> F2。 因业务需要反向进…...

AI大模型开发原理篇-9:GPT模型的概念和基本结构
基本概念 生成式预训练模型 GPT(Generative Pre-trained Transformer)模型 是由 OpenAI 开发的基于 Transformer 架构的自然语言处理(NLP)模型,专门用于文本生成任务。它的设计理念在于通过大规模的预训练来学习语言模…...

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

从0到1:C++ 开启游戏开发奇幻之旅(二)
目录 游戏开发核心组件设计 游戏循环 游戏对象管理 碰撞检测 人工智能(AI) 与物理引擎 人工智能 物理引擎 性能优化技巧 内存管理优化 多线程处理 实战案例:开发一个简单的 2D 射击游戏 项目结构设计 代码实现 总结与展望 游戏…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.18 逻辑运算引擎:数组条件判断的智能法则
1.18 逻辑运算引擎:数组条件判断的智能法则 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
最近在工作中,作者频频接触到Excel处理,因此也对EasyExcel进行了一定的研究和学习,也曾困扰过如何处理多个sheet,因此此处分享给大家,希望能有所帮助 目录 1.依赖 2. Excel类 3.处理Excel读取和写入多个sheet 4. 执…...

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

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.22 形状操控者:转置与轴交换的奥秘
1.22 形状操控者:转置与轴交换的奥秘 目录 #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 我们可以用一个 图书馆查询 的类比来解释它们的差异: 一、核心差异对比 维度n-gram 模型Transformer工作方式固定窗口的"近视观察员"全局关联的&q…...

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

Java基础面试题总结(题目来源JavaGuide)
问题1:Java 中有哪 8 种基本数据类型?它们的默认值和占用的空间大小知道不? 说说这 8 种基本数据类型对 应的包装类型。 在 Java 中,有 8 种基本数据类型(Primitive Types): 基本数据类型关键…...

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

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

MotionLCM 部署笔记
目录 依赖项 humanml3d: sentence-t5-large 下载数据: 报错:No module named sentence_transformers 继续报错:from transformers.integrations import CodeCarbonCallback 解决方法: GitHub - Dai-Wenxun/Moti…...

VLLM性能调优
1. 抢占 显存不够的时候,某些request会被抢占。其KV cache被清除,腾退给其他request,下次调度到它,重新计算KV cache。 报这条消息,说明已被抢占: 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环境,那么接下来在本篇当中我们就要来学习Linux的基础指令。在此我们的学习是包括两个部分,即指令和关于Linux的基础知识;因此本篇指令和基础知识的…...

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

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

供应链系统设计-供应链中台系统设计(十二)- 清结算中心设计篇(一)
概述 在之前的文章中,我们通过之前的两篇文章中,如下所示: 供应链系统设计-供应链中台系统设计(十)- 清结算中心概念片篇 供应链系统设计-供应链中台系统设计(十一)- 清结算中心概念片篇 说…...

Vue.js 单页应用(SPA)开发教程:从零开始构建你的第一个项目
单页应用(SPA,Single Page Application)是现代前端开发的主流模式。Vue.js 是一个非常适合构建 SPA 的框架,它通过 Vue Router 实现页面导航,通过组件化开发和状态管理实现复杂的交互功能。本篇教程将带你了解 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限流算法?
大家好,我是锋哥。今天分享关于【你了解哪些Java限流算法?】面试题。希望对大家有帮助; 你了解哪些Java限流算法? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Java 中常用的限流算法主要有以下几种,它们广泛应用于处理流量控…...
【漫话机器学习系列】065.梯度(Gradient)
梯度(Gradient) 在数学和机器学习中,梯度是一个向量,用来表示函数在某一点的变化方向和变化率。它是多变量函数的一阶偏导数的组合。 梯度的定义 设有一个标量函数 ,它对 是可微的,则该函数在某一点的…...

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