java comparator泛型_泛型和Comparable、Comparator接口

♥泛型类型的本质:1. 能够检测参数的类型是否正确合法       2.自动类型转换,避免用户手动类型转换

♥java泛型类型的擦除机制:在编译阶段,能够检测参数的类型是否正确合法 ,自动类型转换,避免用户手动类型转换,类型就擦除到它的上界.

例:开始的Object类编程:

public classGenericTest {//定义一个存储数据的数组

privateObject[] array;//定义变量描述数组有效数据的大小

private intsize;public GenericTest(intsize){this.array=newObject[size];this.size=0;

}publicGenericTest(){this(10);

}//在数组尾部增加元素

public voidadd(Object data){if(this.size==this.array.length){this.array= Arrays.copyOf(this.array,this.array.length*3);

}this.array[size++]=data;

}//获取数组最后一个元素

publicObject get(){if(this.size==0){return null;//引用类型默认返回null,也可以选择跑出异常

}return this.array[size-1];//通过返回值返回

}/*** Object写泛型编程提供的限制是java提供泛型编程本质的意义

*@paramargs*/

public static voidmain(String[] args) {

GenericTest g=newGenericTest();

g.add(20);

g.add(10);

g.add("30");//Object可以接受任意类型,所以本来想存数组,结果写错存了字符串"50"//g.add("hello world");//不会报错,可以接受任意类型

int data=(int)g.get();//基类类型不能赋给具体类型(不能把大类型赋给小类型),会报错,所以要进行类型转化

System.out.println(data);

}

}

出现错误:类型转换错误,String类不能转化为Integer类型

58539fb403ddf3ba1506f3ed0f41eb25.png

•Object实现泛型编程的缺陷:

1.   g.add(20);

g.add(10);

g.add("30");  //这里无法检测传入的数据是否符合用户存储数据的正确类型,不能做类型检查

2.因为是用Object进行泛型编程,所有的方法返回值类型都是Object,  Object作为积累不能转化为派生类类型,必须手动加入类型转换

int data=(int)g.get();

•引出泛型的意义:可以进行类型的检测和自动转换。

•说明泛型类:普通类+    public class GenericTest2

baf9d3cd147eda9e6ed9b4d9851388ec.png

•java泛型的好处:1.可以进行类型的检查  2.可以做类型自动转换

可以确认具体的类型也可以使用原始类型,默认为Object类型

fbacf7da6d90ea460aad63aacfcbf686.png

♥为什么会报错但是不强制转换为指定类型?

历史问题,如果指定,以前开发的代码会报错。因为java5以后才增加泛型,但是要让原来的类使用的时候又不能报错,所以不强制。

♥java泛型的类型擦除机制?

在编译阶段,java编译器通过泛型类型进行类型检查和自动类型转换,处理完成以后,就会把T类型一直往上擦除,直到上界(Object)

GenericTest2GenericTest2一个类型,里面的类型只是为了做对应的类型检查

efb202589706dca64aac3be002223aa8.png

注:打印出来类型相同,经过编译阶段尖括号里面的类型不存在了,擦除了;都是GenericTest2类型,里面的类型只存在编译阶段,运行阶段不存在了。

•参数类型不能为简单类型,因为在编译阶段要进行类型检测和类型转换,处理完成以后要向上擦除到它的基类,简单类型不是类类型,没有基类。

32bd88065c02dd2ea014fef1bb61a150.png

再写一个Student类的泛型,按照id号进行排序:

classStudent {privateString name;privateInteger id;publicStudent(Integer id,String name){this.name=name;this.id=id;

}

@OverridepublicString toString() {

String str= "id:" + id + " name:" +name;returnstr;

}

public void getName() {

this.name=name;

}

}

public class StudentTest {

public static void main(String[] args) {

Student[] stuArr=new Student[3];

stuArr[0]=new Student(1001,"zhang san");

stuArr[1]=new Student(1000,"li si");

stuArr[2]=new Student(1002,"wang wu");

Arrays.sort(stuArr);//给数组排序

//报错,因为这个时候java编译器不知道要给什么进行排序 转型错误(对象没有办法进行比较)

//错误类型:Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

//要实现泛型接口,才能比较

System.out.println(Arrays.toString(stuArr));//打印数组

错误分析:

报错,因为这个时候java编译器不知道要给什么进行排序   转型错误(对象没有办法进行比较)

错误类型Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

要实现泛型接口,才能比较

dbbbec014767db0874747ca7a93a4399.png

实现接口后:class Student implements Comparable{ //Comparable 接口要有,比较学生对象

id实现按照顺序打印:

b4a8cebbce279363d1bdf318409e89e2.png

注:自定义的类型要支持比较,一定要实现Comparable接口,重写compareTo方法

第一种方式:再创建一个比较用户传入的名字类,需要实现Comparator接口,再重写compare()方法:

Sudent类里面需要添加getName方法:classStudent{/*** 外部访问name,需要调用get方法,String类型的getName,需要返回Name*/

publicString getName() {returnname;

}

}public static voidmain(String[] args){

/**

*sort的重载函数,接受一个自定义的比较器,比较name

*/

Arrays.sort(stuArr,newStudentCompareName());

System.out.println(Arrays.toString(stuArr));//打印数组

}

/**

*注:这里的名字需要写成英文的,才能进行排序"zhang san" ,中文式的不能比较"张三"

*这是定义的一个普通类型

*比较学生名字的类实现Comparator接口,重写compare方法

*/

class StudentCompareName implements Comparator{

@Overridepublic intcompare(Student o1, Student o2) {returno1.getName().compareTo(o2.getName());

}

}

f03371be2419c2161079df3328317344.png

第二种方式:定义一个实现了Comparator接口的匿名对象,不用再创建一个新类:

/*** 用一个静态方法来实现名字的比较,产生匿名对象类,不用再创建新的类*/Arrays.sort(stuArr,NAME_COPM);

System.out.println(Arrays.toString(stuArr));//打印数组

/*** new Comparator() 不是new实例化接口,而是实现了一个实现了Comparator接口的匿名对象而已*/

public static Comparator NAME_COPM=new Comparator() {

@Overridepublic intcompare(Student o1, Student o2) {returno1.getName().compareTo(o2.getName());

}

};

e95e3685a346c47ae2094c1c457a6004.png

第三种方式:直接将匿名对象放在sort方法里(最简单)

Arrays.sort(stuArr, new Comparator() {

@Overridepublic intcompare(Student o1, Student o2) {returno1.getName().compareTo(o2.getName());

}

});

System.out.println(Arrays.toString(stuArr));//打印数组

输出一个泛型的顺序栈:实现出栈、入栈、判断栈空栈满

/**

*输出一个泛型的顺序栈*实现构造函数 入栈出栈栈空栈满 获取栈顶元素peek* @param

*/

public class GenericStack{privateT[] stack;private inttop;publicGenericStack() {this(4);

}/*** 带参数的构造函数

*@paramsize*/

public GenericStack(intsize) {this.stack = (T[])newObject[size];this.top=0;

}/*** 获取栈顶元素

*@return

*/

publicT peek(){if(empty()){return null;

}return this.stack[this.top-1];

}/**ctrl+Q 键生成说明

* 入栈操作

*@paramdata*/

public voidpush(T data){if(full()){this.stack=Arrays.copyOf(this.stack,this.stack.length*2);

}this.stack[this.top++]=data;

}public intsize(){return this.top;

}/*** 出栈并返回出栈元素

*@return

*/

publicT pop(){if(empty()){return null;

}

T t= this.stack[this.top-1];--this.top;

returnt;

}/*** 判断栈满

*@return

*/

private boolean full() { return this.top==this.stack.length; }/*** 判断栈空

*@return

*/

private boolean empty() { return this.top==0; }public static void main(String[] args)throwsInterruptedException {

GenericStack s=new GenericStack<>(10);

s.push("20");

s.push("10");

System.out.println(s.pop());

System.out.println(s.peek());for(int i=0;i<10;i++){

s.push(String.valueOf(i+1));//将i+1转换为String类型的并入栈

}while (!s.empty()){

System.out.print(s.pop()+" "); //将栈中的元素输出

}

垃圾回收机制(GC):

GC:Garbage collection怎么回收对象-》任意一个对象,如果没有被其他引用变量引用,这个对象就可以被GC回收了

可以手动启动GC ,System.gc(),用jamp命令查看当前活着的进程

注:将引用变量s置为空后,查看进程时找不到该对象,说明已经被回收

285fbd540ec93047c0e3c14ce33d8dd4.png

提供一个学生类,定义姓名、学号、年龄属性,提供get set方法

public classStudent{privateInteger id;privateString name;privateInteger age;publicStudent(Integer id,String name,Integer age) {this.id =id;this.name=name;this.age=age;

}publicInteger getId() {returnid;

}public voidsetId(Integer id) {this.id =id;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicInteger getAge() {returnage;

}public voidsetAge(Integer age) {this.age =age;

}

@OverridepublicString toString() {return "Student{" +

"id=" + id +

", name='" + name + '\'' +

", age=" + age +

'}';

}

}

public class GenericStack {

private T[] stack;

private int top;

public GenericStack() {

this(4);

}

/**

* 带参数的构造函数

* @param size

*/

public GenericStack(int size) {

this.stack = (T[])new Object[size];

this.top=0;

}

/**

* 获取栈顶元素

* @return

*/

public T peek(){

if(empty()){

return null;

}

return this.stack[this.top-1];

}

/** ctrl+Q 键生成说明

* 入栈操作

* @param data

*/

public void push(T data){

if(full()){

this.stack=Arrays.copyOf(this.stack,this.stack.length*2);

}

this.stack[this.top++]=data;

}

public int size(){

return this.top;

}

/**

* 出栈并返回出栈元素

* @return

*/

public T pop(){

if(empty()){

return null;

}

T t= this.stack[this.top-1];

--this.top;

this.stack[this.top]=null; //将出栈的值置为null,才能将对象删除

return t;

}

/**

* 判断栈满

* @return

*/

private boolean full() { return this.top==this.stack.length; }

/**

* 判断栈空

* @return

*/

private boolean empty() { return this.top==0; }

public static void main(String[] args)throws InterruptedException {

GenericStack s2=new GenericStack<>();

s2.push(new Student(1000,"zhangsan",20));

s2.push(new Student(1001,"lisi",21));

s2.push(new Student(1002,"wangwu",22));

s2.push(new Student(1003,"zhan",20));

s2.push(new Student(1004,"san",20));

System.out.println(s2.pop());

System.out.println(s2.pop());

Thread.sleep(10000000);

}

}

没有将输出的栈元素置空时,在出栈两个元素后,查看Student依然存活着5个对象。

acde425aa400e0a2fa2e1e4cacce9f9b.png

在出栈的方法中加入 this.stack[this.top]=null; //将出栈的值置为null,才能将对象删除,此时查看活着的进程,只有三个。

eee7918ab7984c402a7379979ae101ab.png

将栈里面的元素放在一个数组中,并按照学号排序:

/*** 想将目前栈里面的元素放在一个数组里(3个)

* 所以返回栈元素的个数

*@return

*/

public intsize(){return this.top;

}

}public static voidmain(String[] args){

Student[] st=newStudent[s2.size()];for(int i=0;!s2.empty();++i){

st[i]=s2.pop();

}

System.out.println(Arrays.toString(st));

Arrays.sort(st);

System.out.println(Arrays.toString(st));

}

}

出现类型转型错误:

b308f2d014975316ec8c970bc964f2a1.png

给Student实现Comparable接口,重写它的compareTo方法,才能进行比较

11f70772f9f05a041a12750c55e27e54.png

但是后面可能还有别的需求;难道比较名字、年龄就要重写compareTo方法吗?

sort函数提供了相应的构造器来接收比较的内容:λ表达式

df1c9649e1c3af47e9d87f6edc5ce254.png

若按照从大到小排序:(a,b)->{ - return a.getAge().compareTo(b.getAge());}  (加负号即可)

泛型方法:

1.普通泛型方法

在一个数组中寻找最大值

publicT findMaxValue(T[] arr) {if(arr==null){return null;

}if(arr.length==1){return arr[0];

}

T max= arr[0];for (int i = 1; i < arr.length; i++) {if (max.compareTo(arr[i])<0) { //compareTo比较对象,不能用 > <

max =arr[i];

}

}returnmax;

}

2.静态的泛型方法

/*** static 方法能不能使用泛型类定义的泛型类型参数呢?? 不能。静态方法的调用不需要依赖对象

* java的泛型可以定义三种东西:1.泛型类public class A { }

* 2.泛型方法: 在函数的返回值前面增加类型列表

* 3.泛型接口 Comparable Comparator

*@paramarr

*@param 可改变的方法的类型,要实现compareTo方法,该类需要继Comparable接口

* 第二个E相当于其他方法里的void ,即返回一个E类型的参数

*@return

*/

public static >E findMax (E[] arr){

E max1=arr[0];for (int i = 1; i < arr.length; i++) {if (max1.compareTo(arr[i])<0) { //compareTo比较对象

max1 =arr[i];

}

}returnmax1;

}

总程序:

/*** 要求T类型向上擦除到Comparable才能实现compareTo方法

* 此处,给泛型类型定义类泛型的上界(不定义上界,就擦除到Object类了)

*现在擦除到接口类型

*@param

* 2019/10/22*/

class Compare>{publicT findMaxValue(T[] arr) {if(arr==null){return null;

}if(arr.length==1){return arr[0];

}

T max= arr[0];for (int i = 1; i < arr.length; i++) {if (max.compareTo(arr[i])<0) { //compareTo比较对象,不能用 > <

max =arr[i];

}

}returnmax;

}/*** static 方法能不能使用泛型类定义的泛型类型参数呢?? 不能。静态方法的调用不需要依赖对象

* java的泛型可以定义三种东西:1.泛型类public class A { }

* 2.泛型方法: 在函数的返回值前面增加类型列表

* 3.泛型接口 Comparable Comparator

*@paramarr

*@param 可改变的方法的类型,要实现compareTo方法,该类需要继Comparable接口

* 第二个E相当于其他方法里的void ,即返回一个E类型的参数

*@return

*/

public static >E findMax (E[] arr){

E max1=arr[0];for (int i = 1; i < arr.length; i++) {if (max1.compareTo(arr[i])<0) { //compareTo比较对象

max1 =arr[i];

}

}returnmax1;

}

}public class泛型的上界 {public static voidmain(String[] args) {

Integer[] arr=new Integer[]{12,5,78,9,45};

Compare comp=newCompare();

System.out.println(comp.findMaxValue(arr));

System.out.println(Compare.findMax(arr));

}

}

002c0bcaa0503002aa8ca3b6af8f0515.png

♥总结:

泛型可以用来定义什么?

1.泛型类 public class A{  }

2.泛型方法 (1).普通方法:public T fly(T  t)  { }  (若要实现比较应用compareTo方法,该类需要继承Comparable接口,需要给泛型定义上界)

(2).静态方法:public E fly(E  e)(若要实现比较应用compareTo方法,该类需要继承Comparable接口 )

3.泛型接口   class StudentCompareName implements Comparator  ,比较的是Student里面的属性,所以

Comparble(重写compareTo方法)     Comparator(重写compare方法,两个参数)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "Comparable" 和 "Comparator" 这两个词在 Java 编程语言中都是用于排序的概念。 - "Comparable" 是 Java 类库自带的一个接口,它的实现类可以使用 Java 内置的排序方法,例如 Collections.sort()。如果一个类实现了 "Comparable" 接口,就表示这个类支持比较排序。 - "Comparator" 是一个独立的接口,它的实现类可以用于定义自定义的排序方法,例如 Collections.sort(List, Comparator)。如果某个类没有实现 "Comparable" 接口,那么可以通过使用 "Comparator" 来实现排序。 总的来说,如果一个类已经实现了 "Comparable" 接口,那么可以直接使用它的比较方法进行排序。如果没有实现,则需要使用 "Comparator" 来定义自定义的排序方法。 ### 回答2: ComparableComparator是在Java中用于比较对象的两种不同方式。 1. Comparable是一个接口,它允许与它相关的类实现自己的比较规则。实现Comparable接口的类必须实现compareTo()方法,该方法用于定义对象之间的自然排序。compareTo()方法返回一个整数值,表示当前对象与参数对象的比较结果。这个值决定了两个对象之间的大小关系。 2. Comparator是一个接口,它允许在不修改源代码的情况下定义一个额外的比较规则。与Comparable不同,实现Comparator接口的类可以独立于被比较的类进行比较。Comparator接口要求实现compare()方法,该方法用于定义两个参数对象之间的比较结果。compare()方法返回一个整数值,表示对象之间的大小关系。 因此,Comparable是被实现在对象自身内部的排序规则,而Comparator是一个独立的外部排序规则。利用Comparable实现的排序规则是类内部默认的排序规则,而Comparator通过传入不同的比较器来实现多种排序规则。 在使用场景上,Comparable常用于对已有的类进行排序,而Comparator通常用于对现有的类进行定制的排序需求。 ### 回答3: ComparableComparator都是Java中用于排序的接口,它们主要的区别在于使用的方式和对象类型。 Comparable接口Java中的一个泛型接口,它定义了一个compareTo()方法,用于比较当前对象和另一个对象的大小。实现Comparable接口的类可以直接通过compareTo()方法进行比较和排序,例如,使用Collections.sort()方法对Comparable对象进行排序。 Comparator接口也是Java中的一个泛型接口,它定义了一个compare()方法,用于比较两个对象的大小。Comparator接口是一个独立于被比较的对象的比较器,可以用于实现灵活的比较逻辑。比如,如果一个类已经实现了Comparable接口,但我们想要根据不同的条件进行排序,就可以使用Comparator接口来定义不同的比较器。Comparator接口可以作为参数传递给排序方法,如Collections.sort(),来实现定制的排序。 简而言之,Comparable是一个类的内部排序方式,实现Comparable接口的类可以通过compareTo()方法进行大小比较和排序。Comparator是一个独立的比较器,可以用于比较任意类型的对象,通过compare()方法来实现不同的排序逻辑。相比之下,Comparator的灵活性更高,可以用于实现各种不同的排序规则和策略,而Comparable只能用于同一种排序逻辑的对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值