深入理解Java泛型及其在实际编程中的应用

第1章:泛型的起源与重要性

大家好,我是小黑,在Java里,泛型(Generics)是一种不可或缺的特性,它允许咱们在编码时使用类型(Type)作为参数。这听起来可能有点绕,但其实就像是给方法传递参数一样,只不过这次传递的是数据类型而不是数据值。这样一来,咱们就能写出更加通用、更加安全的代码。想象一下,如果有一个容器,这个容器可以装任何类型的数据,不管是整数、字符串还是自定义的对象,这岂不是非常方便?但如果在取出数据的时候,咱们不知道它是什么类型,那就得转换类型,这时候很容易出错。泛型就是来解决这个问题的。

泛型最早在其他编程语言中出现,Java直到JDK 5.0版本才引入泛型,这一改进大大增强了Java的表达能力,同时也提高了代码的安全性和可读性。通过泛型,编译器可以在编译期间检查类型,避免了运行时的ClassCastException,这对于提升大型应用程序的稳定性和健壮性有着不言而喻的好处。

简单来说,泛型就像是一种严格的门卫,确保咱们在代码中严格遵守类型安全,不会不小心把猫当成狗来养。这样一来,就可以大大减少运行时出现问题的可能性,让咱们的程序更加健壮。

第2章:泛型的基本概念

泛型的基础概念围绕着类型参数(Type Parameters)和类型变量(Type Variables)。让小黑来举个栗子,假设咱们要写一个可以存储任意类型元素的容器类。在不使用泛型的世界里,可能会用Object类型来实现,但这样做既不安全也不方便。引入泛型后,情况就大不相同了。

public class GenericContainer<T> {
    private T element;

    public void setElement(T element) {
        this.element = element;
    }

    public T getElement() {
        return this.element;
    }
}

在这个例子中,T就是一个类型参数,它代表着任何类型。当创建GenericContainer实例的时候,可以指定T的具体类型:

GenericContainer<String> stringContainer = new GenericContainer<>();
stringContainer.setElement("泛型真好玩");
String element = stringContainer.getElement(); // 不需要类型转换

这样一来,咱们就可以在编译期间确保类型的安全性,避免了运行时的类型转换错误。此外,泛型不仅仅可以用在类上,还可以用在接口和方法上。比如,咱们可以有一个泛型接口,表示任何可以比较自己的类型:

public interface Comparable<T> {
    int compareTo(T o);
}

或者是一个泛型方法,用来交换数组中两个元素的位置:

public class ArrayUtil {
    public static <T> void swap(T[] array, int i, int j) {
        T temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

通过这个swap方法的例子,可以看到泛型方法的强大之处:它不依赖于类或接口的泛型。这个方法可以用于任何类型的数组,增加了代码的复用性。

小黑偷偷告诉你一个买会员便宜的网站: 小黑整的视頻会园优惠站

第3章:泛型的使用场景与实例

泛型在Java编程中的应用非常广泛,尤其是在集合框架中。在没有泛型之前,咱们处理集合时常常需要进行类型转换,这既繁琐又容易出错。有了泛型之后,这一切都变得简单且安全多了。让小黑来带大家看看泛型在实际编程中是如何发挥作用的。

集合框架中的泛型

在Java的集合框架中,泛型的引入让集合的操作变得类型安全且易于管理。比如说,咱们来看看如何使用泛型创建一个只存储字符串的列表:

List<String> stringList = new ArrayList<>();
stringList.add("Java");
stringList.add("泛型");
// stringList.add(123); // 这行代码会编译错误,因为列表只接受字符串类型

这样,编译器就能在编译期间帮助咱们检查类型错误,避免了运行时的类型转换异常。咱们再也不用担心不小心把整数加入到字符串列表中了。

自定义泛型类和方法的使用

泛型不仅仅局限于集合框架,咱们还可以在自己的类和方法中使用泛型。比如说,小黑想要实现一个可以对任意类型的两个元素进行比较的工具类:

public class Pair<T extends Comparable<T>> {
    private T first;
    private T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public T getBigger() {
        return (first.compareTo(second) > 0) ? first : second;
    }
}

// 使用示例
Pair<Integer> intPair = new Pair<>(1, 2);
System.out.println("较大的数字是:" + intPair.getBigger());

Pair<String> stringPair = new Pair<>("apple", "banana");
System.out.println("字典序较后的是:" + stringPair.getBigger());

在这个例子中,Pair类使用了泛型T,并且限制了T必须是实现了Comparable接口的类型,这样就可以保证T类型的对象是可以比较的。这种方式不仅提高了代码的复用性,也保证了类型安全。

泛型的使用场景远不止这些,咱们在实际编程中会发现,几乎所有需要类型参数的地方都可以用泛型来解决。它不仅可以让代码更加灵活和安全,还可以大大提高代码的可读性和可维护性。随着对泛型理解的加深,咱们会发现它在设计模式、API开发等高级应用中的巨大潜力。

第4章:类型擦除与泛型的局限性

泛型在Java中的实现方式是通过类型擦除(Type Erasure)来完成的,这个概念听起来可能有点抽象,但实际上它对咱们使用泛型有着直接的影响。类型擦除意味着在编译时期,所有的泛型信息都会被擦除掉,换句话说,泛型类型参数在编译后的字节码中都会被替换成它们的限定类型(Bounding Type),如果没有指定限定类型,则默认为Object。这个设计决策带来了一些特别的限制,但也使得Java的泛型能够与之前版本的代码兼容。

类型擦除的实例

让小黑用代码示例来说明类型擦除是怎么一回事:

List<String> stringList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
System.out.println(stringList.getClass() == intList.getClass()); // 输出true

虽然stringListintList是不同类型的泛型实例,但在运行时,它们的类都是ArrayList,没有任何泛型信息。这就是类型擦除的结果。这意味着在运行时,咱们无法获取泛型的具体类型信息,因为它们都被擦除了。

泛型的局限性

由于类型擦除,泛型在Java中有以下几个局限性:

  1. 不能实例化泛型类型的数组

    // T[] array = new T[10]; // 编译错误
    

    这是因为在运行时,JVM需要知道数组的确切类型,而由于类型擦除,这个信息是不可知的。

  2. 不能实例化泛型类的类型参数

    // public class GenericClass<T> {
    //     T obj = new T(); // 编译错误
    // }
    

    同样是因为在运行时,T的具体类型是未知的。

  3. 不能创建具体类型的泛型数组

    // List<Integer>[] arrayOfLists = new List<Integer>[10]; // 编译错误
    

    这违反了Java的类型安全原则,因为泛型类型在运行时会被擦除,导致数组的实际类型只能是List[]

  4. 泛型类不能扩展Throwable

    // public class GenericException<T> extends Exception { } // 编译错误
    

    这是因为异常处理是在运行时进行的,需要知道异常的确切类型。

尽管有这些局限性,泛型仍然是Java编程中非常强大的工具。理解类型擦除和泛型的局限性对于编写健壮和高效的Java代码是非常重要的。通过这些知识,咱们可以更好地利用泛型的优点,同时规避可能遇到的问题。这就需要咱们在使用泛型时既要充分利用其提供的便利和类型安全,又要了解其背后的原理和限制,以便在实际开发中作出恰当的设计和编码决策。

第5章:泛型的继承与通配符

泛型在Java中不仅提高了代码的可读性和安全性,还引入了继承和通配符的概念,这让泛型的应用更加灵活。但是,泛型的继承规则与Java中的类继承有所不同,这经常让初学者感到困惑。让小黑来慢慢道来,希望能让咱们更清晰地理解这个概念。

泛型的继承规则

首先,咱们得明白一个基本概念:在Java泛型中,两个具有相同的泛型类型的类或接口之间,并不存在继承关系。也就是说,List<String>并不是List<Object>的子类型,即使StringObject的子类型。这听起来可能有点违反直觉,但它是有其原因的。这样设计主要是为了确保类型安全,防止咱们在运行时遇到不期望的类型转换错误。

List<Object> objList = new ArrayList<>();
List<String> strList = new ArrayList<>();
// objList = strList; // 编译错误,因为List<String>不是List<Object>的子类型
通配符的使用

为了解决上述问题,Java提供了通配符(Wildcard),用?表示。通配符有两种形式:无界通配符(?),表示任何类型;有界通配符,包括上界通配符(? extends T)和下界通配符(? super T)。

  • 无界通配符(?:当咱们不关心集合中元素的具体类型时,可以使用无界通配符。它主要用于读取操作,因为咱们可以安全地从集合中读取Object类型的数据。
public void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}
  • 上界通配符(? extends T:表示参数化类型的可能是T或T的某个子类型。它限制了未知类型的上限。上界通配符是为了安全地读取T类型数据而设计的。
public <T> T getFirst(List<? extends T> list) {
    return list.get(0); // 安全地返回T类型
}
  • 下界通配符(? super T:表示参数化类型是T或T的某个父类型。下界通配符让咱们可以安全地写入T和T的子类型的对象。
public <T> void addToList(List<? super T> list, T element) {
    list.add(element); // 安全地添加元素
}

通配符使得泛型更加灵活,但同时也增加了泛型的复杂性。理解和正确使用通配符,对于编写健壮的泛型代码来说非常重要。通过上界和下界通配符的使用,咱们可以在保持类型安全的同时,提高代码的灵活性和可用性。

泛型的继承和通配符是Java泛型中非常强大的特性,它们为处理泛型集合提供了更多的灵活性。掌握这些概念,能够帮助咱们更好地设计和实现泛型接口和方法,使代码既安全又灵活。

第6章:泛型方法的深入分析

泛型方法是Java泛型编程中的一个核心概念,它允许在方法级别上指定泛型类型,使得方法能够在不同类型的上下文中重用。这种方法不仅能提升代码的复用性,还能保持代码的清晰度和类型安全。让小黑来带大家深入了解泛型方法的定义、使用以及它的强大之处。

定义泛型方法

泛型方法可以定义在普通类中,也可以定义在泛型类中。它的特点是,在方法返回类型之前有一个类型参数声明部分(由尖括号<>包围的部分)。这告诉编译器,这个特定的方法将会使用一个或多个类型参数。

public class GenericMethodDemo {

    // 定义一个泛型方法,它可以打印不同类型数组的内容
    public static <T> void printArray(T[] inputArray) {
        for (T element : inputArray) {
            System.out.printf("%s ", element);
        }
        System.out.println();
    }
}

在这个例子中,<T>就是类型参数声明,它告诉编译器,T是一个类型参数,printArray方法可以接受T类型的数组,并遍历打印每个元素。

泛型方法的类型推断

调用泛型方法时,大多数情况下不需要显式指定类型参数,因为编译器能够根据方法参数和调用上下文推断出具体的类型。这种特性称为类型推断。

Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"Hello", "World"};

GenericMethodDemo.printArray(intArray); // 类型推断为Integer
GenericMethodDemo.printArray(stringArray); // 类型推断为String

在这个例子中,当调用printArray方法时,不需要指明T代表的是Integer还是String,编译器会自动根据传入参数的类型进行推断。

泛型方法的使用场景

泛型方法非常适用于需要在多种类型之间进行操作的场景。例如,考虑一个交换数组中两个元素位置的方法,这个方法应该能够处理任意类型的数组:

public class ArrayUtil {

    // 泛型方法,用于交换数组中两个元素的位置
    public static <T> void swap(T[] array, int i, int j) {
        T temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

这个swap方法就是一个典型的泛型方法使用示例。它不依赖于数组的具体类型,可以用于整数数组、字符串数组或任何其他类型的数组。

通过上面的示例和讲解,咱们可以看到,泛型方法提供了极大的灵活性和强大的类型安全性。掌握泛型方法的使用,能够让咱们在面对需要广泛重用的方法时,写出更加清晰、简洁且类型安全的代码。这也是Java泛型编程中一个非常重要的概念,理解并掌握它,对于提升咱们的编程技能至关重要。

第7章:泛型的最佳实践

泛型不仅仅是Java编程中的一个高级特性,它还是一种编程思想,帮助咱们写出更加通用、安全和易于维护的代码。但是,要充分利用泛型的优势,避免其陷阱,就需要遵循一些最佳实践。让小黑来跟大家分享一些使用泛型时的建议和技巧。

明确泛型的使用目的

在引入泛型到你的代码中之前,先明确泛型能为你解决什么问题。泛型主要用于以下几个方面:

  • 类型安全:确保你的集合、方法或类在处理数据时不会遇到类型不匹配的问题。
  • 代码复用:通过类型参数化,使得代码可以用于多种数据类型。
  • API清晰:泛型使得方法签名直接表明使用的类型,提高代码的可读性。
避免泛型警告

当你使用泛型时,可能会遇到编译器的警告,比如未经检查的转换警告。这些警告是有其意义的,它们提示可能存在的类型安全问题。不要忽视这些警告,尽可能地解决它们。如果确信代码是类型安全的,可以使用@SuppressWarnings("unchecked")注解来抑制警告,但这应当是最后的选择。

使用有界通配符来增加API的灵活性

当你设计接受泛型参数的方法时,考虑是否可以通过有界通配符(? extends T? super T)来增加方法的通用性。例如,如果你的方法只从泛型参数类型的集合中读取数据,而不会写入,那么使用? extends T可以让你的方法接受更广泛的类型,比如子类型的集合。

优先使用泛型集合

在可能的情况下,总是使用泛型集合而不是原始类型(raw types)的集合。泛型集合不仅可以提供编译时的类型检查,还可以避免在使用集合时的类型转换,使代码更加清晰。

泛型类和方法的设计

在设计泛型类或方法时,要考虑到泛型的类型参数在实际使用中可能带来的限制。例如,如果一个泛型类的方法中需要创建类型参数的实例,那么这个泛型类就只能用于那些具有无参构造函数的类。这时,你可能需要提供一个工厂方法来解决这个问题。

谨慎使用泛型数组

由于泛型和数组的规则有所不同,创建泛型数组是不合法的。如果需要,可以使用泛型集合,如ArrayList<T>,作为替代。泛型集合提供了数组的大部分功能,同时还增加了类型安全性。

遵循这些最佳实践,并不意味着泛型的使用会变得复杂或限制性增强,相反,它们可以帮助咱们更有效地利用泛型带来的好处。随着对泛型更深入的理解和应用,咱们会发现,泛型不仅能提高代码的质量,还能让编程工作变得更加愉快和有成效。通过这些指导原则和技巧,咱们可以避免常见的泛型相关问题,编写出既强大又灵活的Java代码。

第8章:泛型在实际编程中的高级应用

泛型不仅仅是用来增强集合类的类型安全性,它在Java编程中有着更广泛的应用,尤其是在设计模式、API开发以及框架设计中。通过泛型,咱们可以写出更加灵活、可复用且类型安全的代码。

泛型和设计模式

设计模式是解决软件设计问题的通用解决方案。当咱们将泛型应用于设计模式时,会使得这些模式更加灵活和易于使用。以工厂模式为例,泛型可以使得工厂类能够产生多种类型的产品而不需要为每种产品写一个专门的工厂。

interface Product {}

class ProductA implements Product {}

class ProductB implements Product {}

class GenericFactory<T extends Product> {
    private Class<T> kind;

    public GenericFactory(Class<T> kind) {
        this.kind = kind;
    }

    public T createInstance() throws InstantiationException, IllegalAccessException {
        return kind.newInstance();
    }
}

// 使用示例
GenericFactory<ProductA> factoryA = new GenericFactory<>(ProductA.class);
Product a = factoryA.createInstance();

GenericFactory<ProductB> factoryB = new GenericFactory<>(ProductB.class);
Product b = factoryB.createInstance();

在这个例子中,通过泛型,GenericFactory可以用来创建任何Product的子类的实例,大大增加了代码的复用性和灵活性。

泛型在API开发中的应用

在开发泛型API时,泛型不仅可以提高API的灵活性,还可以增强类型安全性。例如,咱们可以设计一个泛型API来处理不同类型的数据转换:

public class DataConverter<T> {
    public <U> U convert(T data, Class<U> targetClass) throws Exception {
        // 实现数据转换逻辑
        // 这里仅为示例,具体实现会根据实际情况而定
        return targetClass.getDeclaredConstructor().newInstance();
    }
}

// 使用示例
DataConverter<String> converter = new DataConverter<>();
Integer convertedData = converter.convert("123", Integer.class);

这个DataConverter类使用泛型方法convert,可以将任意类型的数据转换成另一种类型。通过这种方式,咱们可以创建一个通用的数据转换工具,而不是为每种数据转换写一个单独的方法或工具。

泛型在框架设计中的应用

许多流行的Java框架,如Spring和Hibernate,广泛使用泛型来提供灵活且类型安全的编程接口。以ORM(对象关系映射)框架为例,泛型可以用来定义能够操作任意实体类型的DAO(数据访问对象)接口:

public interface GenericDao<T, ID> {
    T findById(ID id);
    List<T> findAll();
    void save(T entity);
    void update(T entity);
    void delete(T entity);
}

// 实现示例
public class UserDao implements GenericDao<User, Long> {
    // 实现具体方法
}

在这个例子中,GenericDao接口使用泛型定义了一组通用的数据访问方法。实现这个接口的类可以明确指定操作的实体类型和ID类型,这样就可以为不同的实体重用相同的数据访问逻辑,同时保持类型安全。


更多推荐

详解SpringCloud之远程方法调用神器Fegin

掌握Java Future模式及其灵活应用

小黑的视頻会园优惠站

使用Apache Commons Chain实现命令模式

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

倒模专用制作耳机壳UV树脂:改性丙烯酸树脂

倒模专用制作耳机壳的UV树脂是经过改性的丙烯酸树脂&#xff0c;具有高透明度、高粘度、快速固化的特点。这种树脂可以通过紫外线光固化&#xff0c;快速形成坚硬的表面&#xff0c;并且具有较高的硬度和耐磨性&#xff0c;因此非常适合用于制作耳机壳。 此外&#xff0c;改性丙…

anaconda简介以及安装(Windows)

介绍 Anaconda是一个开源的Python发行版本&#xff0c;它是一个打包的集合&#xff0c;里面预装了conda、Python、众多packages、科学计算工具等。Anaconda的目的是方便使用Python进行数据科学研究&#xff0c;它涵盖了数据科学领域常见的Python库&#xff0c;并且自带了专门用…

SpringBoot 整合WebService

文章目录 WebService1.简单介绍WebService1.1. 类型1.2. 架构1.3. 主要特点1.4. 使用场景1.5. Web服务标准和技术 2.案例-WebServiceDemo2.1.引入配置文件2.2.创建接口2.3.创建接口实现类2.4.创建WebService配置类2.5.测试 WebService Web服务&#xff08;Web Services&#xf…

【C语言】指针初阶2.0版本

这篇博文我们来继续学习指针的其他内容 指针2.0 传值调用与传址调用传值调用传址调用 一维数组与指针理解数组名使用指针深入理解一维数组 二级指针指针数组二维数组与指针 传值调用与传址调用 在开始之前&#xff0c;我们需要先了解这个概念&#xff0c;后面才能够正常的学习…

android移动应用开发基础答案,安卓工程师面试题

一线企业的app都是多线程和多进程的&#xff0c;而Android进程间通信机制就是Binder&#xff0c;原生的线程间通信则是Handler&#xff0c;Binder和Handler是了解安卓运行机制必须要掌握的一个知识点&#xff0c;更是一线企业面试必问的知识点&#xff01; 以下几道就是大厂关于…

Ansible的playbook的编写和解析

目录 什么是playbook Ansible 的脚本 --- playbook 剧本 实例部署&#xff08;使用playbook安装启动httpd服务&#xff09; 1.编写一个.yaml文件 在主机下载安装http&#xff0c;将配置文件复制到opt目录下 运行playbook 在192.168.17.77主机上查看httpd服务是否成功开启…

Codeforces Round 930 (Div. 2)题解

A. Shuffle Party&#xff08;Problem - A - Codeforces&#xff09; 题目大意&#xff1a;给定一个n长数组&#xff0c;并使得a[i]i&#xff0c;现在定义一种操作swap(k):找出k的最大不等于自己的除数d&#xff0c;交换a[k]和a[d]&#xff0c;k从1开始直到n结束&#xff0c;问…

训练1 : 老头

以前用blender做的特效 总结 头发很费时间, 需要参考和练习眼窝周边结构还有些待准确把握从光与影中揣摩轮廓形状 从少量面掌握大体, 从多数面雕刻细节

云时代【5】—— LXC 与 容器

云时代【5】—— LXC 与 容器 三、LXC&#xff08;一&#xff09;基本介绍&#xff08;二&#xff09;相关 Linux 指令实战&#xff1a;使用 LXC 操作容器 四、Docker&#xff08;一&#xff09;删除、安装、配置&#xff08;二&#xff09;镜像仓库1. 分类2. 相关指令&#xf…

教师招聘和事业编d类有什么区别吗

每年都有大批怀揣教育梦想的年轻人&#xff0c;站在职业的十字路口&#xff0c;对未来充满期许与疑惑。他们中的许多人都会面临这样一个问题&#xff1a;教师招聘和事业编D类&#xff0c;到底有什么区别&#xff1f;今天&#xff0c;就让我来为你揭开这两者的神秘面纱。 别被这…

基于session注册JAva篇springboot

springboot3全家桶&#xff0c;数据库 &#xff1a;redis&#xff0c;mysql 背景环境&#xff1a;邮箱验证码&#xff0c;验证注册 流程&#xff1a;先通过邮箱验证&#xff0c;发送验证码&#xff0c;将获取到的session和验证码&#xff0c;存入redis里&#xff08;发送邮箱…

3d模型版本转换器注意事项---模大狮模型网

在使用3D模型版本转换器时&#xff0c;有一些注意事项可以帮助您顺利完成模型转换并避免不必要的问题&#xff1a; 数据完整性&#xff1a;在进行模型转换之前&#xff0c;确保您的原始3D模型文件没有损坏或缺失数据。损坏的文件可能导致转换器无法正常处理或输出错误的结果。 …

【前端素材】推荐优质在线大气数码商城电商网页ClassiList平台模板(附源码)

一、需求分析 1、系统定义 电子数码电商平台是专门销售电子数码产品&#xff08;如手机、电脑、相机、智能设备等&#xff09;的在线电子商务平台。这些平台提供了一个便捷的购物环境&#xff0c;让消费者可以方便地浏览、比较和购买各种电子数码产品。 2、功能需求 在线大…

常见外设学习以及无线通信频率

常见外设 UART UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff0c;通用异步收发器&#xff09;是一种异步、串行、全双工的通信总线。 UART 有3根线&#xff0c;分别是&#xff1a;发送线&#xff08;TX&#xff09;、接收线&#xff08;RX&#xff…

找不到msvcp140.dll无法运行程序如何处理?分享5种解决方法

在计算机系统运行过程中&#xff0c;如果无法找到必要的动态链接库文件msvcp140.dll&#xff0c;可能会引发一系列的问题与故障。这个特定的dll文件是Microsoft Visual C Redistributable Package的一部分&#xff0c;对于许多基于此编译环境开发的应用程序至关重要。缺失msvcp…

Android WebView访问网页+自动播放视频+自动全屏+切换横屏

一、引言 近期&#xff0c;我发现电视家、火星直播等在线看电视直播的软件都已倒闭&#xff0c;而我奶奶也再无法通过这些平台看电视了。她已六十多岁&#xff0c;快七十岁啦。这些平台的倒下对我来说其实没有多大的影响&#xff0c;但是对于文化不多的她而言&#xff0c;生活中…

【力扣白嫖日记】550.游戏玩法分析IV

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 550.游戏玩法分析IV 表&#xff1a;Activity 列名类型player_idintdevice_idintevent_datedategames_played…

探秘Python的Pipeline魔法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站AI学习网站。 目录 前言 什么是Pipeline&#xff1f; Pipeline的基本用法 Pipeline的高级用法 1. 动态调参 2. 并行处理 3. 多输出 …

模型练习史

文章目录 肌肉光头vikingtorso死侍蓝毒液卡通girlwalletdog headman anatomy总结 肌肉光头 viking torso 死侍 蓝毒液 卡通girl wallet dog head man anatomy 总结 zbrush 与 blender 结合使用, 善 !

SpringBoot+Vue实战:打造企业级项目管理神器

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…