飞道的博客

Java抽象类VS接口

321人阅读  评论(0)

抽象类与抽象方法

修饰对象

abstract可以用来修饰的结构:类、方法

注意事项

  1. 不能用abstract修饰变量、代码块、构造器;
  2. 不能用abstract修饰私有方法、静态方法、 final的方法、 final的类。

抽象类

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。

abstract关键字来修饰一个类, 这个类叫做抽象类。

abstract

抽象类的特点

  1. 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。

  2. 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)

  3. 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作

抽象方法

用abstract来修饰一个方法, 该方法叫做抽象方法。只有方法的声明,没有方法的实现以分号结束。

抽象方法的特点

  1. 抽象方法只有方法的声明,没有方法体

  2. 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。

  3. 若子类重写了父类中的所有的抽象方法后,此子类方可实例化

  4. 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

示例

抽象类的使用示例

abstract class A { 
    
    abstract void m1();
    
    public void m2() {
    System.out.println("A类中定义的m2方法");
    }
    
}

class B extends A {
    
    void m1() {
    System.out.println("B类中定义的m1方法");
    }
}

public class Test {
    public static void main(String args[]) {
        A a = new B();
        a.m1();
        a.m2();
    }
}

接口

接口(interface)是抽象方法和常量值定义的集合。

Java中,接口和类是并列的两个结构

为什么使用接口?

  1. 一方面, 有时必须从几个类中派生出一个子类, 继承它们所有的属性和方法。 但是, Java不支持多重继承。 有了接口, 就可以得到多重继承的效果。
  2. 另一方面, 有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、 MP3机、手机、数码相机、移动硬盘等都支持USB连接。

接口的特点

  1. 用interface来定义。
  2. 接口中的所有成员变量都默认是由public static final修饰的。
  3. 接口中的所有抽象方法都默认是由public abstract修饰的。
  4. 接口中没有构造器!意味着接口不可以实例化
  5. 接口采用多继承机制。
  6. 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
  7. 与继承关系类似,接口与实现类之间存在多态性
  8. 接口和类是并列关系, 或者可以理解为一种特殊的类。 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前), 而没有变量和方法的实现(JDK8后拥有)。

如何定义接口?

JDK7以前

只能定义全局常量和抽象方法

全局常量:public static final的.但是书写时,可以省略不写

抽象方法:public abstract的

JDK8

除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)

接口实现VS类继承

  1. 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
  2. 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。

图例

接口VS抽象类


在开发中,常看到一个类不是去继承一个已经实现好的类,而是要么继承抽象类,要么实现接口。

接口的使用示例

/*
 * 接口的使用
 * 1.接口使用上也满足多态性
 * 2.接口,实际上就是定义了一种规范
 * 3.开发中,体会面向接口编程!
 * 
 */
public class USBTest {
	public static void main(String[] args) {
		
		Computer com = new Computer();
		//1.创建了接口的非匿名实现类的非匿名对象
		Flash flash = new Flash();
		com.transferData(flash);
		
		//2. 创建了接口的非匿名实现类的匿名对象
		com.transferData(new Printer());
		
		//3. 创建了接口的匿名实现类的非匿名对象
		USB phone = new USB(){

			@Override
			public void start() {
				System.out.println("手机开始工作");
			}

			@Override
			public void stop() {
				System.out.println("手机结束工作");
			}
			
		};
		com.transferData(phone);
		
		
		//4. 创建了接口的匿名实现类的匿名对象
		
		com.transferData(new USB(){
			@Override
			public void start() {
				System.out.println("mp3开始工作");
			}

			@Override
			public void stop() {
				System.out.println("mp3结束工作");
			}
		});
	}
}

class Computer{
	
	public void transferData(USB usb){//USB usb = new Flash();
		usb.start();
		
		System.out.println("具体传输数据的细节");
		
		usb.stop();
	}
	
	
}

interface USB{
	//常量:定义了长、宽、最大最小的传输速度等
	
	void start();
	
	void stop();
	
}

class Flash implements USB{

	@Override
	public void start() {
		System.out.println("U盘开启工作");
	}

	@Override
	public void stop() {
		System.out.println("U盘结束工作");
	}
	
}

class Printer implements USB{
	@Override
	public void start() {
		System.out.println("打印机开启工作");
	}

	@Override
	public void stop() {
		System.out.println("打印机结束工作");
	}
	
}


JDK8关于接口的改进

Java 8中,你可以为接口添加静态方法默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。

静态方法

使用 static 关键字修饰。 可以通过接口直接调用静态方法,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。

使用示例
interface Flyable{
	
	//全局常量
	public static final int MAX_SPEED = 7900;//第一宇宙速度
	int MIN_SPEED = 1;//省略了public static final
	
	//抽象方法
	public abstract void fly();
	//省略了public abstract
	void stop();

}

默认方法

默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如: java 8 API中对Collection、 List、 Comparator等接口提供了丰富的默认方法。

使用示例
interface Filial {// 孝顺的
    default void help() {
    	System.out.println("老妈,我来救你了");
    }
}

interface Spoony {// 痴情的
    default void help() {
    	System.out.println("媳妇,别怕,我来了");
    }
}

class Man implements Filial, Spoony {
    @Override
    public void help() {
    	System.out.println("我该怎么办呢?");
    	Filial.super.help();
    	Spoony.super.help();
    }
}

注意事项

  1. 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。会出现: 接口冲突
    解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突(在实现类中重写此方法)。
  2. 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守: 类优先原则。 接口中具有相同名称和参数的默认方法会被忽略。(如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。)
  3. 接口中定义的静态方法,只能通过接口来调用。
  4. 通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法。

转载:https://blog.csdn.net/qq_42937522/article/details/106564758
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场