[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…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
