九、super 关键字
如果在子类中想使用被子类隐藏的成员变量和方法就可以使用关键字 super。
1.使用 super 调用父类的构造方法
子类不继承父类的构造方法,因此子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字 super 来表示,而且 super 必须是子类构造方法中的头一条语句。
如:
class Student
{ int number;
String name;
Student()
{
}
Student(int number,String name)
{ this.number=number;
this.name=name;
System.out.println("I am "+name+"my number is "+number);
}
}
class UniverStudent extends Student
{ boolean 婚否;
UniverStudent(int number,String name,boolean b)
{ super(number,name);
婚否=b;
System.out.println("婚否="+婚否);
}
}
public class Example5_10
{ public static void main(String[] args)
{ UniverStudent zhang=new UniverStudent(9901,"和晓林",false);
}
}
运行结果:
I am 和晓林 my number is 9901
婚否=false
如果在子类的构造方法中,没有明显地写出 super 关键字来调用父类的某个构造方法,那么默认有以下语句:
super();
即调用父类的不带参数的构造方法。
因此当在父类中定义多个构造方法时,应当包括一个不带参数的构造方法,以防子类省略 super 时出现错误。
2.使用 super 操作被隐藏的成员变量和方法
子类可以通过方法的重写隐藏继承的方法。如果用户在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字 super。如 super.x、super.play() 就是被子类隐藏的成员变量 x 和方法 play()。
注意:子类创建一个对象时,除了子类声明的成员变量和继承的成员变量要分配内存外(这些内存单元是属于子类对象的),被隐藏的成员变量也要分配内存,但该内存单元不属于任何对象,这些内存单元必须用 super 调用。方法同理。
当 super 调用隐藏的方法时,该方法中出现的成员变量是被隐藏的成员变量。
class Sum
{ int n;
double f()
{ double sum=0;
for(int i=1;i<=n;i++)
sum+=i;
return sum;
}
}
class Average extends Sum
{ double n; //子类继承的int型变量n被隐藏
double f()
{ double c;
super.n=(int)n; //子类double型变量n进行int转换运算,赋值给隐藏的int型变量n
c=super.f();
return c+n;
}
double g()
{ double c;
c=super.f();
return c-n;
}
public class Example5_11
{ public static void main(String[] args)
{ Average aver=new Average();
aver.n=100.5678;
double result1=aver.f();
double result2=aver.g();
System.out.println("result1="+result1);
System.out.println("result2="+result2);
}
}
运行结果:
result1=5150.5678
result2=4949.4322
不提倡子类隐藏可以继承的成员变量,但提倡重写 abstract 类中的 abstract 方法。这是因为 abstract 方法不会被分配入口地址,重写 abstract 方法不会付出额外的方法入口地址的开销。
十、接口
Java 不支持多继承性,即一个类只能有一个父类。为了克服单继承性的缺点,Java 使用了接口,一个类可以实现多个接口。
使用 interface 来定义一个接口,接口的定义和类的定义很类似,分为接口的声明和接口体。
1.接口的声明与使用
(1)接口声明
格式如下:
interface 接口的名字;
(2)接口体
包含常量定义和方法定义两部分。借口体中只进行方法的声明,不提供方法的实现。所以方法的定义没有方法体,如:
interface Printable
{ final int MAX=100;
void add();
float sum(float x,float y);
}
(3)接口的使用
一个类使用关键字 inplements,声明自己使用一个或多个借口。如果使用多个接口,用逗号隔开接口名,如:
类 Dog 使用接口 Etable 和接口 Sleepable:
class Dog entends Animal implements Eatable,Sleepable
如果一个类使用了一个接口,那么这个类必须为该接口的所有方法提供方法体。类在实现接口的方法时,方法的名字、返回类型、参数个数及类型必须与接口中的方法完全一致。而接口中的方法一定是 public abstract 方法,所以,类在实现接口方法时不仅要给出方法体,而且方法的访问权限一定要用 public 来修饰。接口的常量一定是 public static 常量。
接口体中只有 public static 常量和 public abstract 方法。
Java 为用户提供的接口都在相应的包中,通过 import 语句不仅可以引入包中的类,也可以引入包中的接口。如:
import java.io.*;
不仅引入了 java.io 包中的类,也同时引入了该包中的接口。
用户也可以自定义接口,一个 Java 源文件就是由类和接口组成的。
下例使用了一个接口:
interface Computable
{ int MAX=100;
int f(int x);
}
class China implements Computable
{ int number;
public int f(int x)
{ int sum=0;
for(int i=1;i<=x;i++)
{ sum+=i;
}
return sum;
}
}
class Japan implements Computable
{ int number;
public int f(int x)
{ return 66+x;
}
}
public class Example5_12
{ public static void main(String[] args)
{ China zhang;
Japan henlu;
zhang=new China();
henlu=new Japan();
zhang.number=991898+Computable.MAX;
henlu.number=941448+Computable.MAX;
System.out.println("number:"+zhang.number+"求和"+zhang.f(100));
System.out.println("number:"+henlu.number+"求和"+henlu.f(100));
}
}
类实现的接口方法以及接口中的常量可以被类的对象调用,且常量也可以使用类名或接口名直接调用。
接口声明时,如果关键字 interface 前加上 public 关键字,就称这样一个接口是一个 public 接口。public 接口可以被任何一个类实现。如果一个接口不加 public 修饰,就称作友好接口,友好接口可以被与该接口在同一包中的类声明实现。
如果父类实现了某个接口,那么子类也就自然实现了该接口,而不必再使用关键字 implements 声明实现这个接口。接口也可以被继承,即可以通过关键字 extends 声明一个接口是另一个接口的子接口。由于接口中的方法和常量都是 public 的,子接口将继承父接口中的全部方法和常量。
如果一个类声明实现一个接口,但没有实现接口中的所有方法,那么这个类必须是 abstract 类。如:
interface Computable
{ final int MAX=100;
void speak(String s);
int f(int x);
float g(float x,float y);
}
abstract class A implements Computable
{ public inf f(int x)
{ int sum=0;
for(int i=1;i<=x;i++)
{ sum+=i;
}
return sum;
}
}