黑马程序员--泛型

    ----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

 

关键字:TreeSet、泛型

 

Set:无序,不可重复元素。数据结构不一样,保证数据唯一性的方式也不一样。

  |-----HashSet:数据结构是哈希表,线程非同步。

              保证元素唯一性的原理,判断元素的hashCode值是否相同。

              如果相同,还会继续判断元素的equals方法,是否为true。

  |-----TreeSet:可以对Set集合中的元素进行排序,例如,编码表顺序。所以存入的对象必须具备比较性,例如,年龄。所有对象必须实现Comparable才能排序。

              底层数据结构是二叉树,为了保证元素的唯一性,复写CompareTo()方法。

    ClassCastException:类型转换异常。

 

    TreeSet集合

    Comparable接口强制类具备比较性。例如,String类;新建类实现接口并需要复写方法compareTo();才能使用。排序时,当主要条件相同时,一定要判断次要条件。

    compareTo方法,大部分类都有该方法,所以能够进行比较,排出先后顺序。排序考察的是compareTo的结果,即返回值为正数、负数和0,不一定是1或-1。具体的内部过程没有要求,可以自建排列顺序,例如,想要按照输入顺序排列,只返回-1即可;按照反输入顺序排列,只返回1,反向取元素。

    二叉树结构:第一个元素为起点,小的(compareTo返回-1)放左下方,大的(compareTo返回1)放右下方,依次放置,一个数只能有2个叉。元素多的话,会自动取一个元素作为新的起点,向上下延伸。正向遍历元素,从小到大取。反向取元素,直接更改compareTo方法即可。例如,年龄从大到小排列。

    排序方式:

1. 让元素自身具备比较性,元素要实现Comparable接口,覆盖compareTo()方法,这种方式也称为元素的自然顺序,或者叫默认顺序。许多java已有类都已经实现该接口,例如,String、Integer等。代码举例,

public int compareTo(Student st)//先比较年龄再比较姓名

{

       if(this.age>st.age)

              return 1;

       if(this.age==st.age)

       {

              return this.name.compareTo(st.name);//字符串排序比较

       }

       return -1;

}

2. 当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时需要让集合自身具备比较性。在集合初始化时,就有了比较方式。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。定义一个比较器,实现Comparator接口,覆盖compare()方法(返回值是正数、负数和0,不一定是1或-1)。代码举例,

class MyCompare implements Comparator<Student>//比较器

{

       public int compare(Student s1,Student s2)

       {

              int num = s1.getName().compareTo(s2.getName());//按照姓名排列,年龄为次要。

              if(num==0)

                     return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));

              return num;

       }

}

当两种排序都存在时,以比较器为主。比较器更加常用。做项目时,一定要留有接口。

注意:主要条件和次要条件搭配使用,防止元素丢失。涉及到对元素的操作都与排序有关。

 

泛型

当集合中存入不同类型数据时,某些操作会因为类型不同引发异常,例如,Integer类和String类无法同时输出长度。

JDK1.5后出现的新特性,用于解决安全问题,是一种安全机制。让集合只能装一种类型的对象,如果有其他类对象进入,编译不通过。

泛型格式,通过< >来定义只能操作的引用数据类型,例如,ArrayList<String> ss = new ArrayList<String>();定义一个ArrayList容器,元素都是String类型。

好处:1. 将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题,让运行期间问题减少,更加安全。

2. 避免了强制装换的繁琐,强制客观的限定类型。

在使用java提供的对象时,何时使用泛型?在集合框架中很常见,只要见到< >就要定义泛型。其实< >用来接受数据类型的。当使用集合时,将集合中要存储的数据类型(引用数据类型)作为参数传递到< >中即可,类似函数中传递参数。

HashSet集合框架不能使用泛型,因为内部的equals仍然使用Object作为参数,而Object类没有泛型。

定义一个新类,需要在内部添加hashCode()、equals()、toString()并实现Comparable接口复写compareTo()方法,以便于适应各种集合框架。

 

泛型扩展

当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型类完成扩展。例如:

class Demo<T>//内部函数只能操作T类型。

{

       public void show(T t)

       {

              System.out.println("show = "+t);

       }

}

泛型类,类的内部无需再明确操作类型,无需转换动作,但是只能操作某一引用类型的数据。泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。类定义后,创建对象只操作一种数据。

 

泛型方法,为了让不同方法可以操作不同类型,而且类型还不确定,可以将泛型定义在方法上。例如,

class Demo_2

{

       public<T> void show(T t)//T只在此函数有效。

       {

              System.out.println("show = "+t);

       }

}

也可以将泛型类和泛型方法混合使用,泛型方法走自己的类型,随意,例如,

class Demo_3<T>

{

       public void show(T t)

       {

              System.out.println("show = "+t);

       }

       public<E> void print(E e)

       {

              System.out.println("print = "+e);

       }

}

 

泛型静态方法:静态方法不可以访问类上定义的泛型;如果静态方法操作的引用数据类型不确定,可以将泛型定义在静态方法上。例如,

public static<R> void fun(R r)

{

       System.out.println("fun = "+r);

}

注意泛型的位置:返回值类型的前面,修饰符的后面。泛型类的位置是,类名后面。

注意泛型的位置:class Utils<QQ>;interface Inter<T>;public<T> void show(T t);public static<R> void fun(R r);ArrayList<String> arr = new ArrayList<String>();

 

泛型接口:两种方式:

子类已经确定操作类型,例如:

class Demo_1 implements Inter<String>

{

       public void show(String s)

       {

              System.out.println("show = "+s);

       }

       public<E> void print(E e)//依然可以有其他类型

       {

              System.out.println("print = "+e);

       }

}

子类不能确定操作类型,继续使用泛型类,例如,

class Demo_4<T> implements Inter<T>

{

       public void show(T t)

       {

              System.out.println("show = "+t);

       }

       public<E> void print(E e)

       {

              System.out.println("print = "+e);

       }

}

 

泛型的高级应用:限定

当操作类型不明确时,可以使用通配符(站位符)来表示。例如,

public static void printArray(ArrayList<?> ar)

{

       Iterator<?> it = ar.iterator();

       while(it.hasNext())

       {

              System.out.println(it.next());

       }

}

不用<?>占位符也可以,只是不严谨。将?换成泛型T也可以,T可以代表具体类型,在方法内部接收数据。例如,T t = it.next();。<?>不能在方法内接受数据类型。

使用泛型可以接受不同的对象,但是对象的特有方法不能再使用,例如,length();只要是Object类的方法都能用,例如,toString()。

子父类数据需要同时操作时,使用泛型限定,例如

public static void printArray(ArrayList<? extends Person> ar)//打印Person和其子类。

{

       Iterator<? extends Person> it = ar.iterator();

       while(it.hasNext())

       {

              System.out.println(it.next().getName());//Person有getName()方法可以用。

       }

}

?,通配符,也可以理解为站位符,意为必须具备泛型,但具体泛型不知道。1.5以后都要写,用于站位。

 

泛型的限定:

?extends E:可以接受E类型或者其子类型,上限。例如,

?Super E:可以接受E类型及其父类型,下限。许多集合不可以有下限,例如,ArrayList。

Comparator比较器可以传入父类,使得子类也可以使用比较器。但比较方法必须是父类的。利用了多态的特性。例如,

class Com implements Comparator<Person>//父类的比较器

{

       public int compare(Person p1,Person p2)

       {

              return p1.getName().compareTo(p2.getName());

       }

}

 

 

      ----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值