Java高手的30k之路|面试宝典|精通泛型
泛型
知识点
在Java高级开发中,掌握泛型(Generics)是非常重要的,它是Java语言中的一项重要特性,提供了编译时类型安全检查机制,使得代码更加灵活和可重用。以下是Java高级开发需要掌握的泛型知识点:
-
泛型基础:
- 理解泛型的定义和基本语法,包括泛型类、泛型方法、泛型接口。
- 泛型用法示例:
class MyClass<T> {}
、public <T> void myMethod(T t) {}
。
-
泛型通配符:
- 理解
<?>
、<? extends T>
、<? super T>
等通配符的含义和使用场景。 - 了解上界通配符和下界通配符在泛型方法和泛型类中的应用。
- 理解
-
泛型和继承关系:
- 理解泛型在继承和子类化中的表现,包括泛型类的继承、通配符的上下界限定。
-
类型擦除:
- 理解Java泛型的类型擦除机制,即在运行时泛型类型信息被擦除为原始类型。
- 泛型类和泛型方法在编译后如何处理为非泛型形式的字节码。
-
泛型和集合:
- 熟悉Java集合框架中泛型的应用,如
List<T>
、Map<K, V>
等。 - 掌握使用泛型提高集合类型安全性的方法。
- 熟悉Java集合框架中泛型的应用,如
-
泛型方法:
- 理解泛型方法的定义和使用,以及与泛型类的区别。
- 了解泛型方法如何在静态方法和实例方法中应用。
-
泛型的好处:
- 掌握泛型的优势,如提高代码的类型安全性、避免类型转换错误、增加代码的可读性和重用性等。
-
泛型和反射:
- 理解泛型和反射的结合使用,如何通过反射获取泛型信息。
-
泛型约束:
- 熟悉泛型的类型约束,如泛型的边界限定(extends 和 super 关键字)。
-
泛型和异常:
- 了解泛型和异常处理的结合使用,如何处理泛型异常。
使用
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>
extendsAbstractList<E>
AbstractList<E>
extendsAbstractCollection<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
。
相关文章:
Java高手的30k之路|面试宝典|精通泛型
泛型 知识点 在Java高级开发中,掌握泛型(Generics)是非常重要的,它是Java语言中的一项重要特性,提供了编译时类型安全检查机制,使得代码更加灵活和可重用。以下是Java高级开发需要掌握的泛型知识点&#…...
清理Linux操作系统buff/cache缓存
清理Linux操作系统buff/cache缓存 清理页缓存 echo 1 > /proc/sys/vm/drop_caches 或者 sysctl -w vm.drop_caches1 清理目录项和inode缓存 echo 2 > /proc/sys/vm/drop_caches 或者 sysctl -w vm.drop_caches2 同时清理页缓存、目录项和inode缓存 echo 3 > /pr…...
接口测试的几种方法
其实无论用那种测试方法,接口测试的原理是通过测试程序模拟客户端向服务器发送请求报文,服务器接收请求报文后对相应的报文做出处理然后再把应答报文发送给客户端,客户端接收应答报文这一个过程。 方法一、用LoadRunner实现接口测试 大家都…...
OpenGL3.3_C++_Windows(3)
GLSL Shader基础 Shader(把输入转化为输出,运行在GPU上):首先要声明版本,有各自的入口点main()顶点数据上限:16个包含4分量:16 * 4 64个分量向量:容器vec。使用.x、.y、.z和.w&am…...
24执业药师报名时间汇总及报名流程!
24执业药师报名时间汇总!报名流程! 🕛️各省市报名时间汇总(共9地) 西藏:6月29日-7月8日 新疆:6月25日10:30-7月9日19:00 内蒙古:6月20日9:00-7月3日24:00 新疆兵团:6月2…...
成都跃享未来教育咨询解锁新篇章
在快节奏的现代社会中,每个人都在追求着属于自己的非凡人生。而成都跃享未来教育咨询,正是那个能够智慧引领你走向成功、成就非凡人生的灯塔。 跃享未来教育咨询,位于历史悠久的文化名城成都,这里不仅有丰富的文化底蕴,…...
怎么把网页上的接口信息导入postman
第一步 打开f12,右键选中需要的接口。选择copy-copy as cURL 第二步 打开postman,选择"Raw Text", 把刚才复制的curl粘贴到空白位置,点击Continue - 最后的效果。导入的接口自带cookie,不用再输入cookie&a…...
10KM无人机高清图传通信模组,低延迟、抗干扰,飞睿智能无线MESH组网模块
随着科技的飞速发展,无人机技术在各个领域的应用越来越广泛。尤其在海上监测、搜索救援、货物运输等场景中,无人机的应用显得尤为重要。然而,要实现无人机在复杂海域环境中的高效通信,高清图传通信模组的作用不可忽视。本文将深入…...
分布式文件存储 - - - MinIO从入门到飞翔
MinIO从入门到飞翔 文章目录 MinIO从入门到飞翔0、前言1、分布式文件系统2、MinIO 介绍3、 MinIO安装(docker)4、基本概念5、通过代码上传文件到MinIO6、封装MinIO为starter7、在其他项目中集成封装好的模块 0、前言 对象存储是一种数据存储架构&#x…...
Python界面编辑器Tkinter布局助手 使用体验
一、发现 我今天在网上搜关于Python Tkinter方面的信息时,发现了Python界面编辑器 Tkinter布局助手 的使用说明。 https://blog.csdn.net/weixin_52777652/article/details/135291731?spm1001.2014.3001.5506 这个编辑器是个开源的项目,个人用户可以…...
嵌入式操作系统_2.嵌入式操作系统的一般架构
1.嵌入式操作系统的概念 嵌入式操作系统通常由硬件驱动程序、调式代理、操作系统内核、文件系统和可配置组件等功能组成,并为应用软件提供标准的API(Application Programming Interface)接口服务。 2.一般嵌入式操作系统的体系结构 从嵌入…...
docker 容器 network host 模式启动
docker 默认启动容器 network 是 bridge 模式,需使用 -p 映射端口实现容器与宿主机网络通信,较安全; 当使用 network host 模式,直接走宿主机网络通信,较不安全。 下面来一个 docker 容器 network host 模式启动 的 实…...
群晖NAS安装配置Joplin Server用来存储同步Joplin笔记内容
一、Joplin Server简介 1.1、Joplin Server介绍 Joplin支持多种方式进行同步用户的笔记数据(如:Joplin自己提供的收费的云服务Joplin Cloud,还有第三方的云盘如Dropbox、OneDrive,还有自建的云盘Nextcloud、或者通过WebDAV协议来…...
leetcode-08-[151]翻转字符串里的单词[卡码网55]右旋转字符串
一、[151]翻转字符串里的单词 重点:见注释 class Solution {public String reverseWords(String s) {//1、移除多余的空格StringBuilder stringBuilder removeSpace(s);//2、反转整个字符串reverse(stringBuilder,0,stringBuilder.length()-1);//3、反转每个单词…...
Json-server 的使用教程
目录 前言一、简介二、安装与配置1. 安装 node-js2. npm 镜像设置3. 安装 json-server 三、使用1. 创建本地数据源2. 启动 Json Server3. 操作数据(1)查询数据(2)新增数据(3)修改数据(4…...
LLM中表格处理与多模态表格理解
文档处理中不可避免的遇到表格,关于表格的处理问题,整理如下,供各位参考。 问题描述 RAG中,对上传文档完成版式处理后进行切片,切片前如果识别文档元素是表格,那么则需要对表格进行处理。一般而言&#x…...
短剧系统搭建全攻略:功能齐全,一步到位
前言 近年来,短剧系统以其独特魅力,成为大众消遣娱乐的热门选择。简单来说,短剧系统就是用来看短剧的小程序,它汇集了丰富多彩的短剧资源,让观众随时随地享受观影乐趣。本文将为你详细解析短剧系统的搭建全攻略&#…...
【Linux】进程_7
文章目录 五、进程8. 进程地址空间9. 进程终止10. 进程等待 未完待续 五、进程 8. 进程地址空间 我们上节知道了进程地址空间是根据页表来使虚拟地址转换成内存中的物理地址,那这种 地址空间 页表 的机制有什么好处呢?①这种机制可以将物理内存从无序…...
从中概回购潮,看互联网的未来
王兴的饭否语录里有这样一句话:“对未来越有信心,对现在越有耐心。” 而如今的美团,已经不再掩饰对未来的坚定信心。6月11日,美团在港交所公告,计划回购不超过20亿美元的B类普通股股份。 而自从港股一季度财报季结束…...
【OceanBase DBA早下班系列】—— 性能问题如何 “拍CT“ (一键获取火焰图和扁鹊图)
1. 前言 最近接连遇到几个客户的环境在排查集群性能问题,总结了一下,直接教大家如何去获取火焰图、扁鹊图(调用关系图),直击要害,就像是内脏的疾病去医院看病,上来先照一个CT,通过分…...
4.类,方法,对象
1.1.2. 面向对象程序设计的三大特征 1.1.2.1. 封装 面向对象编程核心思想之一就是将数据和对数据的操作封装在一起,形成一般的概念,比如类的概念。 1.1.2.2. 继承 继承体现了一种先进的编程模式。子类可以继承父类的属性和方法。 1.1.2.3. 多态 多…...
重学java 71.网络编程
人生不是坐等暴风雨过去,而是学会在雨中起舞 —— 24.6.14 一、网络编程的基础概念 1.概述: 在网络通信协议下,不同计算机上运行的程序,进行数据传输 比如:通信、视频通话、网络、邮件 只要是计算机之间通过网络进行数据传输,就有…...
Linux驱动面试题
1.导出符号表的原理? 2.字符设备驱动的框架流程 open read wirte close 是系统调用(从用户空间进入内核空间的唯一的方法)会产生swi软中断《也会存在软中断号》(从User模式切换到SVC(管理模式)下因为在…...
git 如何强制下拉某个分支
要强制下拉Git仓库中的某个分支,可以使用以下命令: 第一步: git reset --hard HEAD第二步 git pull origin <分支名> git reset --hard HEAD 是一个 Git 命令,它的作用是将当前分支的头部重置为当前提交(HEAD…...
linux-touch指令
目录 语法 选项 示例 touch 是一个在 Linux 系统中常用的命令,它用于创建空文件,或者如果文件已经存在,则更新文件的访问和修改时间戳。下面是 touch 命令的完整使用说明: 语法 touch [选项]... 文件... 选项 -a 或 --time…...
海外仓系统有哪些?主流海外仓系统类型、优缺点,不同海外仓如何选择
作为海外仓的经营者,不管海外仓大小,你都应该知道海外仓系统对提升仓库管理效率有多重要。 不过现在市场上的海外仓系统确实种类太多了,想选到一个适合自己海外仓,性价比又比较高的wms海外仓系统也不是一件容易的事情。 本文会详…...
05-5.4.1 树的存储结构
👋 Hi, I’m Beast Cheng 👀 I’m interested in photography, hiking, landscape… 🌱 I’m currently learning python, javascript, kotlin… 📫 How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以…...
Spring事务管理与Spring AOP详解
Spring事务管理与Spring AOP详解 一、引言 在企业级应用开发中,事务管理和面向切面编程(AOP)是两个至关重要的概念。Spring框架作为Java企业级应用的首选框架之一,为事务管理和AOP提供了强大的支持。本文将详细解析Spring的事务…...
LaTeX 的使用
文章目录 TeX 编辑器文档类型中文编译文档结构preamble 导言区(不能放正文内容)document body 正文区 正文内容目录段落列表无序列表有序列表 图片表格交叉引用段落图片表格 转义符 数学公式数学符号行内公式行间公式有公式计数器无公式计数器 公式包含文…...
Text2SQL之Vanna优化
文章目录 前言一、优化方向二、干就完了一次性生成多个Question-SQL对先生成一个问题,再根据DDL和业务数据生成SQL总结前言 前阵子写了篇Text2SQL的简单介绍,发现其也是RAG只会,写下了Text2SQL之不装了,我也是RAG 最近也一直在做Text2SQL的优化,于是把自己的一些心得,总…...
网站关于我们怎么做/百度大数据
定义函数function 函数名 {函数的功能体......}函数名(){函数的功能体......}如何调用函数函数名函数的使用规则?1)先定义后调用,可以只定义不调用2)定义放上…...
小程序购物平台/广东seo快速排名
最近学习php,按照书上的描述,下载好apache和php后,按照其中配置进行,结果遇到了上述问题。花费了近一个半小时的时间解决了上述问题。现把解决问题过程中看到的方法总结如下。 最先肯定是一定要注意版本问题,apache和p…...
济南做企业网站公司/治疗腰椎间盘突出的特效药
最近在做应用的时候,遇到了需要选择图片上传头像的需求。本着代码搬运工的精神,在网上浏览了一圈,发现解决办法都大致如下:Intent intentFromGallery new Intent();intentFromGallery.setType("image"); // 设置文件类…...
做网站 做app/港港网app下载最新版
webpack 打包生成文件的时候,为了防止缓存,会在文件后边跟上版本号或者hash值,采用版本号的时候,一些小的修改,必须更改版本号,不然就会造成缓存。这样并不符合我的业务需求,所以我们将文件后边…...
easy ssl wordpress/百度最怕哪个投诉电话
SPI是一种高速的、全双工、同步通信总线,并且只占用四根线,常用来和FLASH、数字信号处理器等通信。SPI通信要比I2C简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,通常也只需要四根线,…...
做网站爱/品牌推广计划
在java中有许多的知识点,但是有些知识点显得非常重要,为什么这么说呢,这些知识点很简单、很基础,但是当别人问起来答不到时,就会被对方直接秒成菜鸟。 1、字符串不变性 Java里面对于字符串的处理方法有很多,…...