一、抽象类
1、概念
在继承的层次结构中,每个新的子类都使类变得更加明确和具体。如果从一个子类向父类追溯,类就会变得更通用、更加不明确。类的设计应该确保父类包含它的子类的共同特征。有时候,一个父类设计得非常抽象,以至于它没有任何具体的实例,这样的类称为抽象类。
在类的头部使用abstract修饰符表示该类为抽象类。
abstract修饰符:
(1)abstract修饰的类为抽象类,此类不能有对象,即无法对此类进行实例化;
(2)abstract修饰的方法称为抽象方法,此方法不能有方法体,即什么内容都不能有。
在UMI图形记号中,抽象类和抽象方法的名字用斜体表示。
2、抽象方法的格式
权限修饰符 abstract 返回值类型 方法名(形参);
public abstract void Circle0bject();
public abstract void Rectangle0bject();
3、抽象类的格式
public abstract class Geometric0bject {
public abstract void Circle0bject();
public abstract void Rectangle0bject();
}
以上代码定义了一个叫做Geometric0bject的抽象类,其中含有Circle0bject()和Rectangle0bject()两个抽象方法。
注意:抽象方法不能有方法体,在方法后面加一个大括号而里面什么都不写也是不行的。
4、抽象的使用
定义了一个Geometric0bject类之后再定义一个Circle类:
public class Circle extends Geometric0bject{
@Override
public void Circle0bject() {
System.out.println("几何对象为圆");
}
@Override
public void Rectangle0bject() {
System.out.println("几何对象不为矩形");
}
}
定义了一个Geometric0bject类之后再定义一个Rectangle类:
public class Rectangle extends Geometric0bject{
@Override
public void Rectangle0bject() {
System.out.println("几何对象为矩形");
}
@Override
public void Circle0bject() {
System.out.println("几何对象不为圆");
}
}
注意:当一个类继承抽象类的时候,这个类必须去重写所继承的抽象类的抽象方法。
在Circle和Rectangle这两个类都含有了 Circle0bject()和Rectangle0bject()这两个方法,但是它们的方法体却不一样。
JVM在运行时根据调用该方法的实际对象的类型来动态地决定调用哪一个方法。
eg:
public class TestCircle {
public static void main(String[] args) {
// TODO Auto-generated method stub
Circle s=new Circle();//创建子类对象
s.Circle0bject();//调用Circle0bject方法
s.Rectangle0bject();//调用Rectangle0bject方法
}
}
eg:
public class TestRectangle {
public static void main(String[] args) {
// TODO Auto-generated method stub
Rectangle s=new Rectangle();//创建子类对象
s.Rectangle0bject();//调用Rectangle0bject方法
s.Circle0bject();//调用Circle0bject方法方法
}
}
5、有关抽象类的几点说明
(1)抽象方法不能包含在非抽象类中。如果抽象父类的子类不能实现所有的抽象方法,那么子类也必须定义为抽象的。换句话说,在继承自抽象类的非抽象子类中,必须实现所有的抽象方法。还要注意到,抽象方法是非静态的。
(2)抽象类不能使用new操作符来初始化。但是,仍然可以定义它的构造方法,这个构造方法在它的子类的构造方法中使用。例如,Geometric0bject类的构造方法在Circle类和Rectangle类中调用。
(3)包含抽象方法的类必须是抽象的。然而,可以定义一个不包含抽象方法的抽象类。这个抽象类用于作为定义新子类的基类。
(4)子类可以重写父类的方法并将它定义为抽象的。这很少见,但是它在当父类的方法实现在子类中变得无效时是很有用的。在这种情况下,子类必须定义为抽象的。
(5)即使子类的父类是具体的,这个子类也可以是抽象的。例如,0bject类是具体的,但是它的子类如Geometric0bject可以是抽象的。
(6)不能使用new操作符从一个抽象类创建一个实例,但是抽象类可以用作一种数据类型。因此,下面的语句创建一个元素Geometric0bject类型的数组是正确的:
Geometric0bject[] object=new Geometric0bject[10];
然后可以创建一个Geometric0bject的实例,并将它的引用赋值给数组:
object[0]=new Circle();
二、接口
1、概念
接口是一种与类相似的结构,用于为对象定义共同的操作,指明相关或不相关类的对象的共同行为。
使用关键字interface来完成
2、注意
(1)接口中所有的数据域默认都是public static final
(2)接口中的所有方法默认都是public abstract
(3)使用关键字implements让对象所属的类来实现这个接口,实现接口与类的继承是相似的。
(4)不能使用new操作符创建接口的实例。
(5)接口没有构造方法
3、例题分析
使用Edible接口来指定一个对象是否是可食用的
public interface Edible {
public abstract String howToEat();
}
public class TestEdible {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object[] objects= {new Tiger(),new Chicken(),new Apple()};
for(int i=0;i<objects.length;i++) {
if(objects[i] instanceof Edible) {
System.out.println(((Edible)objects[i]).howToEat());
}
if(objects[i] instanceof Animal) {
System.out.println(((Animal)objects[i]).sound());
}
}
}
}
abstract class Animal{
private double weight;
public double getWeight() {
return weight;
}
public void setWeight() {
this.weight=weight;
}
public abstract String sound();
}
class Chicken extends Animal implements Edible{
@Override
public String howToEat() {
return "Chicken: Fry it";
}
@Override
public String sound() {
return "Chicken: cock-a-doodle-doo";
}
}
class Tiger extends Animal{
@Override
public String sound() {
return "Tiger: RROOAARR";
}
}
abstract class Fruit implements Edible{
}
class Apple extends Fruit{
@Override
public String howToEat() {
return "Apple: Make apple cider";
}
}
class Orange extends Fruit{
@Override
public String howToEat() {
return "Orange: Make orange juice";
}
}
这个例子使用了多个类和接口。它们的继承关系如图所示
Animal类定义了属性weight及其获取方法和设置方法(第17~25行),还定义了sound方法(第27行)。sound是一个抽象方法,将被具体的animal类所实现。
Chicken类实现了Edible接口以表明小鸡是可食用的。当一个类实现接口时,该类实现定义在接口中的所有方法。Chicken类实现了howToEat方法(第32~34行)。Chicken也继承Animal类并实现sound方法(第37-39行)。
Fruit类实现了Edible。因为它没有howToEat方法,所以Fruit必须定义为abstract(第49行)。Fruit的具体子类必须实现howToEat方法。Apple类和Orange类实现了howToEat方法(第54和61行)。
main方法创建由Tiger、Chicken和Apple类型的三个对象构成的数组(第4行),如果某元素是可食用的,则调用howToEat方法(第7行),如果某元素是一种动物,则调用sound方法(第10行)。
本质上,Edible接口定义了可食用对象的共同行为。所有可食用的对象都有howToEat方法。
三、接口与抽象类
1、一个类只能继承一个父类(单继承),可以“多对一”,不允许“一对多”,但是一个类可以实现多个接口(允许接口做多重继承)。
举个简单的例子:
public interface Eat {
public abstract void ioEat();
}
public interface Study {
public abstract void ioStudy();
}
public class Person implements Eat,Study{
@Override
public void ioEat() {
System.out.println("人需要吃饭");
}
@Override
public void ioStudy() {
System.out.println("人需要学习");
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person s=new Person();
s.ioEat();
s.ioStudy();
}
}
以上代码定义了两个接口分别是Eat和Study,以及一个类Person。定义的Person类实现了这两个接口。
2、利用关键字extends,接口可以继承其他接口。
3、接口可以继承其他接口但不能继承类,一个类可以继承它的父类的同时实现多个接口。
4、所有的类共享同一个根类Object,但是接口没有共同的根。如果一个类实现了一个接口,那么这个接口就类似于该类的一个父类。