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

Java大师成长计划之第4天:Java中的泛型

📢 友情提示:

本文由银河易创AI(https://ai.eaigx.com)平台gpt-4o-mini模型辅助创作完成,旨在提供灵感参考与技术分享,文中关键数据、代码与结论建议通过官方渠道验证。

在现代软件开发中,类型安全和代码重用是提高代码质量和开发效率的两个重要方面。Java 泛型(Generics)作为一种强大的机制,能够有效地解决这两个问题。本文将详细介绍 Java 中泛型的概念、使用方式及其带来的好处,帮助你更好地理解并应用泛型。

一、什么是泛型

泛型(Generics)是 Java 1.5 引入的一种强大特性,它允许开发者在定义类、接口和方法时使用类型参数。通过泛型,开发者能够编写更加灵活且类型安全的代码,避免许多类型相关的错误。

1.1 泛型的基本概念

泛型的核心思想是“类型参数化”,即在类或方法的定义中不指定具体的类型,而是使用一个或多个类型参数。这些类型参数在实例化时被具体的类型替代,从而使代码能够适用于多种数据类型。例如,定义一个泛型类时,可以使用一个占位符表示类型参数:

public class GenericBox<T> {private T item;public void setItem(T item) {this.item = item;}public T getItem() {return item;}
}

在这个例子中,GenericBox<T> 是一个泛型类,其中 T 是类型参数。在使用这个类时,可以用具体的类型替代 T,如 StringInteger 等,代码的灵活性得以增强。

1.2 泛型的目的

泛型的引入有几个主要目的:

  1. 类型安全:在编译时提供类型检查,确保程序的类型安全,帮助开发者在编写代码时发现潜在的类型错误。例如,如果我们使用泛型定义一个集合类,编译器会检查我们向集合中添加的元素是否是正确的类型,从而减少运行时错误的可能性。

  2. 减少强制转换:在使用泛型时,从集合中取出元素时,不需要进行强制类型转换。这不仅简化了代码,也减少了因类型转换不当导致的 ClassCastException 错误。

  3. 代码重用:泛型允许开发者编写通用的类和方法,减少代码重复。例如,通过定义一个泛型的方法,可以对不同类型的数据执行相同的操作,提升代码的重用性。

1.3 泛型的工作原理

在 Java 中,泛型的实现依赖于“类型擦除”机制。类型擦除是指在编译时,泛型的类型参数会被替换为其边界类型(如果没有边界,则为 Object)。这意味着在运行时,泛型信息是不可用的,这就是为什么在 Java 中不能创建泛型数组或使用基本数据类型作为泛型参数的原因。例如,泛型类的实例在运行时会被转换为非泛型类型:

GenericBox<String> stringBox = new GenericBox<>();

在编译后,stringBox 在字节码中实际上是 GenericBox,并且类型参数 String 会被擦除,因此从这个角度看,泛型主要是在编译时提供类型检查和安全性。

1.4 泛型的应用场景

  1. 集合框架:Java 的集合框架广泛使用泛型,如 List<T>Map<K, V> 等,使得开发者能够在集合中存储特定类型的对象,提高类型安全性。

  2. 自定义数据结构:开发者可以使用泛型定义自己的数据结构,如栈、队列、链表等,使其能够处理多种数据类型。

  3. 通用方法:泛型方法使得开发者可以编写通用的算法或操作,适用于多种类型的数据,增强了代码的灵活性。

1.5 总结

泛型是 Java 中一种重要的特性,它通过类型参数化实现了类型安全、减少强制转换和提高代码重用等优势。理解泛型的基本概念和工作原理,对于编写高质量、可维护的 Java 代码至关重要。在后续的学习中,深入掌握泛型的使用和应用场景,将使你在 Java 编程中更具竞争力。

二、泛型的使用

泛型在 Java 中的使用非常广泛,通过定义泛型类、泛型接口和泛型方法,开发者可以编写出灵活、可重用且类型安全的代码。下面将详细介绍泛型的几种主要使用方式。

2.1 泛型类

泛型类是将类型参数化的一种类定义方式。在定义泛型类时,可以声明一个或多个类型参数,使得类能够处理不同数据类型的对象。

2.1.1 定义泛型类

泛型类的定义与普通类相似,只需在类名后面加上类型参数。例如,定义一个可以存储任意类型对象的容器类:

public class Box<T> {private T item;public void setItem(T item) {this.item = item;}public T getItem() {return item;}
}

在上面的代码中,T 是一个类型参数,可以在实例化时替换为具体的类型。

2.1.2 使用泛型类

使用泛型类时,创建对象时需要指定具体的类型。例如:

public class Main {public static void main(String[] args) {Box<String> stringBox = new Box<>();stringBox.setItem("Hello, Generics!");System.out.println(stringBox.getItem());Box<Integer> integerBox = new Box<>();integerBox.setItem(123);System.out.println(integerBox.getItem());}
}

在这个例子中,stringBoxintegerBox 分别是 Box 类的实例,使用不同的类型参数 StringInteger。这样能够确保 Box 中存储的类型是安全的,且在编译时进行类型检查。

2.2 泛型接口

泛型接口允许在接口声明中使用类型参数,任何实现该接口的类都需要指定具体的类型,从而增强了接口的灵活性和可重用性。

2.2.1 定义泛型接口

定义泛型接口时,需要在接口名后面声明类型参数。例如:

public interface Pair<K, V> {K getKey();V getValue();
}

在这个示例中,Pair 接口定义了两个类型参数 KV,分别表示键和值。

2.2.2 实现泛型接口

实现泛型接口的类需要指定具体的类型参数。例如:

public class OrderedPair<K, V> implements Pair<K, V> {private K key;private V value;public OrderedPair(K key, V value) {this.key = key;this.value = value;}@Overridepublic K getKey() {return key;}@Overridepublic V getValue() {return value;}
}

使用泛型接口的示例:

public class Main {public static void main(String[] args) {Pair<String, Integer> pair = new OrderedPair<>("Apple", 1);System.out.println("Key: " + pair.getKey() + ", Value: " + pair.getValue());}
}

在这个例子中,OrderedPair 实现了 Pair 接口,并在实例化时指定了具体的类型参数 StringInteger

2.3 泛型方法

泛型方法是指在方法的定义中使用类型参数,这使得方法可以接收不同类型的参数并返回相应类型的结果。泛型方法的定义可以与普通方法相结合。

2.3.1 定义泛型方法

定义泛型方法时,需要在返回类型前声明类型参数。例如:

public class GenericMethod {public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
}

在这个示例中,printArray 是一个泛型方法,接收一个泛型数组并打印每个元素。

2.3.2 使用泛型方法

使用泛型方法时,可以直接调用,无需显式指定类型参数,编译器会根据传入参数的类型自动推断。

public class Main {public static void main(String[] args) {String[] stringArray = {"Java", "泛型", "示例"};Integer[] integerArray = {1, 2, 3, 4};System.out.println("字符串数组元素:");GenericMethod.printArray(stringArray);System.out.println("整数数组元素:");GenericMethod.printArray(integerArray);}
}

在这个例子中,printArray 方法被调用来打印不同类型的数组,展示了泛型方法的灵活性。

2.4 泛型的边界

在某些情况下,可能需要限制泛型参数的类型范围,可以使用边界来实现这种限制。Java 支持两种类型的边界:上边界和下边界。

2.4.1 上边界

上边界使用 extends 关键字定义,表示类型参数可以是指定类的子类或实现该接口的类。示例如下:

public class NumericBox<T extends Number> {private T number;public NumericBox(T number) {this.number = number;}public double doubleValue() {return number.doubleValue();}
}

在这个示例中,NumericBox 的类型参数 T 限制为 Number 或其子类(如 IntegerDouble 等)。

2.4.2 下边界

下边界使用 super 关键字定义,表示类型参数可以是指定类的父类。使用下边界的示例相对较少,通常用于方法参数中。

public static <T> void addElements(List<? super T> list, T element) {list.add(element);
}

在这个方法中,list 的类型参数可以是 T 的父类,允许向列表中添加元素。

2.5 泛型的局限性

虽然泛型带来了很多好处,但在使用时也需要注意一些局限性:

  1. 不能使用基本数据类型:泛型只能使用对象类型,不能使用基本数据类型,如 intchar 等,应该使用对应的包装类,如 IntegerCharacter

  2. 不能创建泛型数组:无法直接创建泛型类型的数组,例如 new T[10] 会导致编译错误。

  3. 类型擦除:在运行时,类型参数会被擦除为其边界类型(如果没有边界则为 Object),因此无法在运行时获取泛型的实际类型。

2.6 总结

泛型是 Java 中一个强大且灵活的特性,通过定义泛型类、接口和方法,开发者能够实现代码的类型安全、可重用性和灵活性。掌握泛型的使用不仅可以帮助你编写高质量的代码,还能提高程序的健壮性和可维护性。在实际开发中,应合理运用泛型,以实现最佳的编程实践。

三、泛型的优点

泛型是 Java 编程语言中的一项重要特性,它为开发者提供了强大的工具,用于编写类型安全、可重用和易于维护的代码。使用泛型可以带来许多显著的优点,下面我们将详细探讨这些优点。

3.1 类型安全

泛型的一个主要优点是提供了类型安全性。通过在编译时进行类型检查,泛型能够确保程序在运行期间不会出现类型不匹配的错误。

3.1.1 编译时检查

在使用泛型时,编译器会检查类型参数的使用情况。这意味着如果开发者试图将错误类型的对象插入集合中,编译器会在编译阶段就抛出错误,而不是在运行时抛出 ClassCastException

List<String> stringList = new ArrayList<>();
stringList.add("Hello");
// stringList.add(123); // 编译错误,类型不匹配

在这个示例中,尝试向 List<String> 中添加一个整数会导致编译错误,这种机制有效地避免了运行时错误。

3.2 减少强制类型转换

在没有泛型的情况下,开发者经常需要进行强制类型转换,以确保从集合中取出的对象是正确的类型。这种做法不仅增加了代码的复杂性,还可能导致运行时错误,因为强制转换失败会抛出 ClassCastException。使用泛型后,从集合中获取元素的操作不再需要强制类型转换:

List<String> strings = new ArrayList<>();
strings.add("Java");// 不需要强制转换
String str = strings.get(0);

在这个例子中,strings.get(0) 返回的已经是 String 类型,开发者可以直接使用,而不需要额外的强制转换步骤。

3.3 代码重用性

泛型允许开发者编写通用的算法和数据结构,从而大大提高代码的重用性。通过使用类型参数,开发者可以构建可以用于多种类型的类或方法,避免重复编写相似代码。

3.3.1 通用数据结构

例如,开发者可以定义一个泛型栈类,它可以存储任何类型的对象:

public class GenericStack<T> {private List<T> elements = new ArrayList<>();public void push(T item) {elements.add(item);}public T pop() {if (elements.isEmpty()) {throw new EmptyStackException();}return elements.remove(elements.size() - 1);}
}

在这个示例中,GenericStack 类可以存储任意类型的对象,开发者无需为每种类型分别实现一个栈类,这样的设计大大提高了代码的重用性。

3.3.2 通用方法

泛型方法使得开发者可以创建通用的操作,例如一个打印数组的泛型方法:

public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}
}

这个方法可以接受任何类型的数组,无需为不同类型的数组编写多个方法。

3.4 提高代码可读性

使用泛型可以使代码更加清晰,增强可读性。在定义和使用泛型时,开发者能够一目了然地了解各种数据类型的预期和使用方式。例如,List<String> 显示了集合中将存储 String 类型的元素,这使得代码的意图更加明确。

3.4.1 清晰的接口

泛型可以让接口的设计更加明确。在处理集合时,使用泛型可以让开发者快速理解集合中存储的类型。例如,Map<String, Integer> 表示一个映射,键为 String 类型,值为 Integer 类型,这种清晰的接口设计使得 API 的使用更加直观。

Map<String, Integer> ageMap = new HashMap<>();
ageMap.put("Alice", 30);
ageMap.put("Bob", 25);

在这个示例中,ageMap 的类型清楚地表明了键和值的类型,增强了代码的可读性。

3.5 支持多态性

泛型还支持多态性,使得代码能够处理不同类型的对象。这种灵活性在处理复杂数据结构时非常有用。例如,假设你有一个方法,它接受一个泛型列表,可以处理任何类型的对象:

public static <T> void processList(List<T> list) {for (T item : list) {// 处理每个元素System.out.println(item);}
}

在这种情况下,processList 方法可以接受 List<String>List<Integer>,甚至 List<CustomObject> 类型的列表,这使得该方法在处理不同类型的数据时具有很大的灵活性。

3.6 更好的与 Java Collections 框架兼容

Java 的集合框架(如 ListMapSet 等)广泛使用泛型,这使得开发者能够更好地与这些数据结构进行交互。通过使用泛型,开发者可以在操作集合时获得更好的类型安全性和更少的类型转换。

例如,使用泛型可以确保在集合操作过程中,类型始终保持一致,减少了因为涉及不同类型而导致的潜在错误。

3.7 总结

Java 泛型为开发者提供了一种强大的机制,带来了类型安全、减少强制类型转换、提高代码重用性、增强可读性、支持多态性及与集合框架的良好兼容性等诸多优点。掌握和合理运用泛型将极大地提升代码的质量和开发效率,帮助开发者编写出更健壮、可维护的 Java 应用程序。在实际开发中,充分利用泛型的优势,将是提升编程能力的重要一步。

四、泛型的限制

虽然泛型为 Java 编程带来了众多优势,但在使用泛型时也存在一些限制和注意事项。这些限制主要源自 Java 的设计和类型擦除机制,了解这些限制有助于开发者更加有效地使用泛型,避免潜在的问题。下面将详细讨论泛型的主要限制。

4.1 不能使用基本数据类型

在 Java 中,泛型只能使用对象类型而不能直接使用基本数据类型(如 intchardouble 等)。这意味着如果需要使用基本数据类型,必须使用相应的包装类(如 IntegerCharacterDouble 等)。

4.1.1 示例
// 错误示例
// GenericBox<int> intBox; // 编译错误,不能使用基本数据类型// 正确示例
GenericBox<Integer> intBox = new GenericBox<>(); // 使用包装类

这种限制的原因是 Java 泛型使用的是类型擦除机制,在运行时所有泛型参数的信息都会被删除,而基本数据类型没有对应的类型信息。使用包装类不仅符合泛型的要求,还可以使代码更具一致性。

4.2 不能创建泛型数组

在 Java 中,不能直接创建泛型类型的数组。这是因为类型擦除的原因,编译器无法确定运行时数组的具体类型。这会导致在创建泛型数组时出现编译错误。

4.2.1 示例
// 错误示例
// T[] array = new T[10]; // 编译错误,不能创建泛型数组// 正确示例
List<T> list = new ArrayList<>(); // 使用集合替代数组

解决这一问题的常用方法是使用集合类(如 ArrayList)来代替数组,集合类可以动态调整大小,且不会遇到类型擦除的问题。

4.3 不能使用静态泛型数据成员

在泛型类中,不能使用类型参数来定义静态数据成员。这是因为静态成员属于类本身,而不是类的实例,因此无法确定具体的类型。

4.3.1 示例
public class GenericClass<T> {// 错误示例// private static T staticMember; // 编译错误,不能使用类型参数定义静态成员private T instanceMember;public GenericClass(T instanceMember) {this.instanceMember = instanceMember;}
}

为了在类中使用静态成员,通常采用不使用类型参数的方式,或者使用具体的类型来定义静态成员。

4.4 不能在静态上下文中引用类型参数

使用泛型时,不能在静态方法或静态成员中引用类型参数。这是因为静态成员属于类而非特定实例,因此在静态上下文中无法访问实例的类型参数。

4.4.1 示例
public class GenericClass<T> {// 错误示例// private static T staticMethod() { return null; } // 编译错误public T instanceMethod() {return null; // 正确,实例方法可以使用类型参数}
}

在这个例子中,静态方法不能使用类型参数 T,但实例方法可以正常使用。这一限制促使开发者在设计类时考虑如何使用类型参数。

4.5 类型擦除

Java 泛型的工作原理是基于类型擦除,意味着在编译时,泛型的类型信息会被擦除,取而代之的是边界类型(如果有的话)或 Object。这使得在运行时无法获取泛型的具体类型。

4.5.1 示例
public class GenericBox<T> {private T item;public void setItem(T item) {this.item = item;}public T getItem() {return item;}
}public class Main {public static void main(String[] args) {GenericBox<String> box = new GenericBox<>();System.out.println(box.getClass()); // 输出 GenericBox// System.out.println(box.getItem().getClass()); // 运行时无法获取 T 的具体类型}
}

在这个例子中,通过 box.getClass() 可以获得 GenericBox 的类信息,但无法获取具体的类型参数 T 的信息。这一特性在某些情况下可能导致开发者无法使用特定的类型信息进行某些操作。

4.6 限制的影响

诸如类型擦除和无法使用基本数据类型等限制,可能会影响某些设计模式和算法的实现。例如,开发者在设计数据结构时必须考虑如何处理基本数据类型,可能需要额外的包装和转换。

4.7 总结

虽然泛型在 Java 编程中提供了许多优势,但开发者在使用泛型时也应了解其限制。这些限制主要包括不能使用基本数据类型、不能创建泛型数组、不能在静态上下文中引用类型参数以及类型擦除等。理解这些限制将有助于开发者在设计和实现泛型相关的代码时做出更明智的选择,从而提高代码的质量和可维护性。在实际开发中,合理利用泛型的优势,同时规避其限制,是成为一个高效 Java 开发者的重要一步。

五、总结

在本文中,我们深入探讨了 Java 中的泛型,包括其定义、使用方式、优点以及限制。泛型作为 Java 语言的一项重要特性,极大地增强了类型安全性、代码的可重用性和可读性,为开发者在编写高质量代码时提供了有效的工具。

5.1 泛型的核心优势

  1. 类型安全:泛型通过在编译时进行类型检查,减少了因类型不匹配而导致的运行时错误。这意味着开发者可以在编写代码时提前发现潜在的问题,确保代码的稳定性和可靠性。

  2. 减少强制类型转换:使用泛型时,从集合或其他泛型类型中获取元素时,不再需要进行强制类型转换。这简化了代码,并减少了可能因错误转换而导致的异常。

  3. 提高代码重用性:泛型使开发者能够编写通用的类和方法,适用于多种数据类型,避免了为每种类型重复编写相似代码的必要。这种灵活性使得代码的维护和扩展变得更加简单和高效。

  4. 增强可读性:泛型提供了明确的类型信息,使代码的意图更加清晰。例如,通过 List<String>List<Integer> 等定义,开发者可以一目了然地知道集合中存储的元素类型。这种清晰性在协作开发和代码审阅中尤为重要。

  5. 与集合框架的良好兼容性:Java 的集合框架广泛采用泛型,开发者在使用集合类时,可以充分利用泛型的优势,提高代码的类型安全性和一致性。

5.2 泛型的局限性与挑战

尽管泛型有诸多优点,但也存在一些限制:

  1. 不能使用基本数据类型:泛型只能接受对象类型,开发者需要使用包装类来处理基本数据类型,这在某些情况下可能增加代码的复杂性。

  2. 不能创建泛型数组:由于类型擦除的原因,无法直接创建泛型数组,开发者需要使用集合类来处理动态数据。

  3. 静态上下文中的限制:在静态方法或静态成员中,无法引用类型参数,这要求设计者在类和方法的结构上进行一定的调整。

  4. 类型擦除的影响:类型擦除使得在运行时无法访问泛型的实际类型信息,这在某些情况下可能限制了开发者的灵活性。

5.3 实践中的应用

在实际开发中,合理使用泛型可以有效提高代码的质量和可维护性。开发者应当在设计类和方法时,考虑如何利用泛型来提升灵活性和安全性。同时,了解泛型的限制也同样重要,以避免在编程过程中遇到意想不到的问题。

5.4 未来的学习与提升

随着对 Java 泛型的深入理解,开发者可以更自信地使用这一特性,编写出更为复杂和高效的代码。此外,结合 Java 8 及以后的新特性,如流(Streams)和 lambda 表达式,开发者可以进一步提升泛型的使用效果,实现更简洁和功能强大的代码。

总之,泛型在 Java 编程中扮演着不可或缺的角色。掌握泛型不仅能帮助开发者编写出更高质量的代码,还能提高开发效率,是成为一名优秀 Java 程序员的重要一步。希望本文能够帮助你更好地理解和应用泛型,在你的 Java 学习和开发之旅中继续前行。

相关文章:

Java大师成长计划之第4天:Java中的泛型

&#x1f4e2; 友情提示&#xff1a; 本文由银河易创AI&#xff08;https://ai.eaigx.com&#xff09;平台gpt-4o-mini模型辅助创作完成&#xff0c;旨在提供灵感参考与技术分享&#xff0c;文中关键数据、代码与结论建议通过官方渠道验证。 在现代软件开发中&#xff0c;类型安…...

计算机学报 2024年 区块链论文 录用汇总 附pdf下载

计算机学报 Year&#xff1a;2024 1 Title: 区块链中的公钥密码&#xff1a;设计、分析、密评与展望 Authors: Key words: 区块链&#xff1b;公钥密码算法&#xff1b;算法设计&#xff1b;复杂性分析&#xff1b;密评 Abstract: 比特币的成功&#xff0c;吸引了人们研…...

【Castle-X机器人】三、紫外消杀模块安装与调试

持续更新。。。。。。。。。。。。。。。 【Castle-X机器人】紫外消杀模块安装与调试 三、紫外消杀模块安装与调试2.1 安装2.2 调试2.2.1 紫外消杀模块话题2.2.2 测试 三、紫外消杀模块安装与调试 2.1 安装 使用相应工具将紫外消杀模块固定在Castle-X机器人底盘 2.2 调试 2.2…...

精益数据分析(29/126):深入剖析电子商务商业模式

精益数据分析&#xff08;29/126&#xff09;&#xff1a;深入剖析电子商务商业模式 在创业和数据分析的学习道路上&#xff0c;我们始终在探索如何更精准地把握商业规律&#xff0c;提升业务的竞争力。今天&#xff0c;我们依旧怀揣着共同进步的愿望&#xff0c;深入解读《精…...

AI图像编辑器 Luminar Neo 便携版 Win1.24.0.14794

如果你对图像编辑有兴趣&#xff0c;但又不想花费太多时间学习复杂的软件操作&#xff0c;那么 Luminar Neo 可能就是你要找的完美工具。作为一款基于AI技术的创意图像编辑器&#xff0c;Luminar Neo简化了复杂的编辑流程&#xff0c;即使是没有任何图像处理经验的新手&#xf…...

在Mybatis中为什么要同时指定扫描mapper接口和 mapper.xml 文件,理论单独扫描 xml 文件就可以啊

设计考虑因素 历史兼容性&#xff1a; MyBatis早期版本主要依赖XML配置&#xff0c;后来才引入接口绑定方式同时支持两种方式可以保证向后兼容 明确性&#xff1a; 显式指定两种路径可以使映射关系更加明确减少因命名不一致导致的潜在问题 性能考虑&#xff1a; 同时扫描可…...

MyBatis XML 配置完整示例(含所有核心配置项)

MyBatis XML 配置完整示例&#xff08;含所有核心配置项&#xff09; 1. 完整 mybatis-config.xml 配置文件 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""htt…...

【数据结构入门训练DAY-24】美国大选

文章目录 前言一、题目二、解题思路结语 前言 本次训练内容 训练STL中sort的操作方法。训练解题思维。 一、题目 美国大选是按各州的投票结果来确定最终的结果的&#xff0c;如果得到超过一半的州的支 持就可以当选&#xff0c;而每个州的投票结果又是由该州选民投票产生…...

stm32L4R5ZI Nucleo-144 GPIO点灯及按键中断

文章目录 前言一、CubeMx环境配置二、GPIO点灯操作三、按键中断点灯总结 前言 STM32L4R5ZI Nucleo-144是STMicroelectronics推出的一款基于ARM Cortex-M4内核的微控制器芯片。它是STM32L4系列中的一员&#xff0c;针对低功耗和高性能的应用而设计。以下是一些关键特点和技术规格…...

访问Redis时遇到 unknown command ‘FT.INFO‘, with args beginning with 错误的解决方案

在B站学习 图灵程序员-诸葛 的LangChain入门课程《基于Redis保存历史聊天信息》。在实践代码时遇到了一些问题&#xff0c;在这里记录一下&#xff0c;希望能帮助到也在学习的同学。话不多说&#xff0c;上代码&#xff0c;这段代码使用langchain_redis来持久化大模型对话的聊天…...

Swift与iOS内存管理机制深度剖析

前言 内存管理是每一位 iOS 开发者都绕不开的话题。虽然 Swift 的 ARC&#xff08;自动引用计数&#xff09;极大简化了开发者的工作&#xff0c;但只有深入理解其底层实现&#xff0c;才能写出高效、健壮的代码&#xff0c;避免各种隐蔽的内存问题。本文将从底层原理出发&…...

数据库系统概论(五)关系模型的数据结构及形式化

数据库系统概论&#xff08;五&#xff09;关系模型的数据结构及形式化 前言一、关系&#xff1a;从“表格”说起1.1 关系数据模型中的“关系”是什么&#xff1f;1.2 域&#xff08;Domain&#xff09;&#xff1a;数据的“类型限定”1.3 笛卡尔积&#xff08;Cartesian Produ…...

Python类和对象四(十三)

魔法方法&#xff1a; 按位运算 按位于运算 只要相同才是1 或运算&#xff1a; 只要某个位是1结果就是1 、 按位非 将结果取反 按位异或&#xff1a; 左移和右移运算符&#xff1a; 右移两位 右移动n位&#xff0c;就是除以2的n次方 左移两位&#xff1a; 左移n位就是乘…...

Go 1.24 中的弱指针包 weak 使用介绍

在 Go 语言中&#xff0c;“弱指针”指的是不会阻止垃圾回收器&#xff08;GC&#xff09;回收目标对象的引用。 当一个对象只剩弱指针指向它&#xff0c;而没有任何强引用时&#xff0c;GC 仍会把该对象当作不可达对象并回收&#xff1b;随后&#xff0c;所有指向它的弱指针会…...

毕业项目-基于深度学习的入侵检测系统

选题背景与意义 随着互联网技术的飞速发展&#xff0c;网络在各个领域中的作用日益重要。然而&#xff0c;伴随着技术的进步&#xff0c;网络安全问题也愈加严峻&#xff0c;网络攻击事件频繁发生&#xff0c;给个人、企业乃至国家带来了巨大的经济损失与安全威胁。入侵检测系…...

Github 2025-04-26 Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-04-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General Public Li…...

【Hive入门】Hive分桶表深度解析:从哈希分桶到Join优化的完整指南

目录 引言 1 分桶表基础概念 1.1 什么是分桶表 1.2 分桶与分区的区别 2 分桶表设计与创建 2.1 创建分桶表语法 2.2 分桶键选择原则 2.3 桶数确定策略 3 分桶表数据加载 3.1 标准数据加载流程 3.2 分桶表数据验证 4 分桶Join优化原理 4.1 Map端Join优化 4.2 Sort-…...

django之优化分页功能(利用参数共存及封装来实现)

优化分页功能 目录 1.封装分页代码 2.解决分页时覆盖搜索参数的bug 3.优化分页功能 上一篇文章我们讲到了搜索功能和分页展示数据功能。那这篇文章, 在上篇文章的基础上, 会去优化这些功能并解决搜索功能和分页功能不能一起使用的bug。 一、封装分页代码 原本我们的asse…...

linux blueZ 第四篇:BLE GATT 编程与自动化——Python 与 C/C++ 实战

本篇聚焦 BLE(Bluetooth Low Energy)GATT 协议层的编程与自动化实践,涵盖 GATT 基础、DBus API 原理、Python(dbus-next/bleak)示例、C/C++ (BlueZ GATT API)示例,以及自动发现、读写特征、订阅通知、安全配对与脚本化测试。 目录 BLE GATT 基础概念 BlueZ DBus GATT 模…...

前端面试每日三题 - Day 16

这是我为准备前端/全栈开发工程师面试整理的第16天每日三题练习&#xff0c;涵盖事件循环深入解析 、Vue3 响应式系统原理 &#xff0c;以及 多租户系统设计实践。每道题附带 详细解析、示例代码与脑图建议&#xff0c;助你全面掌握底层原理与架构设计思维。 ✅ 题目 1&#xf…...

使用PyTorch实现简单图像识别(基于MNIST手写数字数据集)的完整代码示例,包含数据加载、模型定义、训练和预测全流程

以下是一个使用PyTorch实现简单图像识别&#xff08;基于MNIST手写数字数据集&#xff09;的完整代码示例&#xff0c;包含数据加载、模型定义、训练和预测全流程&#xff1a; import torch import torch.nn as nn import torch.optim as optim import torchvision import torc…...

【Android】四大组件之Activity

目录 一、什么是Activity 二、如何创建和配置Activity 三、Activity 跳转与数据传递 四、数据保存与恢复 五、Activity 启动模式 六、自定义返回行为 七、复杂界面布局 你可以把Activity想象成手机屏幕上的一个“页面”。比如&#xff0c;当你打开一个App时&#xff0c;…...

数据库原理(1)

第一章 概论 一、基本概念 数据&#xff08;Data&#xff09;是数据库中存储的基本对象&#xff0c;描述事物的符号记录。例如学生的学号、姓名等信息都是数据。 数据库&#xff08;Database&#xff0c;DB&#xff09;长期存储在计算机内、有组织的、可共享的大量数据的集合。…...

SQL盲注问题深度解析与防范策略

引言 在当今互联网时代,Web应用程序的安全性是重中之重。SQL注入作为一种常见且极具威胁性的攻击手段,而其中的SQL盲注更是因其隐蔽性强、难以察觉而备受关注。攻击者借助SQL盲注,在无法直接获取数据库返回结果的情况下,通过精心构造特殊的SQL语句,利用页面的不同响应来逐…...

Android JIT( ART即时编译器),Just In Time Compiler,即时编译技术

Android JIT&#xff08; ART即时编译器&#xff09;,Just In Time Compiler&#xff0c;即时编译技术 Android Runtime (ART) 包含一个具备代码分析功能的即时 (JIT) 编译器&#xff0c;该编译器可以在 Android 应用运行时持续提高其性能。JIT是Just In Time Compiler&#xf…...

当自动驾驶遇上“安全驾校”:NVIDIA如何用技术给无人驾驶赋能?

自动驾驶技术的商业化落地&#xff0c;核心在于能否通过严苛的安全验证。国内的汽车企业其实也在做自动驾驶&#xff0c;但是吧&#xff0c;基本都在L2级别。换句话说就是在应急时刻内&#xff0c;还是需要人来辅助驾驶&#xff0c;AI驾驶只是决策层&#xff0c;并不能完全掌握…...

Unity中数据储存

在Unity项目开发中,会有很多数据,有需要保存到本地的数据,也有直接保存在缓存中的临时数据,一般为了方便整个项目框架中各个地方能调用需要的数据,因此都会实现一个数据工具或者叫数据管理类,用来管理项目中所有的数据。 首先保存在缓存中的数据,比如用户信息,我们只需…...

【C++11】可变参数模板

前言&#xff1a; 上文我们学到右值引用及其移动语义&#xff0c;学习到了C11中对性能提升对重要的更新之一。C11进阶之路&#xff1a;右值引用和移动语义&#xff0c;让代码跑得更快&#xff01;-CSDN博客 本文我们来讲讲&#xff0c;C11的下一个新语法&#xff1a;可变参数模…...

c语言知识整理

一 数据的存储 对于整形的存储 无论是正负在存储中都是使用补码进行存储的 那个一个数字的补码在转换正负时不同的 对于存储中 首位一定是符号位 如果是0 那么是正数 如果是1 那么是负数 &#xff08;32位 除符号位 缺少的位数使用0补齐&#xff09; 如果是正数 …...

算法习题-力扣446周赛题解

算法可以调度思维&#xff0c;让程序员的思维发散&#xff0c;找到更好的解决方案。 第一题&#xff1a;执行指令后的得分 题目&#xff1a; 给你两个数组&#xff1a;instructions 和 values&#xff0c;数组的长度均为 n。你需要根据以下规则模拟一个过程&#xff1a; 从下标…...

基于共享上下文和自主协作的 RD Agent 生态系统

在llmangentmcp这个框架中&#xff1a; LLM&#xff1a; 依然是智能体的“大脑”&#xff0c;赋予它们理解、推理、生成和规划的能力&#xff0c;并且也用于处理和利用共享上下文。Agent&#xff1a; 具备特定 R&D 职能的自主单元&#xff0c;它们感知共享上下文&#xff0…...

Operating System 实验五 进程管理编程实验

实验目标: 写个多线程的程序,重现竞争条件,并通过信号量或者互斥量,解决临界区问题某工厂有两个生产车间和一个装配车间,两个生产车间分别生产A、B两种零件,装配车间的任务是把A、B两种零件组装成产品。两个生产车间每生产一个零件后,都要分别把它们送到装配车间的货架F…...

Deep Reinforcement learning for real autonomous mobile robot navigation

​​​​​​​https://www.youtube.com/watch?vKyA2uTIQfxw AI Learns to Park - Deep Reinforcement Learning https://www.youtube.com/watch?vVMp6pq6_QjI Q Learning simply explained | SARSA and Q-Learning Explanation https://www.youtube.com/watch?vMI8ByADM…...

计算机网络 | 应用层(4)--DNS:因特网的目录服务

&#x1f493;个人主页&#xff1a;mooridy-CSDN博客 &#x1f493;文章专栏&#xff1a;《计算机网络&#xff1a;自定向下方法》 大纲式阅读笔记_mooridy的博客-CSDN博客 &#x1f339;关注我&#xff0c;和我一起学习更多计算机网络的知识 &#x1f51d;&#x1f51d; 目录 …...

WPF核心技术解析与使用示例

WPF核心技术解析与使用示例 一、依赖属性(Dependency Property)详解 1. 依赖属性基础 ​​核心概念​​: 依赖属性是WPF实现数据绑定、样式、动画等特性的基础通过属性系统实现高效的内存管理和值继承​​标准定义模式​​: public class MyControl : Control {// 1. 定义…...

JVM运行机制全景图:从源码到执行的全过程

JVM运行机制全景图:从源码到执行的全过程 引言:你真的了解 Java 是怎么跑起来的吗? 许多开发者写完 Java 代码之后,就交给编译器和运行时去“神奇”地执行了。但你有没有想过,一段 .java 文件是如何一步步变成可运行的程序?今天,我们就从 源码 ➝ 字节码 ➝ 类加载 ➝…...

使用 AFL++ 对 IoT 二进制文件进行模糊测试 - 第二部分

在上一部分中,我们研究了如何使用 AFL++ 对简单的物联网二进制文件进行模糊测试。这些程序接受来自文件的输入,并且易于模糊测试。 在本文中,我们将研究套接字二进制文件。使用套接字进行网络通信的模糊测试二进制文件与使用基于文件 I/O 的模糊测试二进制文件不同。Vanill…...

在华为云平台上使用 MQTT 协议:构建高效可靠的物联网通信

&#x1f310; 在华为云平台上使用 MQTT 协议&#xff1a;构建高效可靠的物联网通信 随着物联网&#xff08;IoT&#xff09;技术的发展&#xff0c;设备间的高效通信变得尤为重要。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为一种轻量级的消息传输…...

基于STM32的物流搬运机器人

功能&#xff1a;智能循迹、定距夹取、颜色切换、自动跟随、自动避障、声音夹取、蓝牙遥控、手柄遥控、颜色识别夹取、循迹避障、循迹定距…… 包含内容&#xff1a;完整源码、使用手册、原理图、视频演示、PPT、论文参考、其余资料 资料只私聊...

H.264/AVC标准主流开源编解码器编译说明

An artisan must first sharpen his tools if he is to do his work well. 工欲善其事,必先利其器. 前言 想研究和学习H.264/AVC视频编解码标准的入门的伙伴们,不论是学术研究还是工程应用都离不开对源码的分析,因此首要工作是对各类编解码器进行编译,本文针对主流的一些符…...

Xilinx FPGA支持的FLASH型号汇总

以博主这些年的FPGA开发使用经验来看&#xff0c;FPGA开发的主流还是以Xilinx FPGA为主&#xff0c;贸易战关税战打了这么多年&#xff0c;我们做研发的也不可避免的要涉及一些国产替代的工作&#xff1b;这里把Xilinx FPGA官方支持的各类&#xff08;国产和非国产&#xff09;…...

【C++ 类和数据抽象】消息处理示例(1):从设计模式到实战应用

目录 一、数据抽象概述 二、消息处理的核心概念 2.1 什么是消息处理&#xff1f; 2.2 消息处理的核心目标 三、基于设计模式的消息处理实现 3.1 观察者模式&#xff08;Observer Pattern&#xff09; 3.2 命令模式&#xff08;Command Pattern&#xff09; 四、实战场景…...

LiveCharts.WPF图表模块封装

WPF LiveCharts.WPF 封装实现 下面是一个完整的 WPF LiveCharts.WPF 封装实现,提供了常用图表的简单使用方式,并支持数据绑定和更新。 一、LiveCharts.WPF 封装类 1. 图表基类 (ChartBase.cs) using LiveCharts; using LiveCharts.Wpf; using System.Collections.Generic;…...

微信小程序,基于uni-app的轮播图制作,轮播图本地文件图片预览

完整代码 <template><swiper class"banner" indicator-dots circular :autoplay"false"><swiper-item v-for "item in picture" :key"item.id"><view><image tap"onPreviewImage(item.img)" :…...

【QQmusic】复习笔记第四章分点讲解

4.1 音乐加载 功能概述 该部分实现了从本地磁盘加载音乐文件到程序中&#xff0c;并在界面上显示的功能。通过QFileDialog类创建文件选择对话框&#xff0c;用户可选择多个音乐文件&#xff0c;程序筛选出有效音频文件后&#xff0c;交由MusicList类管理&#xff0c;并更新到…...

设置右键打开VSCode

在日常的开发工作中&#xff0c;VSCode 是一款非常受欢迎的代码编辑器。为了更加便捷地使用它&#xff0c;我们可以将 VSCode 添加到右键菜单中&#xff0c;这样只需右键点击文件或文件夹&#xff0c;就能快速用 VSCode 打开&#xff0c;极大地提高工作效率。下面我就来介绍一下…...

数据结构和算法(八)--2-3查找树

目录 一、平衡树 1、2-3查找树 1.1、定义 1.2、查找 1.3、插入 1.3.1、向2-结点中插入新键 1.3.2、向一棵只含有一个3-结点的树中插入新键 1.3.3、向一个父结点为2-结点的3-结点中插入新键 1.3.4、向一个父结点为3-结点的3-结点中插入新键 1.3.5、分解根结点 1.4、2…...

JSAPI2.4——正则表达式

一、语法 const str 一二三四五六七八九十 //判断内容 const reg /二/ //判断条件 console.log(reg.test(str)); //检查 二、test与exec方法的区别 test方法&#xff1a;用于判断是否符合规则的字符串&#xff0c;返回值是布尔值 exec方法&…...

FPGA 100G UDP纯逻辑协议栈

随着器件等级的升高&#xff0c;高速serdes的线速率也随之提高&#xff0c;RFSOC 4x最大可支持100G&#xff0c;主流方案为RDMA方案&#xff0c;该方案相对比较复杂&#xff0c;除了需要负责逻辑端的开发&#xff0c;还需操作系统中开发RDMA的驱动&#xff0c;对于对丢包不那么…...

分享一个可以批量巡检GET和POST接口的Shell脚本

一、场景痛点与需求分析 在分布式系统架构中&#xff0c;服务接口的可用性和稳定性直接影响业务连续性。当面临以下场景时&#xff0c;需批量巡检GET和POST接口&#xff1a; 上线验证&#xff1a;新版本发布后批量验证核心接口 故障恢复&#xff1a;异常数据修复后的批量重试…...