抽象类就是不能使用new方法进行实例化的类,即没有具体实例对象的类。抽象类有点类似“模板”的作用,目的是根据其格式来创建和修改新的类。对象不能由抽象类直接创建,只可以通过抽象类派生出新的子类,再由其子类来创建对象。当一个类被声明为抽象类时,要在这个类前面加上修饰符abstract。
在抽象类中的成员方法可以包括一般方法和抽象方法。抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型、方法名称和所需的参数,没有方法体,也就是说抽象方法只需要声明而不需要实现。当一个方法为抽象方法时,意味着这个方法必须被子类的方法所重写,否则其子类的方法仍然是abstract的。
抽象类中不一定包含抽象方法,但是包含抽象方法的类一定要被声明为抽象类。抽象类本身不具备实际的功能,只能用于派生其子类,而定义为抽象的方法必须在子类派生时被重写。抽象类中可以包含构造方法,但是构造方法不能被声明为抽象。一般来说,由于不能够用抽象类直接创建对象,因此在抽象类内定义构造方法是多余的。
需要注意的是:
l 抽象类不能用final来修饰,即一个类不能既是最终类又是抽象类。
l abstract不能与private、static、final、native并列修饰同一个方法。
【例7-11】定义抽象类Animal,从抽象类派生具体子类Horse和Dog,实现父类的抽象方法。
//********** ep7_11.java **********
abstract class ep7_11_Animal{ //定义抽象类
String str;
ep7_11_Animal(String s){ //定义抽象类的一般方法
str=s;
}
abstract void eat(); //定义抽象方法
}
class ep7_11_Horse extends ep7_11_Animal{ //定义继承Animal的子类
String str;
ep7_11_Horse(String s){
super(s); //调用父类的构造方法
}
void eat(){ //重写父类的抽象方法
System.out.println("马吃草料!");
}
}
class ep7_11_Dog extends ep7_11_Animal{
String str;
ep7_11_Dog(String s){
super(s);
}
void eat(){
System.out.println("狗吃骨头!");
}
}
class ep7_11{
public static void main(String args[]){
ep7_11_Horse Horse1=new ep7_11_Horse("马");
ep7_11_Dog Dog1=new ep7_11_Dog("狗");
Horse1.eat();
Dog1.eat();
}
}
运行结果:
马吃草料!
狗吃骨头!
在例7-11中,动物是一个抽象的概念,由此概念可以派生出“马”和“狗”等具体的动物,所以将Animal声明为抽象类。由于每种动物都需要吃东西,就可以在父类中定义一个吃的方法eat,但每种动物吃的东西不同,没法给出统一的吃方法,所以把动物类Animal中的吃方法定义为抽象方法,而具体的eat方法由子类来完成。
需要注意的是:
语句:ep7_11_Animal a=new ep7_11_Animal()是非法的,因为抽象类不能实例化。
语句:ep7_11_Animal a=new ep7_11_Horse()是合法的,因为引用的是ep7_11_Horse类实例。
【例7-16】接口的继承。
//********** ep7_16.java **********
interface ep7_16_a{ //定义第1个接口
double pi=3.14;
abstract double area();
}
interface ep7_16_b{ //定义第2个接口
abstract void setColor(String c);
}
interface ep7_16_c extends ep7_16_a,ep7_16_b{ //接口的多重继承
abstract void volume();
}
class ep7_16_Cylinder implements ep7_16_c{ //以第3个接口实现类
double radius;
int height;
String color;
public ep7_16_Cylinder(double r,int h){
radius=r;
height=h;
}
public double area(){ //实现第1个接口的方法
return radius*radius*pi;
}
public void setColor(String c){ //实现第2个接口的方法
color=c;
System.out.println("形状的颜色:"+color);
}
public void volume(){ //实现第3个接口的方法
System.out.println("圆柱体的体积:"+area()*height);
}
}
class ep7_16{
public static void main(String args[]){
ep7_16_Cylinder One=new ep7_16_Cylinder(3.0,5);
One.setColor("红色");
One.volume();
}
}
运行结果:
形状的颜色:红色
圆柱体的体积:141.3
7.1 什么是继承?什么是多重继承和单继承?Java采用何种机制来实现多重继承?
7.2 什么是隐藏?什么是重写?二者有何区别?
7.3 子类会继承父类的所有方法和属性么?
7.4 在接口声明成员变量时,其变量在缺省情况下就是______、______和______。
7.5 对于接口的实现,不可以构造一个接口对象,但可以声明一个接口______。
7.6 在Java语言中所有的类都是直接或间接地继承______类而得到的。
7.7 在Java中一个父类可以有______个子类,一个类只能有______个直接父类。
7.8 关于抽象类,正确的是______。
A. 抽象类中不可以有非抽象方法
B. 某个非抽象类的父类是抽象类,则这个子类必须重载父类的所有抽象方法
C. 不能用抽象类去创建对象
D. 接口和抽象类是同一个概念
7.9 下面选项正确的是______。
A. 抽象类可以有构造方法
B. 接口可以有构造方法
C. 可以用new操作符操作一个接口
D. 可以用new操作符操作一个抽象类
7.10下面程序的运行结果是______。
class ex7_8_a{
void printMe(){
System.out.println("parent");
}
}
class ex7_8_b extends ex7_8_a{
void printMe(){
System.out.println("child");
}
void printAll(){
super.printMe();
this.printMe();
printMe();
}
}
class ex7_8{
public static void main(String args[]){
ex7_8_b x=new ex7_8_b();
x.printAll();
}
}
7.11 什么是包?如何创建和引用包中的类?
7.12 抽象类A和抽象类B的定义如下:
abstract class ex7_12_A{
abstract int getinfo(){
}
}
public class ex7_12 extends ex7_12_A{
private int a=0;
public int getinfo(){
return a;
}
public static void main(String args[]){
ex7_12 b=new ex7_12();
System.out.println(b.getinfo());
}
}
关于上述代码说明正确的是______。
A. 输出结果为0 B.通过编译但没有输出任何结果
C. 第5行不能通过编译 D. 程序第2行不能通过编译
7.13下面程序的运行结果是______
class ex7_13_A{
protected static int count=0;
public ex7_13_A(){
count++;
}
}
class ex7_13_B extends ex7_13_A{
public ex7_13_B(){
count++;
}
}
class ex7_13{
public static void main(String args[]){
ex7_13_B x=new ex7_13_B();
System.out.println("count="+x.count);
}
}
7.14 设计一个Student类,以一维数组存储一个班级的学生信息。要求:
(1)将Student设计成一个接口
(2)自定义一个包来管理所设计的类
7.15 什么是包?如何创建和引用包中的类?
7.16 定义一个接口,该接口中只有一个抽象方法getClassName()。设计一个类Horse,该类实现接口ClassName中的方法getClassName(),功能是获取该类的类名。