A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 陈福军 中级黑马   /  2013-10-26 22:26  /  2017 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 陈福军 于 2013-10-30 21:29 编辑

最近写作业用的泛型,不知道到底为啥用,求大神解释一下,谢谢

评分

参与人数 2技术分 +11 收起 理由
茹化肖 + 10
haxyek + 1

查看全部评分

6 个回复

倒序浏览
泛型:通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。

例子代码:

class Program

    {

        static void Main(string[] args)

        {

            int obj = 2;

            Test<int> test = new Test<int>(obj);

            Console.WriteLine("int:" + test.obj);

            string obj2 = "hello world";

            Test<string> test1 = new Test<string>(obj2);

            Console.WriteLine("String:" + test1.obj);

            Console.Read();

        }

    }



    class Test<T>

    {

        public T obj;

        public Test(T obj)

        {

            this.obj = obj;

        }

}

    输出结果是:

    int:2

String:hello world



程序分析:

1、  Test是一个泛型类。T是要实例化的范型类型。如果T被实例化为int型,那么成员变量obj就是int型的,如果T被实例化为string型,那么obj就是string类型的。

2、  根据不同的类型,上面的程序显示出不同的值。

评分

参与人数 1技术分 +1 收起 理由
追溯客 + 1

查看全部评分

回复 使用道具 举报 1 0
我现在学到的是泛型集合(泛型集合指的就是只能存储特定类型的集合),我就说一下为什么要用泛型,
例:有一个数组{1,2,3,4,5,6,7,8,9},放在集合里,求最大值、最小值、和、平均数;

不用泛型集合
  1. int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  2.             ArrayList list = new ArrayList();
  3.             list.AddRange(numbers);
  4.             int max = (int)list[0];//用来存放最大值
  5.             int min = (int)list[0];//用来存放最小值
  6.             int sum = 0;
  7.             for (int i = 0; i < list.Count; i++)
  8.             {
  9.                 if ((int)list[i] > max)//当前成员大于max
  10.                 {
  11.                     max = (int)list[i];
  12.                 }
  13.                 if ((int)list[i] < min)//当前成员小于min
  14.                 {
  15.                     min = (int)list[i];
  16.                 }
  17.                 sum += (int)list[i];
  18.             }
  19.             Console.WriteLine("最大值是{0},最小值是{1},总和是{2},平均值是{3}", max, min, sum, sum / list.Count);
复制代码
使用泛型
  1. int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  2.             List<int> list = new List<int>();
  3.             list.AddRange(numbers);
  4.             int max = list[0];//用来存放最大值
  5.             int min = list[0];//用来存放最小值
  6.             int sum = 0;
  7.             for (int i = 0; i < list.Count; i++)
  8.             {
  9.                 if (list[i] > max)//当前成员大于max
  10.                 {
  11.                     max = list[i];
  12.                 }
  13.                 if (list[i] < min)//当前成员小于min
  14.                 {
  15.                     min = list[i];
  16.                 }
  17.                 sum +=list[i];
  18.             }
  19.             Console.WriteLine("最大值是{0},最小值是{1},总和是{2},平均值是{3}", max, min, sum, sum / list.Count);
复制代码
两段代码的区别是,第二个使用了泛型集合,这样,从集合中取值的时候,不需要,转换取值的类型,因为在泛型集合中,已经限定了添加的类型,这样也就不需要装箱和拆箱,提高了程序运行的效率。

评分

参与人数 1技术分 +2 收起 理由
追溯客 + 2

查看全部评分

回复 使用道具 举报
泛型:是一种能表达能够表达更广泛数据的类型,注意咯,泛型变量的值是一种类型,而非类型取值范围内的值。

泛型机制是一种特殊的类型机制,有两方面的功能:

1. 通用型功能:泛型机制提供一种特殊的带参数描述方式(特殊在于:以类型为参数)  比如上面:T是形式参数,T可以取值Integer、String这些类型。

2. 类型检查功能:说到泛型的类型检查,这就是为什么上面那个例子可以用泛型而不能用Object的原因了。借助编译器当你传入的数据a为整形数据而b为字符串数据时编译阶段会报错。

注意:泛型的检查是在编译阶段的,对于这点要谨记。在java的泛型机制中,必须在编译阶段确知填入的具体类型,不支持在程序的运行阶段传入类型参数。普通的参数都是在运行时传入的,但泛型参数必须在编译时确定。

泛型的申明
class 类名 <类型参数列表>{类体}

如: class A<T1, T2> {T1 a; T2 b;}  // 在类体中,你把T1,T2当做已知类来使用就好了

泛型的具体化
类名 <具体类型列表> 变量=new 类名<具体类型列表>{构造函数的参数列表}  // 注意:具体类型必须是引用型类型

如:A<Integer, String> x=new A<Integer, String>();

泛型参数可以出现在什么地方
泛型参数可以出现在类、接口、成员方法、内嵌类、内嵌接口中

值得注意的是:泛型方法不仅可以出现在泛型类中,也可以出现在普通类中。不过,当泛型方法出现在普通类中时,记得要在泛型方法中申明泛型参数。 如:

<T> void function(T a){……}

泛型约束和泛型通配符
泛型约束:<T extends BoundingType>  // BoundingType 可以是类,也可以是接口;可以有多个BoundingType,用&隔开;但只能有一个类并必须放在第一位置

表示 T必须是BoundingType的子类型(具体化时确定了),或者是实现了BoundingType这个接口的类型

如:<T extends Number> // 要求T的值是Number的子类,且不能是Number类型

       <T extends Comparable>  // 要求T的值(类型)是个实现了Comparable接口的类

泛型中的通配符:<? extends T>  // T即可以是类也可以是接口,把?理解为类型参数,T是类型的上界;?必须是T的子类

来比较一下:  LinkList<Number>  // 以具体化,说明LinkList类中的数据必须是Number类型或者Number的子类型

                       LinList<T extends Number>   // T标识的是一种确定的类型参数,需要要具体化的

                       LinkList<? extends Number>  // ?标识的是一种不确定的类型参数,不要具体化的

来验证一下LinkList<Number>的LinkList类中可以是Number的子类型:

[java] view plaincopy
public class Test {  
  
    /**
     * @param args
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        TestClass<Number> test=new TestClass<Number>(3);  
        TestClass<Number> test1=new TestClass<Number>(2.33);  
        //TestClass<Number> test=new TestClass<Integer>(3); 注意:编译报错  
        System.out.println(test.getData());  
        System.out.println(test1.getData());  
    }  
  
}  
class TestClass<T>{  
    private T date;  
    TestClass(T data){  
        this.date=data;  
    }  
    public void  setData(T data){  
        this.date=data;  
    }  
    public T getData(){  
        return this.date;  
    }  
}  
输出:  
3  
2.33  

这样看起来感觉后面两个差不多,其实是非常有区别的,举个列子老看下:

[java] view plaincopy
// 一个链表,节点中的数据必须是可比较的  
  
import java.util.Scanner;  
  
public class Ch_11_3 {  
  
    /**
     * @param args
     */  
    public static void main(String[] args) {  
        // 整形数据链表  
        System.out.println("创建整数链表,以-1结尾:");  
        Scanner in=new Scanner(System.in);  
        LinkList<Integer> int_list=new LinkList<Integer>();  
        int x=in.nextInt();  
        while(x!=-1){  
            int_list.addNode(x);  
            x=in.nextInt();  
        }  
        int_list.printList();  
        System.out.println();  
         
        // String类型数据链表  
        System.out.println("输入一组String,以空格为分隔符:");  
        LinkList<String> string_list=new LinkList<String>();  
        Scanner in_2=new Scanner(System.in);  
        String str=in_2.nextLine();  
        String[] str_array=str.split(" ");  
        for(String s : str_array){  
            string_list.addNode(s);  
        }  
        string_list.printList();  
         
    }  
  
}  
class LinkList<T extends Comparable>{//Comparable 是个接口 <T extends BoundingType> Bounding可以是个类也可以是个接口  
    // 定义节点类  
    class Node{  
        private T data; //节点存储的数据  
        private Node next; //指向后一节点的指针  
         
        public Node(T x){   // 构造函数  
            this.data=x;      
        }  
        public Node getNext(){  //获取节点的后一个节点  
            return this.next;  
        }  
        public void setNext(Node p){    //设置指针的指向元素  
            this.next=p;  
        }  
        public T getData(){ //获取节点元素  
            return this.data;  
        }  
        public void setData(T d){   //设置节点元素  
            this.data=d;  
        }  
    }  
      
    private Node head,tail; // 头指针和尾指针  
    public LinkList(){  
        head=tail=null;  
    }  
    public boolean isEmpty(){   //判断是否为空链表  
        return head==null;  
    }  
    public Node getHead(){  //获取表头  
        return head;  
    }  
    private T max(T a, T b){    //比较两个节点的元素大小  
        return (a.compareTo(b)>0)?a:b;  
    }  
    public T getMaxValue(){ //获取链表中的最大值  
        if(isEmpty()){  
            return null;  
        }  
        T max_value=this.head.getData();  
        Node p=this.head.getNext();  
        while(p!=null){  
            max_value=max(p.getData(),max_value);  
            p=p.next;  
        }  
        return max_value;  
    }  
    public void printList(){  
        Node p=head;  
        while(p!=null){  
            System.out.print(p.getData()+"==");  
            p=p.getNext();  
        }  
    }  
    public void addNode(T x){  
        Node p=new Node(x);  
        if(isEmpty()){  
            head=tail=p;  
        }  
        else{  
            tail.setNext(p);  
            tail=p;  
        }  
    }  
      
}  

评分

参与人数 1技术分 +1 收起 理由
追溯客 + 1

查看全部评分

回复 使用道具 举报
泛型:JDK 1.5版本以后出现的心特性,用于解决安全问题,是一个类型安全机制。

好处
1,将运行时期出现的问题ClassCastException,转移到了编译时期
        方便程序员解决问题,让运行时期问题减少,安全。
2,避免了强制转换的麻烦

泛型的格式:通过<>来定义要操作的引用数据类型
在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见
只要加到<>就要定义泛型

其实<>就是用来接收类型的

当使用集合时,将集合中要存储的的数据类型作为参数传递到<>中即可

//泛型类
class Utils<QQ>
{
        private QQ q;
        public void setObject(QQ q)
        {
                this.q=q;
        }
        public QQ getObject()
        {
                return q;
        }
}
class GenericDemo2
{
        public static void main(String[] args)
        {
                Utils<Worker> u=new Utils<Worker>();
                u.setObject(new Worker());
                Worker w=u.getObject();
        }
}
这就是一个泛型的简单例子希望能帮到你

评分

参与人数 1技术分 +1 收起 理由
追溯客 + 1

查看全部评分

回复 使用道具 举报
使用泛型,第一可以节省时间和空间,防止代码的臃肿,提高效率,因为不用再写很多不同类型的重载。在定义的时候不用写具体的数据类型,只在使用的时候确定数据类型即可。
第二呢,就是在你不确定你的参数会是什么类型的时候使用。
第三 ,也是我们最常用的。就是用泛型集合。List<T>. 我们用泛型集合 可以在使用的时候 省去装箱与拆箱的操作,避免了各种数据类型之间转换容易出错。而且,泛型也是强类型哦。

评分

参与人数 1技术分 +1 收起 理由
追溯客 + 1

查看全部评分

回复 使用道具 举报

问题解决请将分类设为"已解决".黑马有你更精彩
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马