今日内容:泛型,HashSet,TreeSet
Collection接口只定义了增,删,判断,遍历方法没有定义改查方法!
泛型类
class 类名<T,E,Y>//泛型类创建的时候可以不确定,等到创建对象的时候在确定,泛型可以为多个
import java.util.ArrayList;
class Person {
}
class Student extends Person {
}
class Teacher extends Person {
}
//泛型通配符,占位符,限定界限,注意泛型没有多态,不能前后不一致
public class Demo1 {
public static void main(String[] args) {
ArrayList<Person> l1=new ArrayList<>();
l1.add(new Person());
l1.add(new Student());//多态
l1.add(new Teacher());//多态
ArrayList<Student> l2=new ArrayList<>();
ArrayList<Teacher> l3=new ArrayList<>();
print(l1);
print(l2);
print(l3);
}
public static void print(ArrayList<? extends Person> list){//如果此处是extendsPerson则上面三个print都可以
// public static void print(ArrayList<? super Student> list){//如果此处是supersPerson则Teacher用不了
}
}
import java.util.Comparator;
import java.util.TreeSet;
//comparator后面的泛型在实现的时候要具体指出是哪一个,因为是Person2对象的比较,所以此处写Person2
/*什么时候用comparable什么时候用Comparator?二者其实作用相同,comparator是comparable的子接口,
comparator是创建TreeSet是的构造器中带的方法,此时需要用comparator,还有就是comparable中已经写好了按照自然顺序/字典顺序排序
不能随便更改,不然就要改源码,比较麻烦,适合可以直接适用自然排序的数据类型使用*/
//class Person2 implements Comparator<Person2> {
// int age;
// String name;
// public Person2(){} //一定要写一个无参构造函数,方便下面用这个类创建对象,否则就只能带参数创建对象,比较麻烦
// public Person2(String name,int age){
// this.name=name;
// this.age=age;
// }
// @Override
// public String toString() {
// return name+"---"+age;
// }
// @Override
// public int compare(Person2 p1, Person2 p2) {
// int num=p1.age-p2.age;
// if(num==0){
// return p1.name.compareTo(p2.name);
// }
// return num;
// }
//}
//public class Demo3 { //TreeSet
// public static void main(String[] args) {
/*TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
下面使用了匿名内部类,父接口创建实现类对象,comparator不能直接创建对象,要使用他的实现类,所以直接把他的实现类
Person2中的compare方法重写一遍,这样就相当于创建了comparator对象,或者直接像下面那样创建Person2的对象*/
// TreeSet<Person2> ts=new TreeSet<>(new Comparator<Person2>(){
// public int compare(Person2 p1, Person2 p2) {
// int num=p1.age-p2.age;
// if(num==0){
// return p1.name.compareTo(p2.name);
// }
// return num;
// };
// });
//
// TreeSet<Person2>ts=new TreeSet<>(new Person2());//如果上面没写无参构造函数那么创建对象就只能写成new Person2("",2)
// ts.add(new Person2("zhangsan",20));
// ts.add(new Person2("lisi",21));
// ts.add(new Person2("wangwu",20));
// ts.add(new Person2("zhaoliu",24));
// ts.add(new Person2("heqi",20));
//
// for(Object obj:ts){
// Person2 p=(Person2)obj;//Object是父类,但是name和age是子类特有的,所以要向下转型
// System.out.println(p);
// }
// }
//}
//下面用comparable方法,很简便
class Person3 implements Comparable<Person3>{
int age;
String name;
public Person3(){}
public Person3(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return name+"-----"+age;
}
@Override
public int compareTo(Person3 p) {
int num=this.age-p.age;
if(num==0){
return this.name.compareTo(p.name);//此处调用的是String类中的compareTo方法
}
return num;
}
}
public class Demo3{
public static void main(String[] args) {
TreeSet<Person3> x=new TreeSet<>();
x.add(new Person3("zhangsan",20));
x.add(new Person3("lisi",21));
x.add(new Person3("wangwu",20));
x.add(new Person3("zhaoliu",24));
x.add(new Person3("heqi",20));
for(Object obj:x){
Person3 y=(Person3)obj;//Object是父类,但是name和age是子类特有的,所以要向下转型
System.out.println(y);
}
}
}
HashSet
import java.util.HashSet;
import java.util.Set;
class Person{
int age;
String name;
public Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "姓名:"+name+"---"+"年龄"+age;
}
// @Override
// public int hashCode() {
// System.out.println("----");//先判断了hashcode方法
// return 100;
// }
///*先执行一次hashcode,直接放进去,然后在执行一次hashcode,发现有相同的,执行equals方法,判断是不同对象,存进去,
//然后再计算hashcode,相同,执行equals方法2次,与前面已经存进去的两个元素相比较,发现不是同一元素,存进去,循环直到
//所有元素都执行过了为止*/
// @Override
// public boolean equals(Object obj) {
// System.out.println("****");
// return super.equals(obj);
// }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)//判断地址值,相同说明是堆内存中的同一个元素
return true;
if (obj == null)//对象才能调用方法,空对象不能调用方法,所以如果obj是null的话二者就不相等
return false;
if (getClass() != obj.getClass())//!(obj instanceof Person)
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class Demo2 {
public static void main(String[] args) {
// set方法
Set<Person> a = new HashSet<>();//泛型
a.add(new Person("张三",20));
a.add(new Person("张四",21));
a.add(new Person("张五",22));
a.add(new Person("张四",21));
a.add(new Person("张三",20));
for (Person per : a) {
System.out.println(per);
}
}
}
TreeSet
TreeSet集合中保存对象的时候:
- 如果多个不同类型的对象他们之间没有继承关系,这是是不能同时存储到同一个TreeSet集合中的
- 如果多个不同类型的对象,他们之间有继承关系,并且父类已经实现了Comparable接口,这时这些父类对象和子类对象都可以在TreeSet集合中保存。
import java.util.TreeSet;
/*什么时候用comparable什么时候用Comparator?二者其实作用相同,comparator是comparable的子接口,
comparator是创建TreeSet时的构造器中带的方法,此时需要用comparator,还有就是comparable中已经写好了按照
自然顺序/字典顺序排序不能随便更改,不然就要改源码,比较麻烦,适合可以直接适用自然排序的数据类型使用*/
//comparator后面的泛型在实现的时候要具体指出是哪一个,因为是Person2对象的比较,所以此处写Person2
//class Person2 implements Comparator<Person2> {
// int age;
// String name;
// public Person2(){} //一定要写一个无参构造函数,方便下面用这个类创建对象,否则就只能带参数创建对象,比较麻烦
// public Person2(String name,int age){
// this.name=name;
// this.age=age;
// }
// @Override
// public String toString() {
// return name+"---"+age;
// }
// @Override
// public int compare(Person2 p1, Person2 p2) {
// int num=p1.age-p2.age;
// if(num==0){
// return p1.name.compareTo(p2.name);
// }
// return num;
// }
//}
//public class Demo3 { //TreeSet
// public static void main(String[] args) {
/*TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
下面使用了匿名内部类,父接口创建实现类对象,comparator不能直接创建对象,要使用他的实现类,所以直接把他的实现类
Person2中的compare方法重写一遍,这样就相当于创建了comparator对象,或者直接像下面那样创建Person2的对象*/
// TreeSet<Person2> ts=new TreeSet<>(new Comparator<Person2>(){
// public int compare(Person2 p1, Person2 p2) {
// int num=p1.age-p2.age;
// if(num==0){
// return p1.name.compareTo(p2.name);
// }
// return num;
// };
// });
//
// TreeSet<Person2>ts=new TreeSet<>(new Person2());//如果上面没写无参构造函数那么创建对象就只能写成new Person2("",2)
// ts.add(new Person2("zhangsan",20));
// ts.add(new Person2("lisi",21));
// ts.add(new Person2("wangwu",20));
// ts.add(new Person2("zhaoliu",24));
// ts.add(new Person2("heqi",20));
//
// for(Object obj:ts){
// Person2 p=(Person2)obj;//Object是父类,但是name和age是子类特有的,所以要向下转型
// System.out.println(p);
// }
// }
//}
//下面用comparable方法,很简便
class Person3 implements Comparable<Person3>{
int age;
String name;
public Person3(){}
public Person3(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return name+"-----"+age;
}
@Override
public int compareTo(Person3 p) {
int num=this.age-p.age;
if(num==0){
return this.name.compareTo(p.name);//此处调用的是String类中的compareTo方法
}
return num;
}
}
public class Demo3{
public static void main(String[] args) {
TreeSet<Person3> x=new TreeSet<>();
x.add(new Person3("zhangsan",20));
x.add(new Person3("lisi",21));
x.add(new Person3("wangwu",20));
x.add(new Person3("zhaoliu",24));
x.add(new Person3("heqi",20));
for(Object obj:x){
Person3 y=(Person3)obj;//Object是父类,但是name和age是子类特有的,所以要向下转型
System.out.println(y);
}
}
}
import java.util.ArrayList;
public class Demo4 {
public static void main(String[] args) {
//创建一个容器
ArrayList<String> list1=new ArrayList<>();//泛型
list1.add("a");
list1.add("b");
list1.add("c");
list1.add("d");
list1.add("e");
list1.add("a");
list1.add("b");
list1.add("c");
ArrayList<String> list2=quChong(list1);//调用方法,静态的,可以直接调用,非静态的话就创建对象
System.out.println(list2);
}
//创建一个用来去重的方法,注意要使用静态的,方便直接调用,因为主方法是静态的
public static ArrayList<String> quChong(ArrayList<String> a){
ArrayList<String> newList=new ArrayList<>();
for(Object obj:a){//foreach遍历集合
String x=(String)obj;//需要类型转换,foreach遍历默认的是Object类的
if(!newList.contains(x))
newList.add(x);
}
return newList;
}
}
import java.util.ArrayList;
public class Demo5 {
//把集合中的元素都转换成大写
public static void main(String[] args) {
ArrayList<String> a=new ArrayList<>();
a.add("aBc123");
a.add("cde");
a.add("ert");
a.add("seT");
a.add("vvv");
//调用方法
big(a);
}
public static void big(ArrayList<String> d){
for (String s:d) {
//String是一个存放在常量池里的,如果没有引用指向他,他就会变成垃圾被回收,所以不能写s.toUppercaser然后在下一行里输出
//这样输出的还是没有改变的s,应该直接输出,或者定义一个变量来接收他
String e=s.toUpperCase();
System.out.println(e);
}
}
}
public class Demo6 {
public static void main(String[] args) {
AA<String> a = new AA<>();
a.show("abc");
a.show01(123);// 确定变量具体类型为integer
AA.show02(new Demo6());
}
@Override
public String toString() {
return "hello";
}
}
// 泛型类,成员变量只能是T类型的,可以同时定义多个泛类型
class AA<T> {// class AA<T,Y,E>
T t;// 定义T类型的成员变量t
public void show(T t) {// 泛型方法,可以与泛型类的变量要求相同
System.out.println(t);
}
public <Y> void show01(Y y) {// 泛型方法,可以与泛型类的变量要求不同,申明的时候要写在void前面,在引用方法的时候确定下来具体类型
System.out.println(y);
}
// 静态泛型方法,可以直接用类名调用,同样的在调用方法时确认具体类型,注意:他不能使用泛型类上定义的泛型变量,因为他
// 是静态的,是先加载的,这个概念已经反复强调很多遍了
public static <E> void show02(E e) {
System.out.println(e);
}
}
// 泛型接口
interface inter<T> {// 创建一个泛型接口
abstract public void show(T t);// 可以使用这个泛型
abstract public <Y> void method(Y y);// 也可以不使用这个泛型
}
class interimp implements inter<String> {//创建一个实现类,可以此时确定类型
@Override
public void show(String str) {//重写方法,确认T为String类型
System.out.println(str);
}
@Override
public <String> void method(String a) {//重写方法,注意void前面的<String>不能丢
System.out.println(a);
}
}
//可以先不用确定类型,等到创建实现类对象时再确认,但是类名后面也要跟一个泛型
class interimp1<T> implements inter<T>{
@Override
public void show(T t) {
}
@Override
public <Y> void method(Y y) {//什么时候调用此方法什么时候确认类型
}
}
Comparator和Comparable总结
**相同点:**他们都可以提供比较大小的方法;
不同点:
Comparable: 他是让某个类具备了比较功能,当创建出这个类的对象,就可以直接使用这个对象中的compareTo方法进行比较大小。Comparable是让对象自己具备了比较功能
Comparator: 他是提供比较两个对象大小,但是这个功能和对象自身并没有任何的关系。只要将需要比较的两个对象传递给compare方法即可。提供单独的比较器对象,可以比较任意的两个对象。