Java接口知识整理

       接口技术,这种技术主要用来描述类具有什么功能,而并不给出每个功能的具体实现。一个类可以实现一个或多个接口,并在需要接口接口的地方,随时使用实现接口的对象。在Java程序设计语言中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。

       我们经常听到服务提供商这样说:“如果类遵从某个特定的接口,那么就履行这项义务”。Arrays类中的sort方法承诺可以对对象数组进行排序,但要求满足以下前提:对象所属的类必须实现Compareable接口。

       这就是说,任何实现Comparable接口的类都要包含compareTo方法,并且这个方法的参数必须是一个Object对象,返回一个整型数值。接口中的方法全部自动的都是public,这就是接口存在的原因所在,接口就是为了其他类实现的,所以接口中的所有方法是公有的。因此,在接口中声明方法时,不必提供关键字public。

        在接口中可以有一个方法,也可以有多个方法,还可以在接口中定义常量,然而最终要的是要知道接口不能提供哪些功能。接口不能含有实例域,也不能在接口中实现方法。提供实例域和方法实现的任务应该有实现这个接口的类来完成 ,因此,可以将接口看成是没有实例域的抽象类,但是,两者还是存在一定的区别的。

现在假设使用Arrays类的sort方法对类对象数组进行排序,那么这个类就必须实现Comparable接口。

为了让一个类实现一个接口,通常需要下面的步骤:

  1. 将类声明为实现给定的接口

  2. 对接口中的所有方法进行定义

public class ACar implements Comparable<ACar>,BCar{
	private double speed;
	public double getSpeed() {
		return speed;
	}
	public void setSpeed(double speed) {
		this.speed = speed;
	}
	public ACar( double speed) {
		super();
		this.speed = speed;
	}
	@Override
	public String toString() {
		return "ACar [ speed=" + speed + "]";
	}
	@Override
	public int compareTo(ACar o) {
		return  Double.compare(speed, o.speed);
	}
}
public interface BCar {
     ACar b = new ACar(33) ;
	 int x = 2;
}
public class CarText implements BCar{
	public static void main(String[] args) {
		
		System.out.println(x);
			//x = 5;更改x的值,这里会报错
		System.out.println(b.getSpeed());
		b.setSpeed(100);
		System.out.println(b.getSpeed());
	/*
	 * b = new ACar(66);更改b的引用地址,这里会报错
	 * 与接口中的方法都设置成public一样,接口中的域将自动设置为public static final
	        这里两个地方都会报错,我们可以得出总结了:static的变量值会在内存中的一个特殊的静态内存区,
	        它与堆区和栈区是分离的 对于基本类型来说,静态的常量的值不是在堆中开辟内存了,而是在这个静态内存区,
	        所以改变x的值就是改变栈中x变量名指向静态区的地址指向,   这是不允许的,
	        同样对于引用类型来说,它的引用对象地址存放在静态区,但是它的实例域在堆中开辟内存,
	        然后静态区中的对象引用指向堆中的实例域的值,所以,我们可以更改堆中的值不会报错,但是不能更改引用类型对象的引用地址。
	 */
		ACar car = new ACar(1);
		ACar car1 = new ACar(3);
		ACar car2 = new ACar(5);
		ACar car3 = new ACar(7);
		
		ACar[] list = {car2,car,car3,car1};
		Arrays.sort(list);
		
		int [] A = {3,5,2,1,7};
		Arrays.sort(A);
		
		for(ACar a : list) {System.out.print("=="+a);}
		System.out.println();
		for(int a : A) {System.out.print("=="+a);}
	}
}
结果:
==ACar [ speed=1.0]==ACar [ speed=3.0]==ACar [ speed=5.0]==ACar [ speed=7.0]
==1==2==3==5==7

几个重要的方法:

Java.lang.Comparable<T>

Int compareTo(T other)

用这个对象与other进行比较。如果这个对象小于other则返回负值,如果相等则返回0;否则返回正值。

Java.util.Arrays

Static void sort(Object [] a)

使用mergesort算法(归并排序)对数组a中的元素进行排序,要求数组中的元素必须属于实现了Comparable接口的类,并且元素之间是可比较的。

Java.lang.Integer

Static int compare(int x,int y)

如果x<y,返回一个负数,如果x=y,返回0,否则返回一个正数。

Java.lang.Double

Static int conpare(double x,double y)

如果x<y,返回一个负数,如果x=y,返回0,否则返回一个正数。

接口的特性

       接口不是类,尤其不能使用new运算符实例化一个接口,然而,尽管不能构造接口的对象,却能声明接口的变量。接口变量必须引用实现该接口的类对象。接下来如同使用instanceof检查一个对象是否属于一个特定的类一样,也可以使用instanceof检查对象是否实现了某个接口。

与建立类的继承关系一样,接口也可以被扩展。实现扩展接口的类要实现该接口和被扩展接口的所有方法。

静态方法:

在Java SE 8 中,允许在接口中增加静态方法。理论上讲,没有任何理由认为这是不合理的,只是这样有违于接口作为抽象规范的初衷。目前为止,通常的做法都是将静态方法放在伴随类中。在标准库中,你可能会看到成对出现的接口和实用工具类,如Collection/Collections.

 

默认方法

可以为接口方法提供一个默认实现。必须使用default修饰符标记这一方法。

Public interface Comparable<T>{

    Default int compareTo(T other){return 0;}

}

当然,这并没有太大的用处,因为Comparable的每一个实际实现都要覆盖这个方法。不过有的情况下,默认方法可能会很有用。

例如,希望在发生鼠标点击事件时得到通知,就要实现一个包含5个方法的接口:

public interface MouseListener{
		void mouseClicked(MouseEvent event);
		void mousePressed(MouseEvent event);
		void mouseReleased(MouseEvent event);
		void mouseEntered(MouseEvent event);
		void mouseExited(MouseEvent event);
	}

大多数的情况下,你只需要关心其中的一个或两个事件类型,所以在Java SE 8 中,可以把所有的方法声明为默认方法,这些默认方法什么也不做。声明如下:

public interface MouseListener{
		default	void mouseClicked(MouseEvent event);
		default	void mousePressed(MouseEvent event);
		default	void mouseReleased(MouseEvent event);
		default	void mouseEntered(MouseEvent event);
		default	void mouseExited(MouseEvent event);
	}

这样一来,实现这个接口的程序员只需要为他真心关心的事件覆盖监听器。默认方法可以调用任何其他方法。比如:

public interface Collection{
		int size();
		default boolean idEmpty() {return size() == 0;}
	}

这样实现Collection的程序员就不用操心实现isEmpty方法了。

假设很久之前提供一个类,public class Bag implements Collection ,后来在Java SE 8中又为接口增加了一个stream方法。假设这个方法不是默认方法,那么Bag类不能进行编译,因为它没有实现该接口的所有方法。为接口增加一个非默认方法不能保证“源代码兼容”。不过,假设不重新编译这个类,而是仅使用原来包装这个类的JAR文件,这个类仍然可以正常加载,尽管没有实现这个新方法,但是如果Bag实例上调用了stream方法,则会出现一个AbstractMethodError。解决这两个问题的方法就是将stream方法在接口中定义为默认方法,这样,Bag类既能正常编译,另外如果没有重新编译这个了,Bag的实例调用stream方法,将调用Collection中的stream方法。

解决默认方法的冲突

规则如下:

1、超类优先。如果超类提供一个具体方法,同名而且有相同的参数的默认方法会被忽略。

2、接口冲突。如果一个超接口提供一个默认方法,另一个接口提供一个相同参数类型的同名的方法,必须覆盖这个方法来解决冲突。这里解释一下,一个类实现了两个接口中的相同方法,其实在类中直接实现就可以了,因为在接口中都只是声明了方法,具体实现还是要实现接口的类来完成。

还有一种情况,一个类扩展了一个超类,同时实现一个接口,并从超类和接口中继承了相同的方法,在这种情况下,只考虑超类的方法,接口中的所有默认方法都会被忽略。

接口与回调

回调是一种常见的程序设计模式,在这种模式下,可以指出某个特定事件发生时应该采取的动作。


public class TimerText {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ActionListener listener = new TimePrinter();
		Timer t = new  Timer(10000,listener);
		t.start();
		JOptionPane.showMessageDialog(null, "quit program?");
		System.exit(0);
	}
}

public class TimePrinter implements ActionListener {
	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		System.out.println("at the time the time is:"+ new Date());
		Toolkit.getDefaultToolkit().beep();
	}
}

结果:
at the time the time is:Sat Aug 18 16:20:15 CST 2018
at the time the time is:Sat Aug 18 16:20:25 CST 2018
at the time the time is:Sat Aug 18 16:20:35 CST 2018
at the time the time is:Sat Aug 18 16:20:45 CST 2018
at the time the time is:Sat Aug 18 16:20:55 CST 2018

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值