继承用关键字extends来实现,例如:
class A{
}
class B extends A{
}
继承的优点:
继承可以提高代码的复用性。
最重要的,因为继承的存在,Java的另一大特性多态才得以实现。
类与类之间的继承会产生一个很有意思的继承体系,就像一个family-tree一样。同时在使用继承时,一定要弄清楚继承体系中成员之间的关系,否则你的程序一定会非常混乱。
继承体系中成员变量的关系:
父类中如果存在被private修饰的变量,则该变量不会被子类继承到,而仅在父类中有效,当存在被protected和public或子父同包时有默认修饰符的变量时都会被子类继承到,这样子类就不用再创建这些成员变量而可以直接访问他们了。
当子类中存在和父类中相同的成员变量时,若在子类中使用该变量则默认使用的是子类中的变量,若想区分是父类中的变量还是子类中的变量可以用this或super来表示子类或父类中的成员变量,一般情况下,都要用this或super把子父类中重名的变量区分,提高代码的可读性。例如:
class A{
int x = 8;
}
class B extends A{
int x = 10;
public void print(){
System.out.println(this.x);
System.out.println(super.x);
}
}
public class HelloWorld {
public static void main(String []args){
B b = new B();
b.print();
}
}
输出结果:10
8
继承体系中成员函数的关系:
和成员变量一样,私有函数不会被子类继承到。(其他权限)父类中的函数子类可以直接使用,当子类中的函数功能不符合子类的要求时,子类要重写父类的函数,当子类复写了父类中的函数时,子类对象再掉用该方法就是调用子类自己的复写父类的方法而不是父类中的方法了,这也是Java中函数的另一个特性:重写。
子类重写父类函数时要注意一下两点:
1.当子类重写父类方法时,要保证子类中该方法的访问权限大于或等于父类中该方法的访问权限,否则会出现编译时错误。例如:
class A{
int x = 8;
public void print(){
}
}
class B extends A{
int x = 10;
private void print(){ //编译时错误
System.out.println(this.x);
System.out.println(super.x);
}
}
2.当父类中的方法为静态方法时,如果子类要重写该方法则子类中的该方法也必须是静态方法。例如:
class A{
int x = 8;
public void print(){
}
public static void func(){
}
}
class B extends A{
int x = 10;
public void print(){
System.out.println(this.x);
System.out.println(super.x);
}
public static void func(){ //静态方法
System.out.println("static");
}
}
继承体系中构造函数之间的关系:
下面先看一个小例子:
class A{
A(){
System.out.println("constructor A");
}
}
class B extends A{
B(){
System.out.println("constructor B");
}
}
public class HelloWorld {
public static void main(String []args){
new B();
}
}
结果为:constructor A
constructor B
从结果中可以看到在创建子类对象时首先调用父类的构造方法,这是因为在子构造器的第一行有一条隐士的语句:super();
那么为什么子类要调用父类的构造函数呢?
因为子类可以共享父类的数据,那么子类就必须先查看父类是如何对这些数据进行初始化的,所以,子类初始化时要先访问一下父类中的构造函数。
注意:当父类中有默认或者无参构造函数时,系统会自动在子类的构造函数的第一行添加super();语句来调用父类构造函数,那么当父类中没有无参构造函数时,子类就不能使用默认构造函数而是手动创建构造函数并在构造函数内的第一行加入super(参数列表);语句,来使子类创建对象是能狗调用父类构造函数。当子类中有多个构造函数时,至少有保证有一个构造函数可以直接访问父类构造函数,而其他构造函数可以通过直接或间接的形式访问父类构造函数,例如:
class A{
A(String s){
System.out.println("constructor A");
}
}
class B extends A{
B(String b1){
super(b1);
System.out.println("constructor B");
}
B(String b2,String b3){
this(b2);
}
}
要保证每一个子类构造函数都能直接或间接的访问到父类构造函数。
final关键字
final关键字是程序设计中经常用到的,他可以修饰类,函数,变量,当他们被fina修饰后就回有不同的意义了。
final类:
被final修饰的类不能被继承,当一个类中的描述是能够很好的独立完成一些事情,而不需要其他类进行继承补充时,就被定义为final,同时这也是防止当中方法被重写。
final方法:被final修饰的方法不能被重写,这个很好理解了。
final变量:final既可以修饰成员变量也可以修饰局部变量,修饰变量时,表示这个变量不能被修改,只可以被赋值一次,就相当于一个常量的存在。注意:当final修饰成员变量时一定要保证在构造函数调用完成前,对其进行初始化,否则会出现编译时错误,例如;
public class HelloWorld {
final int x;
public HelloWorld(){
}
}
这就会出现编译时错误,
public class HelloWorld {
final int x; //final int x = 0
public HelloWorld(){
x = 0;
}
}
抽象类:(abstract class)
抽象类是Java面向对象的一个非常具体的体现,Java程序设计中,不断的抽取事物的共性信息,用抽象类来表示这些信息,并让子类来完成具体的实现。
Java中类可以是抽象的,方法也可以是抽象的,但抽象方法一定在抽象类当中存在,但是抽象类中可以存在非抽象方法(抽象方法不能用private修饰)。
当一个类继承了一个抽象类,那它就必须复写父类中所有的抽象方法,否则它也是一个抽象类。