文章目录
1.子类与父类
子类也是类,它的定义形式与一般类的定义形式极其相似,其格式为:
[public] class SubClassName extends SuperClassName{
//ClassBody
}
1.子类是父类的继承。Java中的继承分为类的继承和接口的继承两种,类的继承只支持**单继承**;而接口的继承可以是**多重继承**。
子类继承了父类中可访问的数据域和方法(构造方法除外),在子类中就不用再定义父类中这些已有的数据域和方法了,从而提高了代码的可重用性。
2.子类是父类的扩展,不是父类的子集:子类可以在父类的基础上添加自己的数据域和方法,者对父类中定义的数据域和方法重新定义。
3.子类和父类的关系是"is-a"关系:如果要在一个父类的基础上扩展生成一个子类,要确保二者存在“is-a”关系。如:Apple is a Fruit。
4.Java的类按继承关系形成树形结构这个树形结构中,根节点是Object类(Object是java.lang包中的类),即Object是所有类的祖先类。
5.除了Object类,每个类都有且仅有一个父类,一个类可以有多个或零个子类。如果一个类(除了Object类)的声明中没有使用extends关键字,
这个类被系统默认为是Object的子类,即类声明"class A"与"class A extends Object"是等同的。
2.子类的继承性
子类的继承性:
1.类可以有两种重要的成员:数据域和方法。子类的成员中有一部分是子类自己声明定义的,另一部分是从它的父类继承的。
2.子类继承父类的数据域就是把继承来的数据域作为自己的一个数据域,就好象它们是在子类中直接声明一样,可以被子类中自己定义的任何方法操作。
3.所谓子类继承父类的方法就是把继承来的方法作为子类中的一个方法,就好象它们是在子类中直接定义了一样,可以被子类中自己定义的任何方法调用。
特别提示 :
1.并不是所有的父类成员都可被子类继承,例如父类中用private修饰的成员在该类之外都不允许访问,因此其子类也不能继承。
2.子类只能继承父类中除构造方法、不可访问成员之外的所有成员,只有这些成员才是子类的继承成员。
子类的继承性:
3.隐藏、覆盖与重载
当在**子类中新添加的数据域**与父类中的数据域同名、**子类中新添加的静态方法**与父类中的静态方法**同名同参同返回值类型**
(或属于父类返回值类型的子类)时,父类中的数据域与静态方法在子类中也将被隐藏起来
1.在子类中,如果直接引用这些同名的数据域与静态方法,则引用的是子类中定义的数据域与静态方法。
2.当在子类中要引用父类中的同名的数据域与静态方法时,可以通过super关键字(表示当前类的父类对象引用变量)来引用;
对父类中被隐藏的静态方法,也可通过父类名.静态方法引用。
父类的成员变量的隐藏示例
class SuperClass{
int x,y;
static void getx(){ }
}//父类
class SubClass extends SuperClass{
int x,y;
SubClass(int x,int y){
this.x=x; this.y=y; super.x=x+10;super.y=y+10;
}//子类
void getXY(){
System.out.println(“SubClass’s x is ”+x);
System.out.println(“SuperClass’s x is ”+super.x);
super.getx(); getx();
}
static void getx(){ }
}
public class Ch9_1{
public static void main(String[] args){
SubClass sub=new SubClass(10,10);
sub.getXY();
}
}
3.1.隐藏
静态方法的隐藏:在子类中定义了与父类中同名同参同返回值类型(或属于
父类返回值类型的子类)的静态方法。
3.2. 覆盖(重写)
实例方法的覆盖(重写):在子类中定义了与父类中同名同参同返回值类型(或属于
父类返回值类型的子类)的实例方法。
若要在子类中引用父类中覆盖的实例方法,可以通过关键字super来完成。
方法覆盖的说明:
1.子类不能覆盖父类中的final方法,否则会编译出错。
2.子类必须覆盖父类中的abstract方法,否则子类也必须是抽象类;父类的非抽象方法可以覆盖为抽象方法。
3.父类中被覆盖的方法的返回值类型如果是基本数据类型,则子类中覆盖的方法的返回类型应与父类中被覆盖的方法的返回值类型相同;
如果父类中被覆盖的方法的返回值类型如果是引用类型,则子类中覆盖的方法的返回类型应与父类中被覆盖的方法的返回值类型相同或者是其子类。
4.子类中覆盖的方法不能缩小父类中被覆盖的方法的访问权限,只能保持或者扩大原有访问权限。
5. 父类的实例方法仅当可访问时才能被覆盖。因为私有方法不能在定义它的类外被访问,所以它不能被覆盖。如果子类中定义的方法在父类中是私有的,那么这两个方法实际上没有联系,不能称为覆盖。
6. 与实例方法一样,静态方法也能被继承,但是静态方法不能被覆盖。如果父类中定义的静态方法在子类中重新被定义,父类中定义的静态方法将被隐藏;前面的1-5条对静态方法同样适用。
7. 父类的构造方法不能被继承,也谈不上被覆盖。
3.3. 重载
重载:在子类或者同一个类中,定义了(与父类)同名不同参的成员方法
(静态方法和实例方法都允许重载)
父类构造方法的调用:
父类的构造方法不能被子类继承,也无所谓被覆盖。因为构造方法的名称总是要与当前类名相同。子类中的构造方
法是新创建的,而不是继承而来的,子类不能直接通过父类的一个构造方法名调用父类的一个构造方法,而是通过关键
字super调用父类的一个构造方法。
同名问题小结(非常重要!!!)
1.子类中的构造方法与父类中的构造方法--------------------------------没有继承关系
2.子类中的数据域、成员方法与父类中可访问的数据域、成员方法不同名-------继承
3.子类中的数据域与父类中可访问的数据域同名---------------------------隐藏
4.子类中的静态方法与父类中可访问的静态方法同名同参同返回值类型---------隐藏
5.子类中的静态方法与父类中可访问的静态方法同名同参不同返回值类型-------可能错误
6.子类中的静态方法与父类中可访问的静态方法同名不同参------------------重载
7.子类中的实例方法与父类中可访问的实例方法同名同参同返回值类型---------覆盖
8.子类中的实例方法与父类中可访问的实例方法同名同参不同返回值类型-------可能错误
9.子类中的实例方法与父类中可访问的实例方法同名不同参------------------重载
10.子类中的实例方法与父类中可访问的静态方法同名同参同返回值类型--------错误
4.super 关键字
如果在子类中要调用父类中的成员,可用super完成。有如下作用
1> 在子类中用来调用父类中被隐藏的数据域;
2> 在子类中用来调用父类中被隐藏的静态方法和被覆盖的实例方法
3> 在子类中用来调用父类中的构造方法,如super(); super(参数);
注:子类访问父类的静态成员还可以用: 父类名.静态成员
5.final 关键字
final 常用来修饰常量,也可用来修饰类、方法和变量
1> final修饰的类称为终极类,不能被扩展,所以不能做父类。例如String就是final类。
2> final修饰的方法称为终极方法,在其子类中不能被覆盖或隐藏。
3> 变量经final修饰就成了常量了,其值不能被修改
6.上转型对象
对象类型转换原则:
1.同个类的不同对象引用变量之间可以相互赋值;
2.子类的对象引用变量可以直接赋值给父类的对象引用变量;
3.父类的对象引用变量不一定可以赋值给子类的对象引用变量,如要转换必须确保转换的对象
是子类的一个实例,如果父类的对象不是子类的一个实例,则转换时会出错;
4.没有继承关系的不同类的对象引用变量之间不能相互转换。
假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,称对象a是对象b的上转型对象。比如:
A a = new B();
或
A a;
B b=new B();
a=b;
上转型对象应用示例
例 : A x=new B(); // 设B为A的子类,设B对A中的变
量i进行了隐藏,B对A中的方法getX()进行了覆盖
System.out.println(x.i);
//此时x的数据类型为A,打印A中定义的变量x的i
值;
System.out.println(x.getX());
//此时x引用的对象为B,调用B中定义的方法
getX();
上转型对象的使用小结
1.上转型对象不能访问子类新增的数据域;不能直接访问子类新增的方法(子类中定义的覆盖、隐藏方法不算新增)。
2.上转型对象可以访问子类从父类继承来的数据域、方法或子类中对父类覆盖重写的实例方法,但不能直接访问子类中对父类隐藏重写的静态方法和对父类隐藏定义的数据域。
3. 如果子类覆盖了父类的某个实例方法后,当用上转型对象调用这个实例方法时,一定是调用子类中的这个实例方法。
4. 如果子类隐藏了父类的某个静态方法后,当用上转型对象调用这个静态方法时,一定是调用父类中的这个静态方法,而不是子类中的这个静态方法。
5. 子类从父类继承来的方法如果没有被覆盖或隐藏,此方法中如果存在成员变量调用,则此调用是针对父类的成员变量的调用。
6. 上转型对象即使采用父类做一个强制转换,所访问到的被覆盖的实例方法依旧是子类的,
7. 例如:
A a = new B(); //B是A的子类
a.getX(); //getX()是B中对A中的实例方法getx()的覆盖
((A)a).getX(); //结果与a.getX();等同
7.抽象类abstract
Java抽象类的定义是通过关键字abstract来修饰的。其格式为:
[public] abstract class ClassName{......}
其中:abstract是声明抽象类的关键字,class是定义类的关键字,ClassName是类名,大括号内的省略号表示类体部分。
抽象类的成员可以是常量、实例变量、静态变量、构造方法、静态方法、实例方法,还可以是可访问的抽象实例方法。
但不能包含静态(static)的抽象方法、私有(private)的抽象方法、final抽象方法)
关于抽象类的几点说明:
1.定义抽象类的目的是用于描述一个抽象的概念,它不能用于实例化对象。因此,常通过抽象类定义一个基本骨架,由其派生出的子类来实现具体的功能。
派生出的子类可以是抽象类,也可以是非抽象的类,即一般的类。
2.如果由抽象类派生出一个非抽象的子类,则在子类中必须覆盖掉父类(抽象类)中
所有的抽方法并加以实现,否则,只能将子类定义为抽象类。
3.抽象类虽然不能实例化对象,但可以用来作为父类来声明抽象类类型的变量,由该变量可
引用此抽象类的某个非抽象子类的对象,这在多态性的实现中经常用到。
4.抽象方法只能出现在抽象类中,在非抽象类中不能定义抽象方法。
5.static、private和final修饰符不能用来修饰抽象类和抽象方法。
6.子类可以定义为抽象类,即使它的父类是非抽象类。
7.子类可以覆盖父类的方法,即使被覆盖父类的方法是具体的,也可将其声明为抽象的,
当然这种情况下子类必须声明为抽象的,一般这种情况比较少见。
8.接口
8.1.接口定义
格式定义:
[public] interface 接口名称{
//静态常量及抽象方法
}
注意:在Java接口中,编译器将常量的定义默认为public static final类型的静态常量,不论是否使用了这些修饰符,它都是这样处理的。
所以在定义常量时,可以只给出其数据类型说明和常量名,同时,定义时要为每个常量都赋值。因为成员方法都是抽象的,在定义成员方
法时也可以省略关键字abstract,它默认也是抽象的.
public interface T{
public static final int K=1;
public abstract void p();
}
等价于
public interface T{
int K=1;
void p();
}
接口定义注意事项:
1.接口内方法的定义必须是公有和抽象的,如果没有包括这些限定符,它们将被自动转换为公有和抽象的。
2.不能在接口内将方法声明为私有(private)或保护的(protected)。
3.接口内定义的常量必须声明为公有、静态和final,或者不使用限定符
8.2.接口的继承
类仅支持单继承,而接口既支持单继承,也支持多重继承。通过继承,一个接口可以继承父接口中的所有成员。接口之间的继承也是通过关键字extends来说明的。
public interface SubMathInterface extends MathInterface, PhysicalInterface{
double minuteToRadian();//分转换为弧度
double RadianToMinute();//弧度转换为分
double secondToRadian();//秒转换为弧度
double radianToSecond();//弧度转换为秒
}
/*通过继承,在子接口SubMathInterface中不仅有此处定义的四个方
法,而且也继承了父接口MathInterface、PhysicalInterface中的所
有常量和方法.*/
8.2.接口的实现
在Java中,要让接口发挥其功能,需定义一个普通的类,在这个类中要覆盖掉接口中的所有方法,
以便将其实现,称为该类对接口的实现,实现接口是通过关键字implements来说明的。
注:定义一个类来实现接口时,需要在类中覆盖掉接口中的所有方法,不能有选择地实现其中的某些方法,
否则只能将这个类定义成一个抽象类。
一个类在实现多个接口时,如果两个接口中定义了名称相同的方法,可分三种方式处理:
1. 如果两个方法的方法头相同,则可在类中用一个方法进行实现,其定义可满足两个接口;
2. 如果两个方法只是名称相同,参数不同,则在类中分别进行重载即可;
3. 如果两个方法方法名称、参数列表相同,仅是返回值类型不同,
则在类中无法创建一个能满足两个接口的方法,需要对所实现的接口进行修改。