JAVA中接口和抽象类的区别

JAVA中接口和抽象类的区别


    学过C++的朋友应该知道,在C++中并没有显式地区分出接口这个概念,但是在C++中可以定义类似于JAVA中的接口的抽象类实现接口的功能。JAVA中将接口抽离出来,作为一个单独的形式存在,使得在JAVA中使用接口变得更加清晰明朗,在JAVA中对接口的使用也是青睐有加。

    本篇文章不涉及JDK7以后的新特性,对于新的JDK特性可能对于接口和抽象类的区别有一些变化,但是目前采用的并不多,所以我们还以大家最经常使用的情况为例进行介绍。本篇文章重点在于介绍区别,所以对于接口和抽象类的细节问题不深究。

    1. 抽象类

(1)抽象类的由来

    把多个共性的东西提取到一个类中,这是继承的做法。但是呢,这多个共性的东西,在有些时候,方法声明一样,但是方法体。也就是说,方法声明一样,但是每个具体的对象在具体实现的时候内容不一样。所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。而一个没有具体的方法体的方法是抽象的方法。在一个类中如果有抽象方法,该类必须定义为抽象类。

(2)抽象类的特点

    A. 抽象类和抽象方法必须用关键字abstract修饰;
    B. 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类;
    C. 抽象类不能实例化;
    D. 抽象类的子类可以是一个抽象类,也可以是一个具体类。如果是具体类,则这个类必须重写抽象类中的所有抽象方法。

(3)抽象类的成员特点

    A. 成员变量:有变量,有常量;
    B. 构造方法:有构造方法;
    C. 成员方法:有抽象,有非抽象。

(4)抽象类的几个小问题

    A. 抽象类有构造方法,不能实例化,那么构造方法有什么用?
    答:用于子类访问父类数据的初始化

    B. 一个类如果没有抽象方法,却定义为了抽象类,有什么用?
    答:为了不让创建对象

    C. abstract不能和哪些关键字共存?
    答:abstract关键字与final和private关键字冲突,因为抽象类必须要被子类重写,要被继承,所以不能是私有的和最终的,它与static组合则是无意义的。

(5)抽象类的一个例子

abstract class Animal {
	// 抽象方法,必须是空
	public abstract void eat();
	
	public Animal(){}
}

// 子类是抽象类
abstract class Dog extends Animal {}

// 子类是具体类,重写抽象方法
class Cat extends Animal {
	public void eat() {
		System.out.println("猫吃鱼");
	}
}

class AbstractDemo {
	public static void main(String[] args) {
		// 创建对象
		// Animal是抽象的; 无法实例化
		// Animal a = new Animal();
		// 通过多态的方式
		Animal a = new Cat();
		a.eat();
	}
}

    2. 接口


(1)接口被实现体现的是:”like a”的关系,接口中定义的是该继承体系的扩展功能。比如人类通常都有吃饭、睡觉、喝水等习惯,这些习惯就可以抽象出来一个抽象类,然后不同的人类用不同的继承体系去继承,得到相应的子类,然而,有一些人可能会编程,其他人可能会美术等,可能有一些扩展功能需要实现,那么这些扩展功能就不是统一所有人都会的,所以可以采用接口来定义一个编程或美术,然后相应的子类去实现这些接口就行了。

(2)接口的特点

    A. 接口用关键字interface修饰:interface 接口名 {};
    B. 类实现接口用implements修饰:class 类名 implements 接口名 {};
    C. 接口不能实例化;
    D. 接口的实现类,可以是一个抽象类,也可以是一个具体类,具体类必须重写接口中的所有抽象方法。

(3)接口的成员特点

    A. 成员变量:只能是常量,默认修饰符:public static final;
    B. 构造方法:没有构造方法;
    C. 成员方法:只能是抽象的,默认修饰符:public abstract。

(4)类与类,类与接口,接口与接口
    
    A. 类与类:继承关系,只能单继承,可以多层继承;
    B. 类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时,实现多个接口;
    C. 接口与接口:实现关系,可以单实现,也可以多实现。

(5)接口的一个例子

/*
	猫狗案例,加入跳高的额外功能
	
	分析:从具体到抽象
		猫:
			姓名,年龄
			吃饭,睡觉
		狗:
			姓名,年龄
			吃饭,睡觉
			
		由于有共性功能,所以,我们抽取出一个父类:
		动物:
			姓名,年龄
			吃饭();
			睡觉(){}
			
		猫:继承自动物
		狗:继承自动物
		
		跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
		接口:
			跳高
			
		部分猫:实现跳高
		部分狗:实现跳高
	实现;
		从抽象到具体
		
	使用:
		使用具体类
*/
//定义跳高接口
interface Jumpping {
	//跳高功能
	public abstract void jump();
}

//定义抽象类
abstract class Animal {
	//姓名
	private String name;
	//年龄
	private int age;
	
	public Animal() {}
	
	public Animal(String name,int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	//吃饭();
	public abstract void eat();
	
	//睡觉(){}
	public void sleep() {
		System.out.println("睡觉觉了");
	}
}

//具体猫类
class Cat extends Animal {
	public Cat(){}
	
	public Cat(String name,int age) {
		super(name,age);
	}
	
	public void eat() {
		System.out.println("猫吃鱼");
	}
}

//具体狗类
class Dog extends Animal {
	public Dog(){}
	
	public Dog(String name,int age) {
		super(name,age);
	}
	
	public void eat() {
		System.out.println("狗吃肉");
	}
}

//有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
	public JumpCat() {}
	
	public JumpCat(String name,int age) {
		super(name,age);
	}

	public void jump() {
		System.out.println("跳高猫");
	}
}

//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
	public JumpDog() {}
	
	public JumpDog(String name,int age) {
		super(name,age);
	}

	public void jump() {
		System.out.println("跳高狗");
	}
}

class InterfaceTest {
	public static void main(String[] args) {
		//定义跳高猫并测试
		JumpCat jc = new JumpCat();
		jc.setName("哆啦A梦");
		jc.setAge(3);
		System.out.println(jc.getName()+"---"+jc.getAge());
		jc.eat();
		jc.sleep();
		jc.jump();
		System.out.println("-----------------");
		
		JumpCat jc2 = new JumpCat("加菲猫",2);
		System.out.println(jc2.getName()+"---"+jc2.getAge());
		jc2.eat();
		jc2.sleep();
		jc2.jump();
		
		//定义跳高狗并进行测试的事情自己完成。
	}
}

    3. 接口和抽象类的区别


(1)成员区别

    A. 抽象类:第一,成员变量:可以变量,也可以常量;第二,构造方法:有;第三,成员方法:可以抽象,也可以非抽象。
    B. 接口:第一,成员变量:只可以常量;第二,构造方法:无;第三,成员方法:只可以抽象。

(2)关系区别

    A. 类与类:继承关系,只能单继承,可以多层继承;
    B. 类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时,实现多个接口;
    C. 接口与接口:实现关系,可以单实现,也可以多实现。

(3)设计理念区别

    A. 抽象类被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能;
    B. 接口被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能。

    总之,接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。另外,实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。 还有,接口可以实现多重继承,而一个类只能继承一个超类,但可以通过继承多个接口实现多重继承,接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。抽象类是模板,接口是规范。抽象方法是必须实现的方法。就象动物都要呼吸。但是鱼用鳃呼吸,猪用肺呼吸。动物类要有呼吸方法。怎么呼吸就是子类的事了。
现在有很多讨论和建议提倡用interface代替abstract类,两者从理论上可以做一般性的混用,但是在实际应用中,他们还是有一定区别的。抽象类一般作为公共的父类为子类的扩展提供基础,这里的扩展包括了属性上和行为上的。而接口一般来说不考虑属性,只考虑方法,使得子类可以自由的填补或者扩展接口所定义的方法,就像JAVA王子所说的事件中的适配器就是一个很好的应用。用一个简单的例子,比如说一个教师,我们把它作为一个抽象类,有自己的属性,比如说年龄,教育程度,教师编号等等,而教师也是分很多种类的,我们就可以继承教师类而扩展特有的种类属性,而普遍属性已经直接继承了下来。而接口呢,还是拿教师做例子,教师的行为很多,除了和普通人相同的以外,还有职业相关的行为,比如改考卷,讲课等,我们把这些行为定义成无body的方法,作为一个集合,它是一个interface。而教师张三李四的各自行为特点又有不同,那么他们就可以扩展自己的行为body。从这点意义上来说, interface偏重于行为。总之,在许多情况下,接口确实可以代替抽象类,如果你不需要刻意表达属性上的继承的话。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值