初识Java 10-1 集合

目录

泛型和类型安全的集合

基本概念

添加一组元素

打印集合

List

Iterator(迭代器)


本笔记参考自: 《On Java 中文版》


        在进行程序设计时我们会发现,程序总是会根据某些在运行时才能知道的条件来创建新的对象。这意味着,我们必须能够随时随地创建任意数量的对象。

        Java提供了几种方法来持有对象(的引用),其中之一就是数组。数组的优点在于其的高效,但其本身却会受到自身大小固定的制约。实际上,Java.util库提供了一组集合类来解决这一问题,其中包括的基本类ListSetQueueMap也被称为容器类

    Java并没有直接为集合提供关键字支持。

泛型和类型安全的集合

        在Java 5之前,编译器允许向集合中插入不正确的类型。在举例之前需要先对ArrayList类进行一些必要的说明:

        ArrayList是是一种泛型类型,它实现了迭代器(Iterable)、CollectionList等接口。泛型是一种参数化类型的机制,在这种机制下,形参的数据类型也会成为可传输的参数。因为泛型的存在,ArrayList可以存储任何类型的对象,而不需要在使用前进行类型转换(本段参考​林二月er​的博客、讯飞星火提供的信息)

    ArrayList使用一个数值来查找对应对象。从某种意义上,ArrayList将数值和对象关联起来了。

        下例中出现的ArrayList是一个反例,它没有使用泛型:

import java.util.ArrayList;class Apple {private static long counter;private final long id = counter++;public long id() {return id;}
}class Orange {
}public class AppleAndOrangesWithoutGenerics {@SuppressWarnings("unchecked") // 参数unchecked表示只有“unchecked”警告应该被忽略public static void main(String[] args) {ArrayList apples = new ArrayList<>();for (int i = 0; i < 3; i++)apples.add(new Apple());apples.add(new Orange()); // 注意:插入的是一个Orange类型,这本来应该是错误的操作for (Object apple : apples) {((Apple) apple).id(); // 需要强制类型转换,此时Orange只有在运行时才会被检测出来}}}

        上述程序的错误不会在编译时被发现,这个报错会出现在运行时:

        AppleOrange唯一的联系在于它们都继承了Object类。ArrayList持有的也是Object,所以无论是Apple类还是Orange类都能被加入其中(并且不会引发报错)。此时会从ArrayList中取出Object类型的引用,若想使用引用还必须强制类型转换。也正是在运行时,程序尝试将Orange对象转型为Apple时才会发现错误。

        若要定义一个持有Apple对象的ArrayList,应该使用:

ArrayList<Apple>

尖括号包围的是类型参数(可以有多个),它指定了集合实例中可以保存的类型。

        下面是修改后的例子:

import java.util.ArrayList;public class AppleAndOrangesWithGenerics {public static void main(String[] args) {ArrayList<Apple> apples = new ArrayList<>();for (int i = 0; i < 3; i++)apples.add(new Apple());// 此时,下方的做法就会引发编译时错误// apples.add(new Orange());for (Apple apple : apples)System.out.println(apple.id());}
}

        程序执行的结果如下:

        上述程序中,出现了语句 ArrayList<Apple> apples = new ArrayList<>(); 。这种语句因为<>符号,也被称为“钻石语法”。在Java 7之前,这种语法的使用会更加复杂:

ArrayList<Apple> apples = new ArrayList<Apple>(); // 需要在表达式的两侧重复写出类型声明

随着类型的深入,上述这种语法会变得越发复杂。因此最后被现在这种更为简便的语法代替了。

        泛型的存在使得我们从List(接口)中获取对象时,无须进行转型了。因为List知道它所持有的类型。另外,在泛型的情况下,向上转型也可以生效:

import java.util.ArrayList;class GrannySmith extends Apple {
}class Gala extends Apple {
}class Fuji extends Apple {
}class Braeburn extends Apple {
}public class GenericeAndUpcasting {public static void main(String[] args) {ArrayList<Apple> apples = new ArrayList<>();apples.add(new GrannySmith());apples.add(new Gala());apples.add(new Fuji());apples.add(new Braeburn());for (Apple apple : apples)System.out.println(apple);}
}

        程序执行的结果是:

        因为向上转型,所有可以向持有Apple对象的集合中,放入Apple的子类型。

    上述输出结果中,子对象名字后面的是由无符号十六进制表示的哈希码。

新特性:类型推断和泛型

        “局部变量类型推断”也可用于简化涉及泛型的定义:

import java.util.ArrayList;public class GenericTypeInference {void old() {ArrayList<Apple> apples = new ArrayList<>();}void modern() {var apples = new ArrayList<Apple>();}void pitFall() {var apples = new ArrayList<>();apples.add(new Apple());apples.get(0); // 会作为普通的Object类型返回}
}

        在modern()方法中,定义右侧使用的是<Apple>,通过这种方式提供信息,使编译器知道如何进行类型推断。

        但替代现有的语法时也可能会产生问题,在pitFall()方法中存在着语句

var apples = new ArrayList<>();

尽管这样也可以正常编译,但<>实际上会变为<Object>,这不是我们需要的。当我们想要从apples中提取元素时,它们会作为普通的Object类型返回,而不是具体的Apple类型。

基本概念

        Java的集合类库是用来“持有对象”的。从设计上,可以将这个库分为两种概念,这两种概念分别表示库的两个基本接口:

  1. Collection:一个由单独元素组成的序列,这些元素要符合一条或多条规则。

  2. Map:一组键值-对象对,使用键来查找值。Map也被称为关联数组(或是字典),它关联了对象与其他对象。

        在理想情况下,我们编写的大部分代码都是在和这些接口打交道,只有在创建的时候才需要指名所使用的确切类型。例如,按照这种思想创建一个List

List<Apple> apples = new ArrayList<>();

        和之前不同,ArrayList在这里被向上转型为了List。这样,在我们决定修改实现时,只需要修改创建的地方即可:

List<Apple> apples = new LinkedList<>(); // 将实现修改为LinkedList

        因此,通常会创建一个具体类的对象,并将其向上转型为相应的接口,在其余的代码中使用该接口

    但这种方法不会总是行得通,因为有些类会有额外的功能。当我们需要使用到这些额外的功能时,就无法将对象向上转型为更通用的接口了。

---

        序列是一种持有一组对象的方法,而Collection就是序列这一概念的一般化。例如:

import java.util.ArrayList;
import java.util.Collection;public class SimpleCollection {public static void main(String[] args) {Collection<Integer> c = new ArrayList<>();for (int i = 0; i < 10; i++)c.add(i); // 发生了自动装箱,向c中添加一个元素for (Integer i : c)System.out.print(i + " ");System.out.println();}
}

        程序执行的结果如下:

        这个示例只使用Collection中定义的方法,所以继承自该接口的类的任何对象都可以正常工作。不过,ArrayList是最基本的序列类型。

添加一组元素

        java.util中的ArraysCollection类都包含了一些工具方法,用于向一个Collection中添加一组元素:

  1. Arrays.asList():可以接受一个数组,或一个使用逗号分隔的元素列表,将其转换为一个List对象。
  2. Collection.addAll():接受一个Collection对象、一个数组或一个用都逗号分隔的列表,将其中的所有元素都添加到这个Collection中。
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;public class AddingGroups {public static void main(String[] args) {Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));System.out.println("line 10: " + collection);Integer[] moreInts = { 6, 7, 8, 9, 10 };collection.addAll(Arrays.asList(moreInts)); // 传统的addAll()方法System.out.println("line 14: " + collection);// 下方的这种方式运行速度更快,但无法通过这种方式构建Collection。Collections.addAll(collection, 11, 12, 13, 14, 15);System.out.println("line 18: " + collection);Collections.addAll(collection, moreInts);System.out.println("line 20: " + collection);// 生成一个底层是数组的列表:List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);System.out.println("line 24: " + list);list.set(1, 99); // 可以进行元素的修改:将下标为1的元素值改为99// list.add(21); //运行时会发生报错,因为底层数组是不能调整大小的System.out.println("line 27: " + list);}
}

        运行结果如下(line后跟的是行号):

        Collection.addAll()的运行速度会快很多。因此,可以先构建一个没有元素的Collection,之后调用Collection.addAll()进行元素输入。

        collection.addAll(Arrays.asList(moreInts)); 表示该方法只能接受另一个Collection对象作为参数,使用限制较大。相比之下,Arrays.asList()Collection.addAll()方法就更加好用了。

        可以直接将Arrays.asList()的输出作为一个List进行使用,但这种方式进行的实现,其底层是数组,大小无法改变。

        也可以向Collection中添加子类型:

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;class Snow {}class Powder extends Snow {}class Light extends Powder {}class Heavy extends Powder {}class Crusty extends Snow {}class Slush extends Snow {}public class AsListInferecnce {public static void main(String[] args) {List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(), new Powder());// snow1.add(new Heavy()); // 发生异常List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());// snow2.add(new Slush()); // 发生异常List<Snow> snow3 = new ArrayList<>();Collections.addAll(snow3, new Light(), new Heavy(), new Powder()); // 有一个可变参数列表snow3.add(new Crusty()); // 可以正常操作// 使用显式类型参数说明作为提示List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy(), new Slush());// snow4.add(new Powder()); // 发生异常}
}

打印集合

        数组的打印往往需要借助于Arrays.toString()等方法,但就像之前的例子演示过的那样,集合类不需要这些:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;public class PrintingCollections {static Collection fill(Collection<String> collection) {collection.add("鼠");collection.add("猫");collection.add("狗");collection.add("狗");return collection;}static Map fill(Map<String, String> map) {map.put("鼠", "杰瑞");map.put("猫", "汤姆");map.put("狗", "斯派克");map.put("狗", "斯派克");return map;}public static void main(String[] args) {System.out.println(fill(new ArrayList<>()));System.out.println(fill(new LinkedList<>()));System.out.println();System.out.println(fill(new HashSet<>()));System.out.println(fill(new TreeSet<>())); // 按键的升序保存对象System.out.println(fill(new LinkedHashSet<>())); // 按添加顺序保存对象System.out.println();System.out.println(fill(new HashMap<>()));System.out.println(fill(new TreeMap<>())); // 按键的升序进行排序System.out.println(fill(new LinkedHashMap<>())); // 按插入顺序保存键,同时具有HashMap的查找速度}
}

        程序执行的结果是:

        上述例子演示了Java集合类库的两种主要类型。区别在于集合中的每个“槽”(slot)内持有的条目数:

  • Collection:每个槽这只保存一个条目。其中,List以指定顺序保存一组条目;Set中,同样的条目只能加入一个;Queue只能一端进,另一端出。
  • Map:每个槽内持有两个对象,即和与之关联的

        除此之外,上述例子中ArrayListLinkedList的区别不仅在于进行一些操作时性能上的差异,而且LinkedList包含的操作比ArrayList多。另一个值得注意的是与Hash相关的类,这种类使用的保存方式会不同于同属的其他类。

List

        List接口继承了Collection接口,并在此基础之上添加了一些方法,这些方法支持在List的中间进行元素的插入和移除。

        List会以特定的顺序维护元素,由其衍生出了许多有用的类:

        接下来会介绍其中两种较为常用的List

  • ArrayList:一种基本的List,擅长随机访问元素,但在List中间进行插入和删除速度较慢。
  • LinkedList:具有理想的顺序访问性能,插入和删除的成本较低。除此之外,随机访问性能也更差,但与ArrayList相比有更多的功能。

        下述程序将会用到的Pet类笔者只进行了简单实现,大致如下:

因此代码未写入本笔记。 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;public class ListFeatures {public static void main(String[] args) {List<Pet> pets = new ArrayList<>();Collections.addAll(pets, new Rat(), new Manx(),new Cymric(), new Pug(), new Cymric(), new Pug()); // 插入一些数据System.out.println("1. 创建List:" + pets);System.out.println();Hamster h = new Hamster();pets.add(h);System.out.println("2. 删除元素:" + pets);System.out.println("3. 确定对象是否存在:" + pets.contains(h)); // 按对象搜索pets.remove(h); // 按对象删除System.out.println();Pet tmpp = pets.get(2); // 按下标获取System.out.println("4. 获取元素下标:" + pets.indexOf(tmpp));System.out.println();Pet cymric = new Cymric();System.out.println("5. 试图通过同类对象进行索引:" + pets.indexOf(cymric));System.out.println("6. 试图通过同类对象进行删除:" + pets.remove(cymric));System.out.println("7. 对象能够精确匹配,正常删除:" + pets.remove(tmpp));System.out.println();pets.add(3, new Mouse());System.out.println("8. 借助索引进行插入:" + pets);List<Pet> sub = pets.subList(1, 4);System.out.println("9. 使用区间提取List:" + sub);System.out.println("10. 判断sub是否存在于pets中:" + pets.containsAll(sub));System.out.println();// List<Pet>没有实现Comparator接口。为方便请见,这里进行了现场实现Collections.sort(sub, new Comparator<Pet>() {@Overridepublic int compare(Pet p1, Pet p2) {return p1.toString().compareTo(p2.toString());}});System.out.println("11. 对sub进行原地排序:" + sub);System.out.println("12. containsAll()不关心顺序:" + pets.containsAll(sub));System.out.println();Random random = new Random(12);Collections.shuffle(sub, random);System.out.println("13. 通过随机数使sub进行随机排序:" + sub);System.out.println();List<Pet> copy = new ArrayList<>(pets);sub = Arrays.asList(pets.get(1), pets.get(4));System.out.println("14. 通过asList获取sub:" + sub);copy.retainAll(sub);System.out.println("15. 求交集,保留在copy和sub中都存在的元素:" + copy);System.out.println();copy = new ArrayList<>(pets);System.out.println("16. copy获得了一个pets的副本:" + copy);System.out.println();System.out.println("17. 检测pets是否为空:" + pets.isEmpty());pets.clear();System.out.println("18. pets被clear()清空:" + pets.isEmpty());System.out.println();Object[] o = copy.toArray();System.out.println("19. toArray()可以将任意Collection转换为一个数组:" + o[3]);}
}

        程序执行的结果是:

        如之前所说的,List可以在创建后添加或移除元素,而且可以自己调整大小。

        当需要查找某个元素的索引编号,或按照引用从List中删除某个元素时,都会使用到equal()方法(这个方法是Object的组成部分)。另外,每一个Pet都是一个独立的对象,这就是为什么输出5和输出6无法进行匹配的原因。

    应该意识到,List的因为会随着equal()行为的改变而改变。

        尽管插入和删除的操作需要较高的成本,但这并不意味着我们要在插入或删除时将一个ArrayList转变为LinkedList。这只意味着我们需要注意这个问题,若ArrayList执行多次插入后程序变慢,我们应该看看List的实现(可以使用分析器)。这种优化较为棘手,若不必担心可以暂时放到一边。

Iterator(迭代器)

        不管是哪种集合,都会需要通过某种方式完成元素的存取。比如List中的add()get()

        但当我们开始思考更加复杂的代码时,会发现这样一个缺点:要使用集合,编写程序时就必须考虑集合的确切类型。如果我一开始针对List编写代码,进行优化时却希望将集合修改为Set,这时就麻烦了。

        为此,就出现了迭代器(它同时也是一种设计模式)的概念。迭代器是一个对象,可以在序列中移动,并用来选择序列中的每个对象。并且使用它的程序员不需要知道序列的底层结构

    另外,迭代器是一个轻量级对象,创建成本很低。也因此,迭代器往往会具有一些使用限制。

        Java中的Iterator只能向一个方向移动,并且只能实现几个功能:

  • iterator():让Collection返回一个Iterator。此时,这个迭代器会准备好返回序列中的第一个元素。
  • next():获得序列中的下一个对象。
  • hasNext():检测序列是否存在更多对象。
  • remove():删除迭代器最近返回的元素。

        下列例子中的PetCreator().list()能够返回一个装载了随机Pet对象的ArrayList(笔者是使用了switch语句对这个方法进行了实现)

import java.util.Iterator;
import java.util.List;public class SimpleIteration {public static void main(String[] args) {// PetCreator().list()会返回一个ArrayList,其中包含随机填充的Pet对象List<Pet> pets = new PetCreator().list(12);Iterator<Pet> it = pets.iterator();while (it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ":" + p + " ");}System.out.println();// 可以使用一种更简单的方式for (Pet p : pets)System.out.print(p.id() + ":" + p + " ");System.out.println();// 也可以使用迭代器来删除元素it = pets.iterator();for (int i = 0; i < 6; i++) {it.next();it.remove();}System.out.println(pets);}
}

        程序执行的结果如下:

        Iterator的存在使得程序员不再需要操心集合中的元素数量,因为使用hasNext()next()就能做到不错的处理。

    若只需要对List进行遍历,for-in语句显得更加简洁。

        这种对集合中的每个对象执行一个操作的想法十分有用,可以在许多地方发现。

        上述的例子还无法完全展示Iterator的作用,下面的例子将会创建一个与具体的集合类型无关的display()方法:

        :为了实现这一例子,自制的Pet类需要继承并实现Comparable接口。其中需要被实现的compareTo()方法就是为了进行对象排序而定义的。

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;public class CrossCollectionIteration {public static void display(Iterator<Pet> it) {while (it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ":" + p + " ");}System.out.println();}public static void main(String[] args) {List<Pet> pets = new PetCreator().list(8);LinkedList<Pet> petsLL = new LinkedList<>(pets);HashSet<Pet> petsHS = new HashSet<>(pets);TreeSet<Pet> petsTS = new TreeSet<>(pets);display(pets.iterator());display(petsLL.iterator());display(petsHS.iterator());display(petsTS.iterator());}
}

        程序执行的结果如下:

        这个例子体现了Iterator真正的作用:能够将序列的遍历操作和序列的底层结构分离。也就是说,迭代器统一了对集合的访问

        Iterable接口描述了“任何可以产生一个迭代器的事物”。

使用这一接口可以将上述例子修改成更加简洁的版本:

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;public class CrossCollectionIteration2 {public static void display(Iterable<Pet> ip) {Iterator<Pet> it = ip.iterator();while (it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ":" + p + " ");}System.out.println();}public static void main(String[] args) {List<Pet> pets = new PetCreator().list(8);LinkedList<Pet> petsLL = new LinkedList<>(pets);HashSet<Pet> petsHS = new HashSet<>(pets);TreeSet<Pet> petsTS = new TreeSet<>(pets);// 可以直接传入数组display(pets);display(petsLL);display(petsHS);display(petsTS);}
}

        程序执行的结果与上面的例子无异,不再重复展示。在这里,因为ArrayList已经实现了Iterable接口,所以display()方法在调用时更加方便了。

        ListIteratorIterator的一个更强大的子类型,只有List类才会生成。与Iterator不同,ListIterator可以双向移动。除此之外,它还可以生成相对于迭代器在列表中指向的当前位置的下一个和上一个元素的索引。并且可以使用set()方法替换它所访问过的最后一个元素。

import java.util.List;
import java.util.ListIterator;public class ListIteration {public static void main(String[] args) {List<Pet> pets = new PetCreator().list(8);ListIterator<Pet> it = pets.listIterator();while (it.hasNext())System.out.print(it.next() + ", " + it.nextIndex() + ", " + it.previousIndex() + ";   ");System.out.println();// 也可以进行反向的遍历while (it.hasPrevious())System.out.print(it.previous().id() + " ");System.out.println();System.out.println(pets);it = pets.listIterator(3);while (it.hasNext()) { // 从下标为3的位置开始替换对象it.next();it.set(new PetCreator().get());}System.out.println(pets);}
}

        程序执行的结果是:

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

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

相关文章

C#中实现单元测试的示例流程_MSTest测试项目

一、单元测试简介 1.1、单元测试简介 在《单元测试艺术》一书中对于单元测试的定义是&#xff1a;【一个单元测试是一段代码&#xff0c;这段代码调用一个工作单元&#xff08;指&#xff1a;调用软件中的一个方法&#xff0c;这个方法执行过程中所发生的所有行为以及最后产生…

Day05-循环高级和数组

循环高级 1.无限循环 概念&#xff1a; 又叫死循环。循环一直停不下来。 for格式&#xff1a; for(;;){System.out.println("循环执行一直在打印内容"); } 解释&#xff1a; 初始化语句可以空着不写&#xff0c;表示循环之前不定义任何的控制变量。 条件判断…

maven中relativepath标签的含义

一 relative标签的含义 1.1 作用 这个<parent>下面的<relativePath>属性&#xff1a;parent的pom文件的路径。 relativePath 的作用是为了找到父级工程的pom.xml;因为子工程需要继承父工程的pom.xml文件中的内容。然后relativePath 标签内的值使用相对路径定位…

ChatGPT 在机器学习中的应用

办公室里一个机器人坐在人类旁边&#xff0c;Artstation 上的流行趋势&#xff0c;美丽的色彩&#xff0c;4k&#xff0c;充满活力&#xff0c;蓝色和黄色&#xff0c; DreamStudio出品 一、介绍 大家都知道ChatGPT。它在解释机器学习和深度学习概念方面也非常高效&#xff0c;…

matplotlib绘图实现中文宋体的两种方法(亲测)

方法一&#xff1a;这种方法我没有测试。 第一步 找宋体字体 &#xff08;win11系统&#xff09; 2.matplotlib字体目录&#xff0c;如果不知道的话&#xff0c;可以通过以下代码查询&#xff1a; matplotlib.matplotlib_fname() 如果你是Anaconda3 安装的matplotlib&#x…

uni-app打包iOS ipa文件后不上架App store为用户提供下载解决过程记录

写在前面&#xff0c;itms-services协议是什么 itms-services协议是苹果提供的一种让iOS应用在用户设备上无线安装或升级的协议。 具体来说: itms-services表示iOS应用无线安装服务的URL方案,格式为:itms-services://?actiondownload-manifest&urlMANIFEST_URL其中MANIF…

Apache Beam 2.50.0发布,该版本包括改进功能和新功能

导读我们很高兴向您介绍 Beam 的新版本 2.50.0。该版本包括改进功能和新功能。请查看此版本的下载页面。 亮点 Spark 3.2.2 被用作 Spark 运行程序的默认版本&#xff08;#23804&#xff09;。Go SDK 新增默认本地运行程序&#xff0c;名为 Prism&#xff08;#24789&#xff0…

基于web的学校二手书城系统/二手书交易系统

摘 要 本文论述了学校二手书城系统的设计和实现&#xff0c;该网站从实际运用的角度出发&#xff0c;运用了计算机网站设计、数据库等相关知识&#xff0c;网络和Mysql数据库设计来实现的&#xff0c;网站主要包括用户注册、用户登录、浏览图书、搜索图书、查看图书并进行购买…

大数据Flink(八十五):Window TVF 支持多维数据分析

文章目录 Window TVF 支持多维数据分析 一、Grouping Sets 二、​​​​​​​Rollup

【数据库】存储引擎InnoDB、MyISAM、关系型数据库和非关系型数据库、如何执行一条SQL等重点知识汇总

目录 存储引擎InnoDB、MyISAM的适用场景 关系型和非关系型数据库的区别 MySQL如何执行一条SQL的 存储引擎InnoDB、MyISAM的适用场景 InnoDB 是 MySQL 默认的事务型存储引擎&#xff0c;只有在需要它不支持的特性时&#xff0c;才考虑使用其它存储引擎。实现了四个标准的隔…

Vue2+ElementUI 静态首页案例

源码 <template><div class"app-container home"><el-row type"flex" justify"space-around" class"row-bg"><el-card class"box-card cardDiv1"><el-col :span"5"><div clas…

软考-操作系统

/4操作系统的作用 进程 进程的概念 进程是程序的一次执行过程&#xff0c;没有程序就没有进程 进程可有多个线程&#xff0c;线程可共享资源 进程的两个基本属性&#xff1a; 可拥有资源的独立单位可独立调度和分配资源的基本单位 线程可共享&#xff1a; 内存地址空间代码…

自定义Unity组件——AudioManager(音频管理器)

需求描述 在游戏开发中&#xff0c;音频资源是不可或缺的&#xff0c;通常情况下音频资源随机分布&#xff0c;各个音频的操作和管理都是各自负责&#xff0c;同时对于音频的很多操作逻辑都是大同小异的&#xff0c;这就造成了许多冗余代码的堆叠&#xff0c;除此之外在获取各类…

Axure RP9 引入eCharts图表

一、 ECharts 地址&#xff1a;https://echarts.apache.org/zh/index.html 概述&#xff1a;一个基于 JavaScript 的开源可视化图表库 提供了很多图标样式案例 二、 Axure引入eCharts图表步骤 步骤一&#xff1a;打开Axure&#xff0c;添加矩形元素&#xff0c;调整矩形所…

WorkPlus私有化部署IM即时通讯平台,构建高效安全的局域网办公环境

随着数字化转型的加速&#xff0c;政府机构与企业对高效、安全的即时通讯和协作工具的需求日益增长。企业微信和钉钉作为当前市场上较为常见的通讯工具&#xff0c;虽然在一定程度上满足了企业内部协作的需求&#xff0c;但仍存在一些问题&#xff0c;如数据安全性、私有化部署…

静态路由+BFD实例

项目拓扑与项目需求 项目需求 ① 主链路为电信&#xff0c;电信链路出故障时&#xff0c;业务数据流量切换到联通链路 实验步骤 步骤1&#xff1a;设备重命名以及IP地址的配置 设备 接口编号 IP地址 AR1 G0/0/0 10.0.13.1/24 G0/0/1 10.0.14.1/24 AR2 G0/0/0 10.0…

IntelliJ IDEA快速查询maven依赖关系

1.在Maven窗口中点击Dependencies->show Dependencies 2.得到依赖关系图 此时原有快捷键Ctrlf可以查询jar包&#xff0c;如果没有查询菜单出来则设置快捷键方式为 File->Settings->Keymap->搜索栏输入find->在Main Menu下Edit下Find下Find双击算则Add keyboard…

项目任务管理上的一些总结

1. 开发任务管理现状&#xff1a; 1&#xff1a;基于禅道进行任务派发&#xff0c;缺少任务统计&#xff0c;进度上只能以“来不及”、“进度正常”、“进度延后”等模糊字眼。 2&#xff1a;“感觉”工作效率不高了&#xff0c;工作量是否饱和&#xff0c;任务投入产出偏差多…

vue3中$refs使用调整

前言&#xff1a; vue3环境 在vue2环境中&#xff0c;可以直接通过this.$refs获取模块&#xff1b;在vue3环境中&#xff0c;通用以下两种方式获取&#xff1a; 1、通过声明ref进行获取&#xff1b; import { ref} from vue; const logoForm ref(); console.log(logoForm.va…

NSDT孪生场景编辑器系统介绍

一、产品背景 数字孪生的建设流程涉及建模、美术、程序、仿真等多种人才的协同作业&#xff0c;人力要求高&#xff0c;实施成本高&#xff0c;建设周期长。如何让小型团队甚至一个人就可以完成数字孪生的开发&#xff0c;是数字孪生工具链要解决的重要问题。考虑到数字孪生复杂…