黑马程序员————集合框架2(day15)

----------------------ASP.Net+Android+IOS开发----------------------期待与您交流!

 

 

 

集合框架2

l  TreeSet

l  TreeSet存储自定义对象

l  二叉树

l  实现Comparator方式排序

l  泛型概述

l  泛型使用

l  泛型类

l  泛型方法

l  泛型接口

l  泛型限定

 

 

TreeSet

Set:无序,不可以重复元素。

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

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

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

 

         |--TreeSet:可以对Set集合中的元素进行排序。

                                    底层数据结构是二叉树。

                                     保证元素唯一性的依据:

                                     compareTo方法return 0.

 

                                     TreeSet排序的第一种方式:让元素自身具备比较性。

                                    元素需要实现Comparable接口,覆盖compareTo方法。

                                    也种方式也成为元素的自然顺序,或者叫做默认顺序。

 

                                     TreeSet的第二种排序方式。

                                    当元素自身不具备比较性时,或者具备的比较性不是所需要的。

                                    这时就需要让集合自身具备比较性。

                                    在集合初始化时,就有了比较方式。

 

TreeSet为使用树来进行存储的Set接口提供了一个工具,对象按升序存储。访问和检索是很快的。在存储了大量的需要进行快速检索的排序信息的情况下,TreeSet是一个很好的选择。

 

示例:

import java.util.*;

class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add("c");
		ts.add("b");
		ts.add("d");
		ts.add("a");
		ts.add("g");
		ts.add("e");
		ts.add("f");

		System.out.println(ts);
	}
}


 

运行结果:[a, b, c, d, e, f, g]

可以发现,因为TreeSet按树存储其元素,因此它们被按照排序次序自动排序。

 

 

TreeSet存储自定义对象

需求:

往TreeSet集合中存储自定义对象学生,想按照学生的年龄进行排序。

 

示例:

import java.util.*;

class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add(new Student("zhangsan01", 20));
		ts.add(new Student("zhangsan02", 21));
		ts.add(new Student("zhangsan03", 22));
		ts.add(new Student("zhangsan04", 23));

		Iterator it = ts.iterator();
		while (it.hasNext()) {
			Student stu = (Student) it.next();// 因为迭代器返回的是Obejct类型,所以这里要转型为Student类型,不然输出就是哈希码值
			System.out.println(stu.getName() + "..." + stu.getAge());
		}
	}
}

class Student {
	private String name;
	private int age;

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}


运行结果:

运行后会抛出ClassCastException异常,类型转换异常。Student cannot be cast to java.lang.Comparable,Student不能转换成java.lang.Comparable。在第9行出的问题,那么我们就把第9行到第11行全注释了,只添加一个学生,那么就会输出zhangsan01...20,但是一旦添加两个或两个以上就会报错,这是为什么呢?因为我们是往TreeSet集合里存对象,它是帮我们排序的,但我们并没有把排序的方式告诉它,它就没法帮我们排序,所以TreeSet集合的要求是往里存的对象必须具备比较性。那么怎么具备比较性呢?只要实现Comparable接口并且覆写里的CompareTo()方法就行了。

 

改过之后代码如下:

import java.util.*;

class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add(new Student("zhangsan01", 20));
		ts.add(new Student("zhangsan02", 20));
		ts.add(new Student("zhangsan03", 22));
		ts.add(new Student("zhangsan04", 23));

		Iterator it = ts.iterator();
		while (it.hasNext()) {
			Student stu = (Student) it.next();// 因为迭代器返回的是Obejct类型,所以这里要转型为Student类型,不然输出就是哈希码值
			System.out.println(stu.getName() + "..." + stu.getAge());
		}
	}
}

class Student implements Comparable {//该接口墙纸让学生具备比较性
	private String name;
	private int age;

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	// 覆写compareTo()方法,按照我们的要求进行年龄排序
	public int compareTo(Object obj) {// 因为我们不知道传什么类型对象,所以这里用Object
		if (!(obj instanceof Student))
			throw new RuntimeException("不是学生对象");
		Student s = (Student) obj;// 必须得转为Student类型

		if (this.age > s.age)
			return 1;// 此对象this大于指定对象s(传入的对象)
		if (this.age == s.age)// 只要年龄相同并且姓名也相同才视为同一个人
			// return 0;//此对象this等于指定对象s(传入的对象),但是这里不能这么写,因为如果年龄相同它就不会再添加了
			return this.name.compareTo(s.name);// 对姓名也进行排序,Java里String类默认实现了Comparable接口,所以String类里的compareTo()方法是按字典顺序比较两个字符串,它返回的也是1,-1和0
		return -1;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}


 

运行结果:zhangsan01...20

zhangsan02...20

zhangsan03...22

zhangsan04...23

这样写年龄相同姓名不同也添加到TreeSet集合中了,年龄和姓名都相同就视为同一人所以就不会被添加到TreeSet集合中。

记住,排序时,当主要条件相同时,一定判断一下次要条件。

 

 

二叉树

当程序执行到ts.add(new Student(“zhangsan01”, 22))时,这时会存入到TreeSet中,当程序执行到ts.add(new Student(“zhangsan02”, 20))时,这时会调用自己的compareTo()方法,把22传进来进行比较,这时TreeSet会像上图一样的数据结构,这里比较的是年龄,按照compareTo()方法里规定的大的返回1,小的返回-1,相同返回0,小的在左边,大的在右边,排序会从小到大进行排序。

 

小技巧:

class Demo implements Comparable{
	public int compareTo(Object obj){
		return 1;//怎么存入就怎么排序
		//return -1;//倒序
		//return 0;//只有第一个存入的值
	}
}


 

按照二叉树的结构,返回1,代表大的,在右边,从小到大排序,所以就是怎么存怎么取;返回-1,代表小的,在左边,从小到大排序,所以就是倒序;返回0,代表相同,所以只存入了第一个添加进去的值。

 

 

实现Comparator方式排序

当元素自身不具备比较性,或者具备的比较性不是所需要的,这时需要让容器自身具备比较性,定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

当两种排序都存在时,以比较器为主。

定义一个类,实现Comparator接口,覆盖compare方法。

 

示例:

import java.util.*;

class Student1 implements Comparable {// 该接口强制让学生具备比较性。
	private String name;
	private int age;

	Student1(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public int compareTo(Object obj) {
		if (!(obj instanceof Student1))
			throw new RuntimeException("不是学生对象");
		Student1 s = (Student1) obj;

		if (this.age > s.age)
			return 1;
		if (this.age == s.age) {
			return this.name.compareTo(s.name);
		}
		return -1;
	}

	public String getName() {
		return name;

	}

	public int getAge() {
		return age;
	}
}

class TreeSetDemo2 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet(new MyCompare());// 传入接口对象让TreeSet一初始化就有比较器

		ts.add(new Student1("lisi02", 22));
		ts.add(new Student1("lisi02", 21));
		ts.add(new Student1("lisi007", 20));
		ts.add(new Student1("lisi09", 19));
		ts.add(new Student1("lisi06", 18));
		ts.add(new Student1("lisi06", 18));
		ts.add(new Student1("lisi007", 29));
		// ts.add(new Student("lisi007",20));
		// ts.add(new Student("lisi01",40));

		Iterator it = ts.iterator();
		while (it.hasNext()) {
			Student1 stu = (Student1) it.next();
			System.out.println(stu.getName() + "..." + stu.getAge());
		}
	}
}

// 定义比较器MyCompare必须实现Comparator类覆写compare()方法
class MyCompare implements Comparator {
	public int compare(Object o1, Object o2) {
		Student1 s1 = (Student1) o1;
		Student1 s2 = (Student1) o2;

		int num = s1.getName().compareTo(s2.getName());
		if (num == 0) {
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
			/*
			 * if(s1.getAge()>s2.getAge()) return 1;
			 * if(s1.getAge()==s2.getAge()) return 0; return -1;
			 */
		}
		return num;
	}
}


 

泛型概述

泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。

 

好处:

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

2.  避免了强制转换麻烦。

 

泛型格式:通过<>来定义要操作的引用数据类型。

 

在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见,只要见到<>就要定义泛型。其实<> 就是用来接收类型的,当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。

 

示例:

import java.util.*;

public class GenericDemo {
	public static void main(String[] args) {

		ArrayList<String> al = new ArrayList<String>();// 往ArrayList容器里存的都是String类型的

		al.add("abc01");
		al.add("abc0991");
		al.add("abc014");

		// al.add(4);//al.add(new Integer(4));//因为泛型里规定的是String类型的,所以这里不能存入int类型

		Iterator<String> it = al.iterator();
		while (it.hasNext()) {
			String s = it.next();
			System.out.println(s + "长度为:" + s.length());
		}
	}
}


 

泛型使用

示例:

import java.util.*;

class GenericDemo2 {
	public static void main(String[] args) {
		TreeSet<String> ts = new TreeSet<String>(new LenComparator());// 初始化TreeSet时就有LenComparator比较器

		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("aaa");
		ts.add("z");
		ts.add("hahaha");

		Iterator<String> it = ts.iterator();

		while (it.hasNext()) {
			String s = it.next();
			System.out.println(s);
		}
	}
}

class LenComparator implements Comparator<String> {// 因为已经知道传入的是String类型,所以这里就可以用泛型明确为String类型
	public int compare(String o1, String o2) {
		int num = new Integer(o1.length()).compareTo(new Integer(o2.length()));//想要倒序,只要o1和o2换个位置即可

		if (num == 0)
			return o1.compareTo(o2);//想要倒序,只要o1和o2换个位置即可
		return num;
	}
}


 

泛型类

示例:

/*class Tool {
 private Worker w;

 public void setWorker(Worker w) {
 this.w = w;
 }

 public Worker getWorker() {
 return w;
 }
 }*/

class Worker {
}

class Student2 {
}

// 泛型前做法。
class Tool {
	private Object obj;

	public void setObject(Object obj) {
		this.obj = obj;
	}

	public Object getObject() {
		return obj;
	}
}

// 泛型类。
/*
 * 什么时候定义泛型类? 当类中要操作的引用数据类型不确定的时候, 早期定义Object来完成扩展。 现在定义泛型来完成扩展。
 */
class Utils<QQ> {
	private QQ q;

	public void setObject(QQ q) {
		this.q = q;
	}

	public QQ getObject() {
		return q;
	}
}

class GenericDemo3 {
	public static void main(String[] args) {
		Utils<Worker> u = new Utils<Worker>();
		u.setObject(new Worker());
		Worker w = u.getObject();
		/*
		 * Tool t = new Tool(); t.setObject(new Student()); Worker
		 * w=(Worker)t.getObject();
		 */
	}
}


 

泛型方法

示例:

/*
 class Demo<T>
 {
 public void show(T t)
 {
 System.out.println("show:"+t);
 }
 public void print(T t)
 {
 System.out.println("show:"+t);
 }

 }
 */

//泛型类定义的泛型,在整个类中有效。如果被方法使用,
//那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
//
//为了让不同方法可以操作不同类型,而且类型还不确定。
//那么可以将泛型定义在方法上。

/*
 特殊之处:
 静态方法不可以访问类上定义的泛型。
 如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

 */

class Demo<T> {
	public void show(T t) {
		System.out.println("show:" + t);
	}

	public <Q> void print(Q q) {
		System.out.println("print:" + q);
	}

	public static <W> void method(W t) {
		System.out.println("method:" + t);
	}
}

class GenericDemo4 {
	public static void main(String[] args) {
		Demo<String> d = new Demo<String>();
		d.show("haha");
		// d.show(4);
		d.print(5);
		d.print("hehe");

		Demo.method("hahahahha");

		/*
		 * Demo d = new Demo(); d.show("haha"); d.show(new Integer(4));
		 * d.print("heihei");
		 */
		/*
		 * Demo<Integer> d = new Demo<Integer>();
		 * 
		 * d.show(new Integer(4)); d.print("hah");
		 * 
		 * Demo<String> d1 = new Demo<String>(); d1.print("haha"); d1.show(5);
		 */
	}
}


 

运行结果:show:haha

print:5

print:hehe

method:hahahahha

 

 

泛型接口

示例:

//泛型定义在接口上。
interface Inter<T> {
	void show(T t);
}

/*
 * class InterImpl implements Inter<String> { public void show(String t) {
 * System.out.println("show :"+t); } }
 */

class InterImpl<T> implements Inter<T> {
	public void show(T t) {
		System.out.println("show :" + t);
	}
}

class GenericDemo5 {
	public static void main(String[] args) {

		InterImpl<Integer> i = new InterImpl<Integer>();
		i.show(4);
		// InterImpl i = new InterImpl();
		// i.show("haha");
	}
}


 

运行结果:show :4

 

 

泛型限定

示例:

import java.util.*;

class GenericDemo6 {
	public static void main(String[] args) {
		/*
		 * ArrayList<String> al = new ArrayList<String>();
		 * 
		 * al.add("abc1"); al.add("abc2"); al.add("abc3");
		 * 
		 * ArrayList<Integer> al1 = new ArrayList<Integer>(); al1.add(4);
		 * al1.add(7); al1.add(1);
		 * 
		 * printColl(al); printColl(al1);
		 */

		ArrayList<Person> al = new ArrayList<Person>();
		al.add(new Person("abc1"));
		al.add(new Person("abc2"));
		al.add(new Person("abc3"));
		// printColl(al);

		ArrayList<Student3> al1 = new ArrayList<Student3>();
		al1.add(new Student3("abc--1"));
		al1.add(new Student3("abc--2"));
		al1.add(new Student3("abc--3"));
		printColl(al1); // ArrayList<? extends Person> al = new
						// ArrayList<Student>();error

	}

	public static void printColl(Collection<? extends Person> al) {
		Iterator<? extends Person> it = al.iterator();

		while (it.hasNext()) {
			System.out.println(it.next().getName());
		}
	}
	/*
	 * public static void printColl(ArrayList<?> al)//ArrayList al = new
	 * ArrayList<Integer>();error { Iterator<?> it = al.iterator();
	 * 
	 * 
	 * while(it.hasNext()) { System.out.println(it.next().toString()); } }
	 */
}

class Person {
	private String name;

	Person(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
}

class Student3 extends Person {
	Student3(String name) {
		super(name);
	}
}

/*
 * 
 * class Student implements Comparable<Person>//<? super E> { public int
 * compareTo(Person s) { this.getName() } }
 */
class Comp implements Comparator<Person> {
	public int compare(Person s1, Person s2) {

		// Person s1 = new Student("abc1");
		return s1.getName().compareTo(s2.getName());
	}
}


 

运行结果:abc--1

abc--2

abc--3

 

? 通配符。也可以理解为占位符。

泛型的限定。

? extends E:可以接收E类型或者E的子类型。上限。

? super E:可以接收E类型或者E的父类型。下限

 

 

 

----------------------ASP.Net+Android+IOS开发----------------------期待与您交流!

详情请查看:http://edu.csdn.net

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值