java基础|接口|查漏补缺|comparable接口|深浅拷贝

  • 不能使用new实例化一个接口,但是可以声明一个接口的变量:
Comparable x;
x = new Employe(...);
  • 还可以使用instanceof检查一个对象是否实现了某个特定的接口:
if(anObject instanceof Comparable{}
  • 接口也可以继承,子接口会继承父接口的方法。

  • 接口中不能包含实例字段,但是可以包含常量。

  • 接口中的方法都会自动被声明为public,接口中的字段总是被声明为public static final

  • 一个类只能继承一个父类,但是可以实现多个接口

  • 可以为接口方法提供一个默认实现,使用default关键字

public interface Comparable<T> {
    default int comparaTo(T other) { return 0; }    
}
  • 默认方法还可以调用其他方法
public interface Collection {
    int size();
    default boolean isEmpty() { return size()==0; }
}
  • 默认方法发生冲突时:1、超类优先。2、类实现的两个接口有同名方法时,需要在两个方法中选择一个实现,如下:
class Student implements Person, Named {
    public String getName() { return Person.super.getName(); }
}

Comparable接口与Comparator接口

如果需要使用Arrays类的sort方法对对象数组进行排序,那么需要实现Comparable接口。
Comparable接口需要实现一个方法compareTo(),这个方法返回正值或者负值或者0。

class Employee implements Comparable<Employee> {
    public int compareTo(Employee other) {
        return Double.compare(salary, other.salary);
    }
}

如上述例子实现了Comparable接口,并且使用泛型为接口提供了一个类型参数。这样Employee就可以使用sort方法进行排序。

但是有一个问题,比如像String类这样的已经实现了Comparable接口的类,如果想要修改排序的比较方法的话,我们不可能去修改String类。这种情况就可以使用Comparator接口。
可以定义一个实现了Comparator接口的类,然后将这个类作为参数传入sort方法中同样可以实现排序。

class LengthComparator implements Comparator<String> {
    public int compare(String first, String second) {
        return first.length()-second.length();
    }
}

具体比较时可以这样操作:

Arrays.sort(friends, new LengthComparator());

可以使用lamdba表达式简化上述写法:

Arrays.sort(friends, (first, second) -> first.length()-second.length());

Comparator接口中包含很多方便的静态方法来创建比较器。这些方法可以用于lambda表达式或方法引用。比如下面这个:

Arrays.sort(people, Comparator.comparing(Person::getName));

还可以串联比较器

Arrays.sort(people, Comparator.comparing(Person::getName).thenComparing(Person::getFirstName));

如果有null值可以这样处理:

Arrays.sort(people, Comparator.comparing(Person::getName, nullsFirst(naturalOrder())));

对象克隆(Cloneable接口)

直接为对象创建一个副本实际上只是创建了一个指向同一个对象的引用,任何一个指向这个对象的变量做出改变都会影响另一个变量。如果想要变量指向一个新的对象,可以使用clone方法。但是clone方法是Object的一个protected方法,也就是说,只有对象自己可以调用这个方法来克隆自己。
使用clone进行拷贝,实际上是对对象的每一个字段逐个的进行拷贝,如果对象的每一个字段都是不可变的对象或者是基本类型,那么这种拷贝是没问题的,拷贝的对象的字段变化不会影响原始对象。但是如果对象包含子对象的引用,而且子对象是可变的,这种情况下实际上拷贝过来的对象还是有共享的字段,这种情况拷贝对象改变内容会影响到原始对象。
对于每一个类,需要确定:
1、默认的clone方法是否满足要求。
2、是否可以在可变的子对象上调用clone来修补默认的clone方法。
3、是否不该使用clone。
实际上第三个选项是默认选项。如果想要实现1和2,需要满足:
1、实现Cloneable接口
2、重新定义clone方法,并指定public访问修饰符。

Cloneable接口是一个标记接口。标记接口中不包含任何方法;它唯一的作用是允许在类型查询中使用instanceOf。

一个例子:

class Employee implements Cloneable {
    public Employee clone() throws CloneNotSupportedException {
        Employee cloned =  (Employee) super.clone();
        cloned.hiredDay = (Date)hireDay.clone();
        return cloned;
    }
}

上面这个深拷贝的例子可以看到,实现Cloneable接口需要将clone()方法的修饰符更改为public,在clone()方法中需要对每一个可变对象字段进行拷贝。但是有一个问题是子对象的clone()方法不一定能正常工作,这时就会抛出一个CloneNotSupportedException异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值