day15TreeSet,二叉树原理,比较器,泛型,自定义泛型

/*
TreeSet,二叉树原理,比较器,泛型,自定义泛型
*/


/*
|--Set:元素是无序的(存入和取出的顺序不一致),元素不可重复
	|--HashSet:底层数据结构是哈希表。线程是非同步的。
		是如何保证元素的唯一性的呢?(依据)
		判断是通过元素的两个方法,先判断hashCode,如果相同,再判断equals来完成
		如果元素Hashcode一样,才会判断equals是否为真
		如果元素的Hashcode不同,不会调用equals.

		注意,对于判断元素是否存在,以及删除等操作,依赖hashCode和equals方法来完成

	|--TreeSet:可以对Set集合中的元素进行排序。
				底层数据结构是二叉树。
				保证元素唯一性的依据
				compareTo方法,相同return 0 ;
				
				二叉树存:大的在右下,小的在左下。
				取值:先取小的,再取大的
					
				排序技巧:当compareTo()总是返回1:正序。就是和存入顺序一样了。
								返回-1,逆序。

				TreeSet排序的第一种方式。让元素自身具备可比性
				元素需要实现Comparable接口,覆盖compareTo方法
				这种方式就是元素的自然顺序。

				TreeSet的第二种排序方式。比较器
				当元素自身不具备比较性时,或者具备的比较性不是所需要的
				这时就需要让集合具备比较性。
				定义一个类,实现Comparator接口,覆盖compare方法。
				在集合初始化时,传入这个类的对象,就有了比较方式。
				TreeSet ts = new TreeSet(new Mycompare());

Set集合的功能和Collect是一致的,
哈希表存对象。
先比较哈希值,如果相同,再比较对象equals。


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

comparable compareTo , comparator compare
记住。排序时,当主要条件相同时,按照次要条件再排序。
*/
import java.util.*;

class  TreeSetDemo
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet();
		ts.add(new Student("lisi02",22));//为什么存一个没事?存二个就出错?
										//向Tree里面存对象,是要排序的,必须要有比较性,类的自然顺序。
		ts.add(new Student("lisi007",20));
		ts.add(new Student("lisi09",19));
		ts.add(new Student("lisi01",40));//如果年龄相同,那么存不进去?判断唯一性。

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

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

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

	public int compareTo(Object obj)//覆盖接口方法
	{
		if(!(obj instanceof Student))
			throw new RuntimeException("不是学生对象");
			
		Student s = (Student)obj;
		System.out.println(this.name+".compareto."+s.name);
		if(this.age>s.age)
			return 1;
		if(this.age == s.age)
			//return 0;当年龄相同,再判断姓名。主副条件
		{
			return this.name.compareTo(s.name);//String也实现了此接口
		}
		return -1;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}
}

import java.util.*;
/*
TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的
这时就需要让集合自身具备比较性。
构造函数:在集合初始化时,就有了比较方式。

当二种都存在时,以比较器为主(好)。
比较器类:定义一个类,实现Comparator接口,覆盖compare方法。

我们发现,当我们定义一个学生类时,要有自己的hashCode,equals,compareTo方法,
当然还有toString方法。
*/

class  TreeSetDemo2
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet(new Mycompare());//以比较器为主
		ts.add(new Student("lisi02",22));//没有比较器时,为什么存一个没事?存二个就出错?
										//向Tree里面存对象,是要排序的,必须要有比较性,类的自然顺序。
		ts.add(new Student("lisi007",20));
		ts.add(new Student("lisi09",19));
		ts.add(new Student("lisi01",40));//如果年龄相同,那么存不进去?Set是无序,元素不重复。

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

class Mycompare implements Comparator//比较器方式
{
	public int compare(Object o1,Object o2)
	{
		Student s1 = (Student)o1;
		Student s2 = (Student)o2;

		int num =  s1.getName().compareTo(s2.getName());//按名字排序
		if (num==0)//名字相同,再比较年龄
		{
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		}

		return num;
	}
}

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

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

	public int compareTo(Object obj)
	{
		if(!(obj instanceof Student))
		throw new RuntimeException("不是学生对象");
			
		Student s = (Student)obj;
		//System.out.println(this.name+".compareto."+s.name);
		if(this.age>s.age)
			return 1;
		if(this.age == s.age)
			//return 0;当年龄相同,再判断姓名。
		{
			return this.name.compareTo(s.name);//String 也实现了此接口
		}
		return -1;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}
}

/*
练习:按照字符串长度排序

字符串本身具备比较性。但这个排序方式不是我们想要的
*/
import java.util.*;
class  TreeSetTest
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet(new  StrLenComparator());
		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("z");
		ts.add("hahaha");

		Iterator it = ts.iterator();
		while (it.hasNext())
		{
			System.out.println(it.next());
		}
	}
}

class StrLenComparator implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		String s1 = (String)o1;
		String s2 = (String)o2;

		/*
		if(s1.length()>s2.length())
			return 1;
		if(s1.length()==s2.length())
			return 0;
			
		return -1;
			*///为什么不相接用int比较?那不是对象,没有compareTo方法。
		int num = new  Integer(s.length()).compareTo(new Integer(s2.length()));
		if(num ==0)
		{
			return s1.compareTo(s2);
		}
		return num;
	}
}

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

好处:
1.把运行时出现的ClassCastException问题放到编译时.
让程序员解决问题,减少安全问题。

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

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

在使用java提供的对象时,什么时候写泛型呢?
在集合框架中很常见。
只要有<>就要定义泛型。
其实<>就是用来接受类型的。

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

类似数组一样。
装入时候明确要装入的<类型>。
ArrayList<String> al = new ArrayList<String>();
*/
class  GenericDemo
{
	public static void main(String[] args) 
	{
		ArrayList<String> al = new ArrayList<String>();
		al.add("abc01");
		al.add("abc0001");
		al.add("abc014");
		//al.add(4);问题所在。编译可以通过,运行出问题。
		Iterator<String> it = al.iterator();
		while(it.hasNext())
		{
			String s = it.next();//2避免了强制转换的麻烦。
			System.out.println(s+":"+s.length());
		}
	}
}

//------下面是泛型一个例子。字符串长度排序。
import java.util.*;

class  GenericDemo2
{
	public static void main(String[] args) 
	{
		TreeSet<String> ts = new TreeSet<String>(new StrLenComparator());
		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("z");
		ts.add("hahaha");

		Iterator<String> it = ts.iterator();
		while (it.hasNext())
		{
			System.out.println(it.next());
		}
	}
}

class StrLenComparator implements Comparator<String>
{
	public int compare(String o1,String o2)//当类上加上<String>,此处不是Object了
	{
		int num = new Integer(o1.length()).compareTo(new  Integer(o2.length()));
		
		if(num == 0)
		{
			return o1.compareTo(o2);
		}
		return num;
	}
}

/*
自定义泛型类
我们能不能在自己定义的类中使用泛型来完成程序设计呢?
什么时候使用泛型类:
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。现在定义泛型来完成扩展。

只能是引用的,基本数据类型定义不了,
基本数据类型比如说char类型,
本来就是char了,就不能再用泛型规范了。

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

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

	public Worker getWorker()
	{
		return w;
	}
}第一次
*/
/*
class Worker
{

}

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

	public Object getObject()
	{
		return obj;
	}
}第二次


class Student
{

}
class GenericDemo3 
{
	public static void main(String[] args) 
	{
		Tool t = new Tool();
		t.setObject(new Student());
		//不小心传了学生,编译通过,运行出错。
		//这时自己明确传什么,拿什么。
		Worker w = (Worker)t.getObject();
	}
}
*/
//以上是早期做法,是可以的,得有强转。
//对象都是后过来的,泛型之前用object
//避免一个类要一个工具类操作

//我要操作对象,什么类型不确定。
//由对方来指定要操作什么类型的对象

class Utils<QQ>//泛型类
{
	private QQ q;
	public void setObject(QQ q)
	{
		this.q = q;
	}
	public QQ getObject()
	{
		return q;
	}
}

class Student
{

}
class GenericDemo3
{
	public static void main(String[] args) 
	{
		/*
		Tool t = new Tool();
		t.setObject(new Student());
		//不小心传了学生,编译通过,运行出错。
		//这时自己明确传什么,拿什么。
		Worker w = (Worker)t.getObject();
		*/
		Utils<Worker> u = new Utils<Worker>();//泛型
		u.setObject(new Worker());
		Worker w = u.getObject();//可以不用强转,传入其他的就失败。

	}
}

/*泛型方法*/
class  GenericDemo4
{
	public static void main(String[] args) 
	{
		/*
		Demo<Integer> d = new Demo<Integer>();
		d.show(new Integer(4));
		d.print(9);
		定义在类上时
		*/
		Demo d = new Demo();
		d.show("haah");
		d.show(new Integer(4));
		d.print("heihei");
	}
}
class Demo
{
	public <T> void show(T t)//<T>定义在方法上,<T>只在方法中有效
	{
		System.out.println("show:"+t);
	}
	public <Q> void print(Q q)//这里写<T>也可以
	{
		System.out.println("print:"+q);
	}
}

/*
class Demo<T>//泛型定义在类上
{
	public void show(T t)
	{
		System.out.println("show:"+t);
	}
	public void print(T t)
	{
		System.out.println("print:"+t);
	}
	//以前要明确操作类型,现在可以这样写,传什么都行。

	//泛型类的局限性:当new一个对象时,已经定义类型了。
	//Demo<Integer> d = new Demo<Integer>();
	//泛型类定义的泛型在整个类中有效。如果被方法使用,
	//那么如果泛型类的对象已经明确操作的具体类型后,所
	//有要操作的类型就已经固定了。

	//为了让不同方法可以操作不同类型,而且类型还不确定。
	//那么可以将泛型定义在方法上。public <T> void print(Q q)

	泛型类和方法可以同时定义。
}
*/
/*特殊之处:
当类有静态方法时,不可以访问在类上定义的泛型。
如果静态方法操作的引用数据类型不确定,
可以将泛型定义在方法上。因为静态方法先加载。
public static <W> void method(W w)
{//注意泛型方法书写格式,<W>在void前,返回类型前。
	System.out.println("method" + w);
}
*/
/*
泛型接口:如果类不能确定自己要传什么,也可以定义泛型
*/
interface Inter<T>
{
	void show(T t);
}
/*
class InterImpl implements Inter<String> 
{
	public void show(String s)
	{
		System.out.println("show"+s);
	} 
}//第一种
*/
//后来我自己也不知道自己要传什么类型,
//子类也不知道,由调用者来指定
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 i = new InterImpl();
		//i.show("haha");
		InterImpl<Integer> i = new InterImpl<Integer>();
		i.show(4);
		//由调用者自己指定Integer
	}
}

/*import java.util.*;
<T>具体类型。<?>占位符,通配符。
<?>不明确类型,iterator时不能打印it.next().length().
ArrayList<Person> al = new ArrayList<Student>();
这是不允许的。左右二边要一致。泛型没有继承关系。

泛型的限定:
1.?extends E:可以接收E类型或者E的子类型。上限
2.?super E:可以接收E类型或者E的父类型。下限。
*/
class  GenericDemo6
{
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值