java核心技术笔记——接口

概念:

接口不是类,而是对类的一组需求的描述。接口也是可以继承的。如下是一个接口。接口所有的方法在声明时候自动属于public。接口绝不能含有实力域,提供实力域和方法实现的任务由实现接口的类去完成。

public interface Comparable<T>{

    int compareTo(T other);

}

实现接口的类必须实现接口的所有方法,一个类是可以实现多个接口的。如下是一个类实现上述接口的例子。类实现接口用implements关键字。实现类里提供方法实现的时候必须注明方法为public,否则会当作默认的default.

Class Employee implements Comparable<Employee >{

private double salary;

double get/setSalary(){

...

}

public int compareTo(Employee other){

return Double.compare(salary,other.salary);

}

}

提示:如果要让一个类实现排序服务,必须对这个类实现compareTo,因为要实现比较大小。但是为什么都是现存在的类一般都是实现comparable接口呢?因为java是一种强类型语言,在调用方法时,编译器会检查这个方法是否存在,在sort()中可能存在if(a[i].compareTo(a[j])>0) ,为此编译器必须确定啊a[i]一定有compareTo方法,如果a是一个Comparable对象(类实现一个接口,那么可以接口对象生命,用类对象创建实例  https://blog.csdn.net/wanglin_ni_ge/article/details/77971660)的数组就可以确保有这个方法,因为是实现接口必须要提供接口内方法的定义。

接口的特性:

1、接口不是类,不能实例化,但是可以声明接口对象,接口变量必须引用实现了接口的类对象。个

Comparable a= new Employee();

2、人理解其实类实现接口就像类继承了接口,重写接口的方法,所以也可以用instanceof检查一个对象是否实现了某个特定的接口。而且接口也可以扩展(其实就是继承)。

3、接口不能包含实例域和静态方法,但是可以包含常量。接口中的域将被自动设置成public static final。所以常量默认就是public static final。

4、类智能有一个超类,但是可以实现多个接口。直接逗号分隔,class Employee implements Cloneable , Comparable

提示:java SE8中允许在接口中增加静态方法,但是这违背了接口作为抽象规范的初衷,所以通常的做法都是讲静态方法放在伴随类中,比如Collection/Collections或者Path/Paths。

5、接口可以提供默认实现,但是一般情况先没有用,因为每一个类实现接口时都会覆盖这个方法。默认方法前面加上关键字default修饰。有些时候加上默认修饰,在实现改接口的时候就只需要关注想要实现的方法,不必关注默认的了。类实现接口的时候可以不实现默认方法。默认方法可以调用接口里的任何其他方法。

6、如果方法冲突,即被实现或者继承的类有同一个方法,参数以及名字都相同,此时以超类有限;或者两个超接口冲突(java中两个接口如果都有a方法,哪怕其中一个接口没有提供默认实现,另一个提供了,也算是冲突)则需要重新覆盖这个方法解决冲突。

提示:java方法中stream放就是javaSE8中Collection加入的默人方法,所以在这个版本之前实现Collection方法的类并不会受到Collection中新加入的stream方法的影响。同时上面说的冲突时候类优先原则,也是保证了为接口增加默认方法的时候如果与超类冲突的话原来的类不会受影响。保证兼容性。

回调:一个简单的例子

java.swing 中有Timer类,提供定时器,java将某一个对象传给定时器,定时器定时调用方法,定时器为了知道调用什么方法,于是实现了ActionListener接口。

public static void main(){

ActionListener listener=new TimePrinrer();

Timer t=new Timer(10000,litener);
t.start();

}

Class TimePrinter implements ActionListener(){

public void actionPerformed(ActionEvent event){

system.out.printlv(111);

}

}

Comparator接口:

象String实现了comparable接口,而且是按照字典顺序比较字符串。假设现在希望根据字符串长度排的序。因为我们不能让String实现两个compareTo方法,于是Arrays.sort还有第二个版本,就是用数组、比较器作为参数,比较器是实现了comparator接口的实例。

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

Comparator<String> com=new LengthComparator();
if(com.compare(a[i],a[j])>0)


String[] friends = {"1111","2222","33333333"};
Arrays.sorts(frinends,new LengthComparator());

Cloneable接口:clone()

如果希望copy一个对象,与原来的初始对象状态相同,但是之后他们会有自己各自的状态,那么就用clone方法.因为直接赋值的形式,obj a=b;a、b指向同一个引用,变化是同步的。

实际上clone()是object类的方法,是protect类型的,需要该类或者子类或者一个包的类才能访问,但是如果对象的实例域包含另一个对象,拷贝后的对象和原对象就会有共享信息,也就是我们说的浅拷贝,如果共享信息是不变的或者共享的对象是不可变的比如String,这些情况都没问题。不过通常子对象都是可变的,就需要重新定义clone方法来建立一个深拷贝,同时克隆所有子对象,实际上类需要实现复制的话这时候就需要实现Cloneable接口,重新定义clone方法为public。然后通过super.clone();调用clone方法。比如如下实现浅拷贝。

class Employee implements Cloneable(){
    public Employee clone() throws CloneNotSupportedException{
        return (Employee) super.clone();
    }
}

如下是一个带有Date类型对象的深拷贝

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

lambda表达式:(参数类型 参数)->{逻辑}

有时候参数类型和括号都可以省略,对于只有一个抽象方法的接口,需要这种接口对象时,可以提供一个lambda表达式。这种接口称为函数式接口。例如之前的Arrays.sort(words,(first,second)->first.length()-second.length());

Timer t=new Timer(1000,event->System,out,println(event));

方法引用:例:Array.sorts(Strings,String::compareToIgnoreCase);
object::instanceMethod  

Class::staticMethod  Math::pow==Math.pow(x,y);

Class::instanceMethod  String::compareToIgnoreCase==(x,y)->x.compareToIgnoreCase(y);

可以在方法引用中使用this、super,例如

class Greeter{
    public void greet(){
        ...    
    }
}
class TimedGreeter extends Greeter{
    public void greet(){
        Timer t=new Timer(1000,super::greet);
        t.start();
    }
}

构造器引用:类::new/类[]::new

可以用数组类型建立构造器引用,例如:int[]::new==x->new int[x];

 内部类:

1、内部类可以访问该类定义作用域内的数据,包括私有数据;常规类是不行的比如将创建A累的引用this传给另一个类的构造方法,当B类访问outer.beep的时候还是会报错。因为没有权限。编译器会在编译的时候对外部类进行处理,导致内部类的一些访问是特殊的,与外部常规的访问是不同的。

2、内部类可以对同一包内的其他类隐藏;

3、当想定义一个回调函数而不想编写大量代码时,匿名内部类比较好用。

public class TalkingClock{
    private boolean beep;
    public void TalkingClock();
    public void start();
    

    public class TimerPrinter implements ActionListener{
        public void TimerPrinter(TalkingClock a){//自动生成
            outer=a;
        }
        public void actionPerformed(ActionEvent event){//三个条件等价
            if(outer.beep){...}
            if(beep){...}
            if(TalkingClock.this.beep){...}
        }
    }
}

4、内部类申明中所有的静态域必须是final的,因为每个外部类对象都有一个内部类实例,那么内部类的static不是final的话就可能不唯一了。

5、内部类不能有static方法。

6、如果一个内部类只是在一个方法中使用,那么可以在一个方法中定义局部内部类,局部内部类没有public或者private修饰符吗,对外界完全隐藏,及时是外围类的其他方法块。

7、假设只创建内部类的一个对象就不必对内部类命名了,这种内部类就是匿名内部类。匿名没有名字也就没有生声明。所以如果类似Person a=new Person("aa"){....},就是正在定义的匿名内部类。

8、有时候声明一个内部类只是为了隐藏在外部类里,并不需要引用外部类的,为此可以将内部类声明为static,这就是静态内部类。静态内部类可以有静态域和方法,与常规内部类不同。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值