泛型的详解

2023-11-10

一、泛型的含义?为什么要使用泛型?

​ ==泛型,即“参数化类型”。==一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

​ 泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

二、初识泛型(集合的例子)

一个被举了无数次的例子:

public class ArrayDemo {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("abc");
        list.add(100);
		//遍历
        for (int i = 0; i < list.size(); i++) {
            //强转为string类型
            String rs = (String)list.get(i);
            System.out.println(rs);
        }
    }
}

毫无疑问,程序的运行结果会以崩溃结束:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hYxH0ZtY-1669795986876)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667548462541.png)]

​ ArrayList可以存放任意类型,例子中添加了一个String类型,又添加了一个Integer类型,在使用时都以String的方式使用,因此程序崩溃了。为了解决类似这样的问题(在编译阶段就可以解决),泛型应运而生。

​ 我们将第一行声明初始化list的代码更改一下,编译器会在编译阶段就能够帮我们发现类似这样的问题。意思是这个集合中存储String类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-01L35ypO-1669795986877)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667548594317.png)]

三、泛型特性

泛型只在编译阶段有效。看下面的代码:

public class ArrayDemo3 {
    public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        //获取Class对象
        Class c1 = list1.getClass();
        Class c2 = list2.getClass();
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c1==c2); //true
    }
}

输出结果:Class类型相同。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ON5nPdbc-1669795986878)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667552038490.png)]

​ 通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在**编译阶段有效。**在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。

​ 对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。

四、泛型的使用

泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法

1、 泛型类

​ 泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。

格式如下:

class 类名称<T>{
  private T var; //var是属性 类型为泛型
  .....
  }
}

一个普通的泛型类:

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T> {
    //key这个成员变量的类型为T,T的类型由外部指定
    private T key;
    //泛型构造方法形参key的类型也为T,T的类型由外部指定
    public Generic(T key) {
        this.key = key;
    }
    //泛型方法getKey的返回值类型为T,T的类型由外部指定
    public T getKey() {
        return key;
    }
}

测试类:

//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
public static void main(String[] args) {
    //传入的实参类型需与泛型的类型参数类型相同,即为Integer.
    Generic<Integer> integerGeneric = new Generic<>(12334);
    //传入的实参类型需与泛型的类型参数类型相同,即为String
    Generic<String> stringGeneric = new Generic<>("wewe");

    System.out.println(integerGeneric.getKey());
    System.out.println(stringGeneric.getKey());
}

输出结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0H0imFd2-1669795986879)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667566872336.png)]

​ 定义的泛型类,就一定要传入泛型类型实参么?并不是这样,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

看一个例子:

Generic generic = new Generic("111111");
Generic generic1 = new Generic(4444);
Generic generic2 = new Generic(55.55);
Generic generic3 = new Generic(false);
System.out.println(generic.getKey());
System.out.println(generic1.getKey());
System.out.println(generic2.getKey());
System.out.println(generic3.getKey());

输出结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZHaLcCQ-1669795986879)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667567245223.png)]

2 、泛型接口

​ 泛型接口与泛型类的定义及使用基本相同。格式如下:

//定义一个泛型接口
public interface 接口名<T> {
     T next(); //接口中的抽象方法
}

当实现泛型接口的类,未传入泛型实参时:

/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * 即:class GeneratorImpl<T> implements Generator<T>{
 * 如果不声明泛型,如:class GeneratorImpl implements Generator<T>,编译器会报错:"Unknown class"
 */
public class GeneratorImpl<T> implements Generator<T> {
    @Override
    public T next() {
        return null;
    }
}

当实现泛型接口的类,传入泛型实参时:

/**
 * 传入泛型实参时:
 * 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>
 * 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
 * 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。
 */
public class GeneratorImpl2 implements Generator<String> {

    private String[] musicer = {"黄家驹","陈奕迅","林俊杰"};
    @Override
    public String next() {
        //随机返回一个明星名称
        int random = (int) (Math.random() * 3);
        return musicer[random-1];
    }

    //测试
    public static void main(String[] args) {
       Generator generator = new GeneratorImpl2();
       //输出结果
        System.out.println(generator.next());
    }
}

3、泛型通配符

​ 我们知道Ingeter是Number的子类,Generic与Generic实际上是相同的一种基本类型。那么问题来了,在使用Generic作为形参的方法中,能否使用Generic的实例传入呢?在逻辑上类似于Generic和Generic是否可以看成具有父子关系的泛型类型呢?

为了弄清楚这个问题,我们使用Generic这个泛型类继续看下面的例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIVSuixU-1669795986879)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667568735152.png)]

​ 以上结果说明,**Generic不能被看作为`Generic的子类。**由此可以看出:同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

​ 回到上面的例子,如何解决?总不能为了定义一个新的方法来处理Generic类型的类,这显然与java中的多态理念相违背。因此我们需要一个在逻辑上可以表示同时是Generic和Generic父类的引用类型。由此泛型通配符应运而生。

我们可以将上面的方法改一下:

public class GenericDemo {
    //给定的是 ?类型
    public static void showKeyValue(Generic<?> obj) {
        System.out.println(obj.getKey());
    }

    public static void main(String[] args) {
        Generic<Integer> integerGeneric = new Generic<Integer>(123);
        Generic<Number> numberGeneric = new Generic<Number>(456);
        System.out.println(integerGeneric.getKey());
        System.out.println(numberGeneric.getKey());
    }
}

​ 类型通配符一般是使用 ?代替具体的类型实参,注意了,此处’?’是类型实参,而不是类型形参 。再直白点的意思就是,**此处的 ?和Number、String、Integer一样都是一种实际的类型,**可以把 ?看成所有类型的父类。是一种真实的类型。

​ 可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。

4、泛型方法

​ 泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。

①、泛型方法的格式如下:

访问修饰符  [普通修饰符]  <T>  void/T 方法名(参数){
        //方法体
}

②、泛型方法的基本介绍:

public class GenericMethod1 {

    /**
     *
     * 1)public 与 返回值 中间<T>非常重要,可以理解为声明此方法为泛型方法。
     * 2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
     * 3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
     * 4)与泛型类的定义一样,此处T可以随便写为任意标识,如T、E、K、V等形式的参数常用于表示泛型。
     */

    public <T> void showArray(T[] arr){
        for (T t : arr) {
            System.out.println(t);
        }
    }
}

③、泛型方法的基本用法:

public class Demo1 {
    /**
     * 显示数组内容
     *
     * @param array
     * @param <T>
     */
    private static <T> void showArray(T[] array) {
        for (T t : array) {
            System.out.println(t);
        }
    }
    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
        //泛型方法实例化的时候指定具体参数
        String[] strings = {"tom", "cat"};
        showArray(strings);
        Integer[] integers = {10, 20, 30};
        showArray(integers);
        User[] users = new User[2];
        users[0] = new User(1, "tom");
        users[1] = new User(2, "tom");
        showArray(users);
    }
}

④、利用泛型对数组的增删改查

a.设计泛型接口:

public interface ArrayService2<E> {
    /**
     * 显示数组
     *
     * @param array
     */
    void show(E[] array);

    /**
     * 添加
     *
     * @param array
     * @param e
     * @return
     */
    E[] add(E[] array, E e);

    /**
     * 根据对象删除
     *
     * @param array
     * @param e
     * @return
     */
    E[] delete(E[] array, E e);

    /**
     * 根据索引删除
     *
     * @param array
     * @param index
     * @return
     */
    E[] delete(E[] array, int index);

    /**
     * 查找索引位置
     * @param array
     * @param e
     * @return
     */
    int getIndex(E[] array, E e);

    /**
     * 取值
     * @param array
     * @param index
     * @return
     */
    E get(E[] array, int index);
}

b、编写实现类

public class ArrayServiceImpl2<E> implements ArrayService2<E> {
    public E[] array;
     @Override
    public void show(E[] array) {
        for (E e : array) {
            System.out.println(e);
        }
    }

    @Override
    public E[] add(E[] array, E e) {
        //先扩容
        array = Arrays.copyOf(array, array.length + 1);
        array[array.length - 1] = e;
        return array;
    }

    @Override
    public E[] delete(E[] array, E e) {
        if (array.length==0||array==null){
            System.out.println("[该集合为空]");
        }
        int index = getIndex(array, e);
        //不存在
        if (index == -1) {
            System.out.println("[删除失败,该对象不存在]");
            return array;
        }
        //找到后调用方法 根据索引删除元素
        return delete(array, index);
    }

    @Override
    public E[] delete(E[] array, int index) {
        //将后面元素覆盖签名
        for (int i = index; i < array.length - 1; i++) {
            array[i] = array[i + 1];
        }
        //缩容
        array = Arrays.copyOf(array, array.length - 1);
        return array;
    }

    @Override
    public int getIndex(E[] array, E e) {
        for (int i = 0; i < array.length; i++) {
            if (array[i].equals(e)) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public E get(E[] array, int index) {
        for (int i = 0; i < array.length; i++) {
            if (array[index].equals(array[i])) {
                return array[i];
            }
        }
        return null;
    }
}

c、测试类

public class ArrayTest2 {
    public static void main(String[] args) {
        test2();
        List<String> list = new ArrayList<>(10);
        list.add("2");

    }

    public static void test1() {
        ArrayService2<String> arrayService = new ArrayServiceImpl2<>();
        String[] names = {"car", "jim", "lucy", "lili"};

        //添加
        names = arrayService.add(names, "kit");
        //通过元素查询索引
        int jimIndex = arrayService.getIndex(names, "jim");

        //展示数组
        arrayService.show(names);
        System.out.println("jim的索引: " + jimIndex);

        //删除索引元素
        names = arrayService.delete(names, jimIndex);
        System.out.println("执行删除操作后的数组: ");
        arrayService.show(names);

        //根据索引获取值
        String s = arrayService.get(names, 2);
        System.out.println("根据索引获取值: " + s);

        //根据元素删除
        names = arrayService.delete(names, "car");
        System.out.println("删除car之后的数组: ");
        arrayService.show(names);
    }

    public static void test2() {
        ArrayService2<User> arrayService = new ArrayServiceImpl2<>();
        User user1 = new User(1, "jim");
        User user2 = new User(2, "cat");
        User user3 = new User(3, "tom");
        User[] users = {user1, user2, user3};


        //根据索引获取对象
        System.out.println("获取值通过索引: ");
        User user = arrayService.get(users, 2);
        System.out.println(user);

        //添加数组
        users = arrayService.add(users, new User(4, "lili"));

        //展示数组
        System.out.println("添加后的数组: ");
        arrayService.show(users);

        //根据对象删除数组
        users = arrayService.delete(users, 2);
        System.out.println("根据对象删除后的数组: ");
        arrayService.show(users);

        //根据对象删除数组
        users = arrayService.delete(users, new User(1, "jim"));
        System.out.println("根据对象删除后的数组: ");
        arrayService.show(users);

        //根据对象获取索引
        int jimIndex = arrayService.getIndex(users, new User(1, "jim"));
        System.out.println("根据对象获取索引: "+jimIndex);
    }
}

⑤、 泛型方法与可变参数

再看一个泛型方法和可变参数的例子:

public class TestDemo {
    /**
     * 泛型与可变参数
     * @param params 可变参数
     * @param <T> 泛型
     */
    public static  <T> void printMess(T...params){
        for (T t : params) {
            System.out.println(t);
        }
    }
    //测试
    public static void main(String[] args) {
        //调用方法
        printMess("我","帅哥","蔡徐坤");
    }
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0bYYbO87-1669795986880)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667570451559.png)]

事实上,可变参数就是数组,而且利用泛型,可以接收任意类型的数据。

⑥、泛型方法总结

​ 泛型方法能使方法独立于类而产生变化,以下是一个基本的指导原则:无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法将整个类泛型化,那么就应该使用泛型方法。另外对于一个static的方法而已,无法访问泛型类型的参数。所以如果static方法要使用泛型能力,就必须使其成为泛型方法。

⑦、泛型上下边界

​ 在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类。

a、为泛型添加上边界,即传入的类型实参必须是指定类型的子类型 <? extends T>

public class TestDemo2 {
    /**
     * 定义一个泛型方法(上下边界),打印内容
     * @param obj
     */
    public static void showValue(Generic<? extends Number> obj) {
        System.out.println(obj.getKey());
    }
    //测试
    public static void main(String[] args) {
        Generic<String> generic1 = new Generic<String>("11111");
        Generic<Integer> generic2 = new Generic<Integer>(2222);
        Generic<Float> generic3 = new Generic<Float>(2.4f);
        Generic<Double> generic4 = new Generic<Double>(2.56);
        //这一行代码编译器会提示错误,因为String类型并不是Number类型的子类
//        showValue(generic1);
        showValue(generic2);
        showValue(generic3);
        showValue(generic4);
    }
}

出错的情况如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plzxGXFZ-1669795986881)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1667570882255.png)]

如果我们把泛型类的定义也改一下:

public class Generic<T extends Number>{
    private T key;
	public Generic(T key) {
    this.key = key;
	}

	public T getKey(){
    return key;
	}
}
//这一行代码也会报错,因为String不是Number的子类
Generic<String> generic1 = new Generic<String>("11111");

b、泛型的下限格式: <?super T>

通过上面的两个例子可以看出:泛型的上下边界添加,必须与泛型的声明在一起 。

五、总结

​ 1、实现通用性比较强的代码推荐使用泛型。

​ 2、泛型在存储的时候不能存储基本数据类型,只能存储引用数据类型

​ 3、定义泛型类、方法或者接口时,定义成形式参数,然后在使用/调用时传入具体的类型。

  showValue(generic4);
}

}


出错的情况如下图:

[外链图片转存中...(img-plzxGXFZ-1669795986881)]

如果我们把泛型类的定义也改一下:

```java
public class Generic<T extends Number>{
    private T key;
	public Generic(T key) {
    this.key = key;
	}

	public T getKey(){
    return key;
	}
}
//这一行代码也会报错,因为String不是Number的子类
Generic<String> generic1 = new Generic<String>("11111");

b、泛型的下限格式: <?super T>

通过上面的两个例子可以看出:泛型的上下边界添加,必须与泛型的声明在一起 。

五、总结

​ 1、实现通用性比较强的代码推荐使用泛型。

​ 2、泛型在存储的时候不能存储基本数据类型,只能存储引用数据类型

​ 3、定义泛型类、方法或者接口时,定义成形式参数,然后在使用/调用时传入具体的类型。

​ 4、合理运用泛型通配符和上下限,优化代码提高通用性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

泛型的详解 的相关文章

随机推荐

  • Hystrix使用说明,配置参数说明

    四 配置信息 default或HystrixCommandKey 最常用的几项 超时时间 默认1000ms 单位 ms 1 hystrix command default execution isolation thread timeout
  • 1141:删除单词后缀(C C++)

    题目描述 给定一个单词 如果该单词以er ly或者ing后缀结尾 则删除该后缀 题目保证删除后缀后的单词长度不为0 否则不进行任何操作 输入 输入一行 包含一个单词 单词中间没有空格 每个单词最大长度为32 输出 输出按照题目要求处理后的单
  • BigQuery 如何帮助大规模交付业务型企业提供物联网解决方案

    介绍 Leverege是一家软件公司 它使全球市场领导者能够快速且经济高效地构建企业物联网应用程序 以提供以数据为中心的决策能力 优化运营 改善客户体验 交付客户价值并增加收入 Leverege 的主要 SaaS 产品 Leverege I
  • 不用虚拟机也能在Windows下使用Linux

    不用虚拟机也能在Windows下使用Linux 想学习热门的Linux系统 可是一开始就需要安装虚拟机软件 这样很容易消耗Linux初学者的热情 比如常用的VMWare虚拟机 虽然步骤并不复杂 但是一开始的搭建和配置过程 容易劝退一部分新手
  • 开源CA搭建-基于openssl实现数字证书的生成与分发

    目录 一 前言 二 openssl介绍 三 openssl的常用用法 一 单向加密 二 生成随机数 三 生成公钥 私钥 1 生成私钥 2 提取公钥 四 搭建CA 一 创建根CA私钥 二 生成自签名证书 三 创建数据库以及新颁发证书数字 四
  • Gitee Go代码格式审查、程序编译和冒烟测试

    本文分享自中移OneOS微信公众号 CI CD搭建流程 Gitee篇 作者 Kisann Gitee CI CD能力 Gitee 即码云 是OSCHINA NET推出的代码托管平台 已有超过600 万的开发者选择Gitee Gitee Go
  • ESP8266实现网页交互

    前言 物联网LOT intermet of things 时代 万物互联 wifi芯片是非常重要的 乐鑫的高性价比的ESP8266芯片凭借低功耗低成本高集成度等优势在市场上占有较高的份额 为什么选用这款芯片可以参考之前的调研报告 在之前的资
  • RBF神经网络参数的参数优化(进化算法)+Matlab源码

    RBF神经网络参数的参数优化 进化算法 1 RBF神经网络引入 1985年 Powell提出了多变量插值的径向基函数 RBF 方法 径向基函数是一个取值仅仅依赖于离原点距离的实值函数 也就是 x x 或者还可以是到任意一点c的距离 c点称为
  • aix系统常用的命令

    1 系统性能 1 看 CPU个数 lsdev C grep proc 几条记录就是几个CPU 注意考虑 AIX 5 3的 SMP 2 看每个CPU的大小 lsattr El proc0 3 看 内存条数 lsdev C grep mem 4
  • 借助LVS+Keepalived实现负载均衡

    借助LVS Keepalived实现负载均衡 一 负载均衡 必不可少的基础手段 1 1 找更多的牛来拉车吧 当前大多数的互联网系统都使用了服务器集群技术 集群即将相同服务部署在多台服务器上构成一个集群整体对外提供服务 这些集群可以是Web应
  • ElasticSearch 学习笔记(一):倒排索引(Inverted index)

    分析一个术语 要先从名称入手倒排索引 英文原名Inverted index 大概因为 Invert 有颠倒的意思 就被翻译成了倒排 但是倒排这个名称很容易让人理解为从A Z颠倒成Z A 个人觉得翻译成反向索引更好 倒排索引是区别于正排索引
  • Java中Path环境变量的设置

    第一步 打开文件管理器选择 此电脑 右键 此电脑 选择属性 第二步 再此电脑属性页面找到 高级系统设置 第三步 选择 环境变量 选择最下面的新建 则弹出新建系统变量 变量名为JAVA HOME 一定要大写 变量值为jdk的存储路劲 变量名
  • 小程序首页轮播图设计

    效果图 微信小程序的数据详解 indicator dots 是否显示面板指示点 默认false indicator color 指示点颜色 默认rgba 0 0 0 3 indicator active color 当前选中的指示点颜色 默
  • java如何使用cdn_网站部署使用CDN网络缓存(示例代码)

    CDN原理及为自己的网站部署 CDN是什么 CDN Content Delivery Network or Content Ddistribute Network 内容分发网络 其目的是使用户可就近取得所需内容 解决 Internet网络拥
  • 【超分辨率实验】使用MMEditing进行图像超分辨率

    使用MMEditing进行图像超分辨率 使用MMEditing进行图像超分辨率 安装MMEditing 使用预训练模型完成推理 查找并下载预训练模型 调用API构建模型 调用API进行推理 分析图像恢复效果 使用自定义的数据集微调模型 准备
  • shell命令更新mysql数据库

    bin sh mysql h10 10 10 10 uroot p123456 e use centain database use finereport close sage model for update SET SQL SAFE U
  • 扫雷游戏及代码实现(超详细)

    扫雷游戏及代码实现 前言 1 游戏程序主函数 2 游戏实现原理 游戏过程 3 游戏代码实现 3 1 初始化和打印 3 2 布置雷区 3 3 玩家排查雷 3 4 系统扫描雷 前言 想必屏幕前的你 肯定玩过windows系统自带的那个游戏 扫雷
  • PCB板中字母代表的含义

    PCB板上元芯件的标识 R 电阻 J 跳线 D 二极管或稳压管 Q 三极管 C 电容 U 集成芯片 L 电感 FB 熔断保险丝 IC 芯片 T 变压器 ZD 稳压二极管 P 有时表示端口 插座等 X和Y代表 晶振 F为 保险电阻 ISO代表
  • 服务器动态文档,动态服务器网页.ppt

    动态服务器网页 修改 删除 记录总数 当前页 页大小 首页 gt 上页 gt 下页 gt 末页 size 2 gt 综合实例1 聊天室实现 数据库Chat mdb中有一个聊天信息表tb Chat info 字段如下 ID 自动编号 主键 N
  • 泛型的详解

    一 泛型的含义 为什么要使用泛型 泛型 即 参数化类型 一提到参数 最熟悉的就是定义方法时有形参 然后调用此方法时传递实参 那么参数化类型怎么理解呢 顾名思义 就是将类型由原来的具体的类型参数化 类似于方法中的变量参数 此时类型也定义成参数