Java高手的30k之路|面试宝典|精通泛型

泛型

知识点

在Java高级开发中,掌握泛型(Generics)是非常重要的,它是Java语言中的一项重要特性,提供了编译时类型安全检查机制,使得代码更加灵活和可重用。以下是Java高级开发需要掌握的泛型知识点:

  1. 泛型基础

    • 理解泛型的定义和基本语法,包括泛型类、泛型方法、泛型接口。
    • 泛型用法示例:class MyClass<T> {}public <T> void myMethod(T t) {}
  2. 泛型通配符

    • 理解 <?><? extends T><? super T> 等通配符的含义和使用场景。
    • 了解上界通配符和下界通配符在泛型方法和泛型类中的应用。
  3. 泛型和继承关系

    • 理解泛型在继承和子类化中的表现,包括泛型类的继承、通配符的上下界限定。
  4. 类型擦除

    • 理解Java泛型的类型擦除机制,即在运行时泛型类型信息被擦除为原始类型。
    • 泛型类和泛型方法在编译后如何处理为非泛型形式的字节码。
  5. 泛型和集合

    • 熟悉Java集合框架中泛型的应用,如 List<T>Map<K, V> 等。
    • 掌握使用泛型提高集合类型安全性的方法。
  6. 泛型方法

    • 理解泛型方法的定义和使用,以及与泛型类的区别。
    • 了解泛型方法如何在静态方法和实例方法中应用。
  7. 泛型的好处

    • 掌握泛型的优势,如提高代码的类型安全性、避免类型转换错误、增加代码的可读性和重用性等。
  8. 泛型和反射

    • 理解泛型和反射的结合使用,如何通过反射获取泛型信息。
  9. 泛型约束

    • 熟悉泛型的类型约束,如泛型的边界限定(extends 和 super 关键字)。
  10. 泛型和异常

    • 了解泛型和异常处理的结合使用,如何处理泛型异常。

使用

1. 泛型类和泛型接口

限定类型可以在定义泛型类和泛型接口时使用。

// 限定类型 T 必须是 Number 的子类
public class NumberBox<T extends Number> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}// 泛型接口示例
public interface NumberProcessor<T extends Number> {void process(T number);
}

2. 泛型方法

在定义泛型方法时,可以使用限定类型来约束方法的类型参数。

public class Utility {// 泛型方法,限定类型 T 必须是 Number 的子类public static <T extends Number> void printNumber(T number) {System.out.println("Number: " + number);}
}

3. 泛型通配符

限定类型也可以在泛型通配符中使用,以表示方法参数或返回值的类型约束。

import java.util.List;public class WildcardExample {// 通配符上限,list 中的元素必须是 Number 的子类public static void printNumbers(List<? extends Number> list) {for (Number number : list) {System.out.println(number);}}// 通配符下限,list 中的元素必须是 Integer 的父类public static void addIntegers(List<? super Integer> list) {list.add(1);list.add(2);}
}

4. 多重限定

如果类型参数需要同时满足多个接口,可以使用 & 符号进行多重限定。

// T 必须同时实现 Comparable<T> 和 Serializable 接口
public class MultiBound<T extends Comparable<T> & Serializable> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}

5. 示例业务场景

下面通过一些具体的业务场景示例来说明限定类型的使用。

示例 1: 数据处理器

假设我们有一个数据处理器,需要处理不同类型的数值数据,我们可以使用泛型类来实现。

public class DataProcessor<T extends Number> {private T data;public DataProcessor(T data) {this.data = data;}public void process() {System.out.println("Processing data: " + data);}public T getData() {return data;}
}public class Main {public static void main(String[] args) {DataProcessor<Integer> intProcessor = new DataProcessor<>(100);intProcessor.process();DataProcessor<Double> doubleProcessor = new DataProcessor<>(99.99);doubleProcessor.process();}
}
示例 2: 数字打印工具

我们可以使用泛型方法来创建一个打印数字的工具方法。

public class PrintUtil {public static <T extends Number> void print(T number) {System.out.println("Number: " + number);}public static void main(String[] args) {print(123); // Integerprint(45.67); // Double}
}
示例 3: 集合操作工具

使用泛型通配符来创建一个工具类,用于操作集合中的元素。

import java.util.List;
import java.util.ArrayList;public class CollectionUtil {public static void printNumbers(List<? extends Number> list) {for (Number number : list) {System.out.println("Number: " + number);}}public static void addNumbers(List<? super Integer> list) {list.add(10);list.add(20);}public static void main(String[] args) {List<Integer> intList = new ArrayList<>();addNumbers(intList);printNumbers(intList);}
}

结合具体场景的最佳实践

当然可以。以下是结合具体业务场景的Java泛型最佳实践讲解:

1. 确保类型安全

业务场景:一个电商系统需要存储和处理不同类型的订单(如书籍订单和电子产品订单)。

示例

class Order { /*...*/ }
class BookOrder extends Order { /*...*/ }
class ElectronicsOrder extends Order { /*...*/ }List<Order> orders = new ArrayList<>();
orders.add(new BookOrder());
orders.add(new ElectronicsOrder());
// orders.add(new String()); // 编译时会报错,防止插入非订单类型

通过使用泛型,确保集合中只存储订单对象,防止错误类型的插入。

2. 使用通配符提高代码灵活性

业务场景:需要处理一个包含各种类型商品的库存。

上界通配符(Producer-Extends)

public void printInventory(List<? extends Product> inventory) {for (Product p : inventory) {System.out.println(p.getName());}
}List<Book> books = new ArrayList<>();
List<Electronic> electronics = new ArrayList<>();
printInventory(books);
printInventory(electronics);

通过上界通配符,可以处理各种类型的商品清单。

下界通配符(Consumer-Super)

public void addElectronics(List<? super Electronics> inventory) {inventory.add(new Electronics());inventory.add(new Smartphone()); // Smartphone extends Electronics,注意这里可以添加三种类:父类,自己,子类(多态)
}List<Product> products = new ArrayList<>();
addElectronics(products);

通过下界通配符,可以向商品列表中添加各种电子产品。

3. 避免使用原始类型

业务场景:一个社交媒体应用需要存储用户评论。

示例

List<Comment> comments = new ArrayList<>();
comments.add(new Comment("Great post!"));
// comments.add(new User()); // 编译时会报错,防止插入非评论类型

通过使用泛型,确保集合中只包含评论对象。

4. 使用泛型方法提高代码重用性

业务场景:一个文件处理系统,需要打印不同类型的文件内容。

示例

public <T> void printFiles(T[] files) {for (T file : files) {System.out.println(file.toString());}
}Document[] documents = {new Document("Doc1"), new Document("Doc2")};
Image[] images = {new Image("Image1"), new Image("Image2")};
printFiles(documents);
printFiles(images);

通过使用泛型方法,可以打印任何类型的文件内容,提高代码重用性。

5. 使用有界类型参数进行约束

业务场景:一个排行榜系统,需要找到分数最高的用户。

示例

public <T extends Comparable<T>> T findTopScorer(T[] scores) {T top = scores[0];for (T score : scores) {if (score.compareTo(top) > 0) {top = score;}}return top;
}Integer[] intScores = {85, 92, 88};
Double[] doubleScores = {85.5, 92.3, 88.9};
System.out.println(findTopScorer(intScores)); // 输出92
System.out.println(findTopScorer(doubleScores)); // 输出92.3

通过使用有界类型参数,可以确保数组中的元素可以比较,从而找到最高分数。

6. 避免使用泛型类型的静态成员

业务场景:一个用户管理系统,需要存储用户信息。

示例

public class UserManager<T> {private T user;// private static T instance; // 编译错误,避免使用泛型类型的静态成员
}

通过避免使用泛型类型的静态成员,防止类型擦除带来的问题。

7. 使用类型令牌解决类型擦除问题

业务场景:一个对象工厂,需要根据类型创建对象实例。

示例

public <T> T createInstance(Class<T> clazz) throws Exception {return clazz.getDeclaredConstructor().newInstance();
}User user = createInstance(User.class);

通过使用类型令牌,可以在运行时获取泛型类型信息,创建对象实例。

8. 避免在泛型类中使用泛型数组

业务场景:一个订单管理系统,需要存储不同类型的订单。

示例

public class OrderManager<T> {private T[] orders; // 编译错误,避免使用泛型数组private List<T> orderList = new ArrayList<>();
}

通过避免使用泛型数组,防止类型擦除带来的问题。

9. 谨慎使用泛型和异常

业务场景:一个数据处理系统,需要处理不同类型的数据。

示例

// 错误示例
public <T extends Exception> void processData() throws T {// 不能抛出或捕获泛型异常类型
}

避免抛出或捕获泛型异常类型。

10. 使用PECS原则

业务场景:一个物流系统,需要处理和添加不同类型的货物。

示例

// Producer-Extends
public void processCargo(List<? extends Cargo> cargoList) {for (Cargo cargo : cargoList) {System.out.println(cargo.getDetails());}
}// Consumer-Super
public void addCargo(List<? super PerishableCargo> cargoList) {cargoList.add(new PerishableCargo());cargoList.add(new FreshCargo()); // FreshCargo extends PerishableCargo
}List<Cargo> cargos = new ArrayList<>();
addCargo(cargos);

通过PECS原则,可以处理和添加不同类型的货物。

泛型的实现原理及其在运行时的表现

1. 泛型的本质

Java 泛型在编译时提供类型检查和类型安全,允许开发人员编写更灵活且类型安全的代码。然而,在运行时,Java 泛型会被类型擦除(Type Erasure),这意味着所有的类型参数都会被擦除,并替换为它们的限定类型(如果没有指定,则替换为 Object)。

2. 类型擦除(Type Erasure)

类型擦除是 Java 泛型的核心机制。在编译时,编译器会移除泛型类型信息并插入必要的类型转换,以确保类型安全。在运行时,泛型类型信息不存在,所有泛型类型都被替换为原始类型。

例如,以下泛型类:

public class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}

在编译后,类型参数 T 会被替换为 Object

public class Box {private Object content;public void setContent(Object content) {this.content = content;}public Object getContent() {return content;}
}

编译器在插入和取出元素时会生成适当的类型转换代码,以确保类型安全。

3. 限定类型

如果泛型类型参数有上限限制,如 T extends Number,类型擦除后会替换为限定类型,而不是 Object

例如:

public class NumberBox<T extends Number> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}

在编译后,类型参数 T 会被替换为 Number

public class NumberBox {private Number content;public void setContent(Number content) {this.content = content;}public Number getContent() {return content;}
}

4. 泛型方法

泛型方法在运行时也会经历类型擦除,其类型参数在运行时被替换为限定类型或 Object

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

在编译后,类型参数 T 被替换为 Object

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

5. 泛型数组

Java 不允许创建泛型类型的数组,因为在运行时泛型类型被擦除,数组的运行时类型需要具体的类型信息。

以下代码是非法的:

List<String>[] listArray = new List<String>[10]; // 编译错误

解决方法是使用通配符或 Object

List<?>[] listArray = new List<?>[10];

6. 泛型与反射

由于类型擦除,在使用反射时,无法获取泛型类型参数的具体类型信息。例如:

List<String> list = new ArrayList<>();
Type type = list.getClass().getGenericSuperclass();
System.out.println(type); // 输出 java.util.AbstractList<E>

上面的代码只能得到泛型类型参数 E,而不是具体的 String 类型。

为什么输出 java.util.AbstractList<E>

ArrayList 继承自 AbstractList,而 AbstractList 又是AbstractCollection 的子类。具体的继承关系如下:

  • ArrayList<E> extends AbstractList<E>
  • AbstractList<E> extends AbstractCollection<E>

当你调用 list.getClass().getGenericSuperclass() 时,getGenericSuperclass() 方法返回的是直接父类的类型,即 AbstractList<E>。这个类型包含泛型信息,但因为泛型类型参数 E 是在编译时擦除的,实际运行时显示的是泛型类型 E

小结

Java 泛型通过类型擦除实现,在编译时确保类型安全,但在运行时移除类型信息。类型擦除机制使得 Java 泛型在运行时没有性能开销,并且与非泛型代码兼容。然而,这也导致在运行时无法获取具体的泛型类型信息,需要通过其他方式(如反射)来处理泛型类型。

类型擦除的例外

在 Java 中,泛型类型信息确实会在编译期间被擦除,这就是所谓的类型擦除(type erasure)。类型擦除的基本概念是:泛型参数类型在编译时被替换为它们的非泛型上界(通常是 Object,除非有特定的边界),并在必要时插入类型转换。类型擦除的结果是,在运行时,泛型参数的实际类型信息是不可用的。然而,有一些情况下,类型信息是可以保留的,主要依赖于编译器在生成 class 文件时的额外信息。以下是几种情况:

  • 字段:类的字段声明为泛型时,泛型信息会存储在 class 文件的字段信息部分。
  • 方法参数和返回类型:方法参数或返回类型使用泛型时,泛型信息会存储在 class 文件的方法签名部分。
  • 类和接口:类或接口本身声明为泛型时,泛型信息会存储在 class 文件的类型信息部分。

1. 字段的泛型类型

当一个类的字段声明为泛型类型时,编译器会将泛型类型的信息存储在 class 文件的字段信息部分。这使得在运行时,通过反射 API 可以获取到这些泛型类型的信息。比如:

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;public class GenericField {private List<String> stringList;public static void main(String[] args) throws NoSuchFieldException {Field field = GenericField.class.getDeclaredField("stringList");Type genericFieldType = field.getGenericType();if (genericFieldType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericFieldType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type type : actualTypeArguments) {System.out.println(type);}}}
}

在这个示例中,stringList 字段的泛型类型信息在编译期被存储在 class 文件中,虽然在运行时无法直接使用泛型类型,但可以通过反射 API 获取到这些信息。输出结果为 class java.lang.String

2. 方法的泛型参数类型

类似地,当方法的参数或返回类型使用泛型时,编译器会在 class 文件中存储这些泛型信息。在运行时,可以通过反射获取这些信息。比如:

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;public class GenericMethod {public <T> void printList(List<T> list) {// Method body}public static void main(String[] args) throws NoSuchMethodException {Method method = GenericMethod.class.getMethod("printList", List.class);Type[] genericParameterTypes = method.getGenericParameterTypes();for (Type type : genericParameterTypes) {if (type instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) type;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualType : actualTypeArguments) {System.out.println(actualType);}}}}
}

在这个示例中,printList 方法的参数 list 的泛型类型信息被存储在 class 文件中,可以在运行时通过反射获取。

总结

类型擦除确实会在运行时丢失泛型参数的具体类型信息,但是编译器会在 class 文件中存储一些必要的泛型信息,使得可以在运行时通过反射获取这些信息。因此,通过 ParameterizedType,可以在运行时获取泛型参数的类型信息,这在某些情况下非常有用。

ParameterizedType

ParameterizedType 是 Java 反射 API 中的一个接口,它表示一个带有实际类型参数的泛型类型。在实际开发中,我们经常会遇到需要在运行时获取泛型类型参数的情况,这时 ParameterizedType 就非常有用。

ParameterizedType 接口用于表示参数化类型。一个参数化类型是指带有实际类型参数的类型,比如 List<String>Map<String, Integer> 等。通过反射 API,可以在运行时获取这些参数化类型的实际类型参数。

常用方法

ParameterizedType 接口定义了一些方法,用于获取参数化类型的详细信息:

  • Type[] getActualTypeArguments():返回实际类型参数的数组。
  • Type getRawType():返回不带泛型参数的原始类型。
  • Type getOwnerType():返回这个类型的所有者类型,如果这个类型是一个内部类的话。

使用示例

下面通过一个具体的例子来说明如何使用 ParameterizedType 获取泛型类型参数。

示例 1:获取类的泛型类型参数
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;public class GenericClass<T> {public static void main(String[] args) {// 使用匿名子类来保留泛型类型信息GenericClass<List<String>> instance = new GenericClass<List<String>>() {};Type superclass = instance.getClass().getGenericSuperclass();if (superclass instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) superclass;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type type : actualTypeArguments) {System.out.println(type);}}}
}

在这个示例中,通过创建 GenericClass 的匿名子类,我们保留了泛型类型信息。然后使用反射获取泛型类型参数,输出结果为 java.util.List<java.lang.String>

示例 2:获取方法的泛型类型参数
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;public class GenericMethod {public <T> void printList(List<T> list) {// Method body}public static void main(String[] args) throws NoSuchMethodException {Method method = GenericMethod.class.getMethod("printList", List.class);Type[] genericParameterTypes = method.getGenericParameterTypes();for (Type type : genericParameterTypes) {if (type instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) type;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualType : actualTypeArguments) {System.out.println(actualType);}}}}
}

在这个示例中,我们通过反射获取了泛型方法 printList 的类型参数,输出结果为 T

示例 3:获取字段的泛型类型参数
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;public class GenericField {private List<String> stringList;public static void main(String[] args) throws NoSuchFieldException {Field field = GenericField.class.getDeclaredField("stringList");Type genericFieldType = field.getGenericType();if (genericFieldType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericFieldType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type type : actualTypeArguments) {System.out.println(type);}}}
}

在这个示例中,我们通过反射获取了泛型字段 stringList 的类型参数,输出结果为 java.lang.String

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/29050.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

独立游戏之路:Tap篇 -- Unity 集成 TapTap 广告详细步骤

Unity 集成 TapADN 广告详细步骤 前言一、TapTap 广告介绍二、集成 TapTap 广告的步骤2.1 进入广告后台2.2 创建广告计划2.3 选择广告类型三、代码集成3.1 下载SDK3.2 工程配置3.3 源码分享四、常见问题4.1 有展现量没有预估收益 /eCPM 波动大?4.2 新建正式媒体找不到预约游戏…

六西格玛培训:一次学习,终身受益!

六西格玛培训&#xff0c;这个听起来就充满智慧的名字&#xff0c;其实是一种追求卓越的管理哲学。它的核心理念在于减少缺陷、降低变异&#xff0c;以提升企业的运营效率和质量水平。对于我们这些渴望在职场中更上一层楼的人来说&#xff0c;六西格玛培训无疑是一把打开成功之…

Java Websocket分片发送

一、分片发送和接收(复杂) 如果数据量太大&#xff0c;需要分多次发送&#xff0c; 需要考虑数据划分和重组的问题。 二、具体思路 每次发送和接收用一个布尔值变量指定是否为最后一个分片。 三、具体使用 (一)字符串分片发送&#xff1a; sendText(文本&#xff0c; 布尔值)…

太速科技-基于XCVU9P+ C6678的100G光纤的加速卡

基于XCVU9P C6678的100G光纤的加速卡 一、板卡概述 二、技术指标 • 板卡为自定义结构&#xff0c;板卡大小332mmx260mm; • FPGA采用Xilinx Virtex UltralSCALE 系列芯片 XCVU9P; • FPGA挂载4组FMC HPC 连接器; • 板载4路QSPF&#xff0c;每路数据速…

硕思闪客精灵软件最新版下载及详细安装教程

闪客精灵&#xff08;Sothink SWF Decompiler&#xff09;是一款先进的SWF反编译软件&#xff0c;它不但能捕捉、反编译、查看和提取Shock Wave Flash影片&#xff08;.swf和.exe格式文件&#xff09;&#xff0c;而且可以将SWF格式文件转化为FLA格式文件。 安 装 包 获 取 地 …

Postman接口测试工具详解:高效API测试实践指南

第一章:引言 - Postman在接口测试中的重要性 Postman作为一款专业的接口测试工具,已经成为现代软件开发过程中不可或缺的一部分。在本章中,我们将探讨Postman的核心价值,以及它如何帮助开发者和测试工程师提高API测试的效率和质量。 Postman的核心价值 - **易用性**:Pos…

Python Django 实现教师、学生双端登录管理系统

文章目录 Python Django 实现教师、学生双端登录管理系统引言Django框架简介环境准备模型设计用户认证视图和模板URL路由前端设计测试和部署获取开源项目参考 Python Django 实现教师、学生双端登录管理系统 引言 在当今的教育环境中&#xff0c;数字化管理系统已成为必不可少…

Linux 常用命令 - cd 【切换目录】

简介 “cd” 命令来源于 “change directory”&#xff0c;即 “切换目录”。它是一个用于在 Linux 和 Unix 系统的命令行中更改当前工作目录的命令。通过使用 cd 命令&#xff0c;用户可以在文件系统的不同位置移动&#xff0c;这对于浏览文件系统或定位到特定文件进行操作非…

C# 通过Win32API设置客户端系统时间

在日常工作中&#xff0c;有时可能会需要获取或修改客户端电脑的系统时间&#xff0c;比如软件设置了Licence有效期&#xff0c;预计2024-06-01 00:00:00到期&#xff0c;如果客户手动修改了客户端电脑时间&#xff0c;往前调整了一年&#xff0c;则软件就可以继续使用一年&…

掌控未来:用决策树算法揭秘胜利者的必胜策略!

掌控未来&#xff1a;用决策树算法揭秘胜利者的必胜策略&#xff01; 一、引言1.1. 决策树的定义1.2. 发展历程1.3. 当前应用概况1.4. 本文内容安排 二、决策树的基本概念2.1 节点和叶节点2.2 决策树的结构结构图示不同结构的决策树 三、决策树的算法原理3.1 基本思想3.2 核心算…

Linux系统部署Samba服务,共享文件夹给Windows

Samba服务是在Linux和UNIX系统上实现SMB协议的一个免费软件&#xff0c;由服务器及客户端程序构成。 Samba服务是连接Linux与Windows的桥梁&#xff0c;它通过实现SMB&#xff08;Server Message Block&#xff09;协议来允许跨平台的文件和打印机共享。该服务不仅支持Linux和…

Linux操作系统以及一些操作命令、安装教程

Web课程完结啦&#xff0c;这是Web第一天的课程大家有兴趣可以传送过去学习 http://t.csdnimg.cn/K547r Linux-Day01 课程内容 Linux简介 Linux安装 Linux常用命令 1. 前言 1.1 什么是Linux Linux是一套免费使用和自由传播的操作系统。说到操作系统&#xff0c;大家比…

linux 4G模块 :EC200N—AT指令收发短信

查看/dev目录下的串口设备&#xff1a;在终端中运行以下命令&#xff0c;查看系统检测到的串口设备&#xff1a; $ ls /dev/ttyUSB*minicom串口通信软件安装 sudo apt-get install minicom修改串口配置&#xff1a; 在minicom的配置界面中&#xff0c;选择"Serial Port …

计算机相关专业还值得选择吗

2024年&#xff0c;计算机相关专业还值得选择吗&#xff1f; 随着2024年高考落幕&#xff0c;数百万高三学生又将面临人生中的重要抉择&#xff1a;选择大学专业。在这个关键节点&#xff0c;计算机相关专业是否仍是“万金油”的选择&#xff1f;在过去很长一段时间里&#xf…

知识库的创建(1) - KnowledgeFile文件加载和分割

文章目录 前言一、 类的初始化方法 __init__1. 参数解析2. 初始化步骤 二、 方法 file2docs1. 功能2. 参数3. 步骤 三、 方法 docs2texts1. 功能2. 参数3. 步骤 四、 方法 file2text1. 功能2. 参数3. 步骤 五、 方法 file_exist1. 功能2. 返回3. 方法 get_mtime4. 功能5. 返回 …

高考没考好焦虑怎么选计算机专业!一篇告诉你,推荐三个风口专业!想学计算机怎么选大学专业

高考成绩揭晓&#xff0c;几家欢喜几家愁。对于那些未能如愿考取理想分数的同学来说&#xff0c;未来似乎蒙上了一层阴影。尤其是在计算机专业如此热门的今天&#xff0c;低分考生是否还有机会在这个领域找到一席之地&#xff1f;本文将为你揭秘&#xff0c;即使高考成绩不理想…

Drake 机器人仿真

sudo apt-get install&#xff0c;pip3 install&#xff0c;sudo apt install这些命令是在Linux系统中用于安装软件包或Python库的不同方法&#xff0c;它们分别属于不同的包管理系统和工具。 sudo apt-get install&#xff1a; 这是在Debian、Ubuntu等基于Debian的系统上用于从…

Linux下C程序的编写

Linux下C程序的编写 第一部分&#xff1a;编写C程序并使用gcc编译器 首先&#xff0c;我们编写一个简单的C程序hello_gcc.c&#xff0c;用于在屏幕上输出“Hello gcc&#xff01;”。 // hello_gcc.c #include <stdio.h> int main() { printf("Hello gcc!\n&…

牛客周赛 C-苗苗的气球

原题链接&#xff1a;C-苗苗的气球 题目大意&#xff1a;n种气球&#xff0c;给出每种气球的个数&#xff0c;二种不同的气球相碰会爆炸&#xff0c;问最后留下来的气球有几种可能性。 思路&#xff1a;从特殊到一般&#xff0c;如果是一种气球&#xff0c;那么答案肯定是1&a…

mysql [Err] 1118 - Row size too large (> 8126).

1.找到my.ini文件 1.1 控制台输入以下指令&#xff0c;打开服务 services.msc1.2 查看mysql服务的属性 2.停止mysql服务&#xff0c;修改my.ini文件并且保存 innodb_strict_mode03.重启mysql服务 4.验证是否关闭成功 show variables like %innodb_strict_mode%; show vari…