文章目录
一、类的继承
(1)继承的概念
正如生活中的实例一样,任何事物所属的类型不是单一的,例如狮子属于动物,又属于食肉动物。而羚羊也属于动物,但属于食草动物。不论食肉动物还是食草动物,都有动物的特性,归属于动物这一类。这就需要用到继承来创建具有等级层次的类。
继承就是子类通过继承来获得父类的特性、行为,使子类对象拥有父类的作用域和方法,使子类具有和父类相同的行为。
简单来说,父类更通用,子类更具体。
(2)继承格式
class 父类{
}
class 子类 extends 父类{
}
代码示例:
public class father {
//父类
int age;//父类的成员变量
double height,weight;
public father(){
}//父类无参构造器
public father(int age,double height,double weight){
//父类有参构造器
this.age=age;
this.height=height;
this.weight=weight;
}
//父类的方法
public void getup(){
System.out.println("起床了");
}
public void print(){
System.out.println("年龄:"+age+",身高:"+height+"cm,体重:"+weight+"kg");
}
}
public class son extends father{
//子类 继承 父类
//没有写成员变量 是因为子类已经从父类继承了成员变量
public son(){
}//子类无参构造器
public son(int age,double height,double weight){
//子类有参构造器 用super调用父类构造器
super(age,height,weight);
}
}
public class javaexample {
//测试类
public static void main(String[] args) {
son xiaoming = new son(15,170,60);//创建子类对象
xiaoming.getup();//调用父类方法
xiaoming.print();//调用父类方法 可以看到继承的成员变量
}
}
//三个类写在了同一个包内
结果如下:
如代码所示,虽然父类中可能写了很多成员变量及方法,但是子类中的代码十分简洁明了,当有数量庞大的类中拥有相同的代码块时,可以将相同部分提取出来组成一个父类。这样不仅能提高代码可读性,还增加了代码的复用性,也方便了以后的维护使用。
(3)继承类型
Java支持单继承和多重继承,但不支持多继承。即A类可以继承B类;可以A类继承B类,C类继承B类(注意不能形成闭环);也可以B类和C类都继承A类。但不能继承多个类,即A类不能同时继承B类和C类。(亲爹只能有一个)
(4)继承的特点
1、子类拥有父类的非 private 属性、方法。(不包括构造方法)
2、子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
3、子类可以用自己的方式实现父类的方法。(方法的重写)
4、提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
(5)关键字
extends关键字
extends用于实现类的继承。类的继承是单一的,也就是说一个子类只能拥有一个父类,所以 extends 只能继承一个类。
所有的类都是继承于 java.lang.Object,当一个类没有extends关键字,则默认继承Object类,这个类在 java.lang 包中,所以不需要 import。代码示例如(2)
super关键字
如同this一样,super指的是超类,即父类。this调用的是当前类的方法与成员变量和属性,super则调用继承的父类的方法和成员变量和属性。
值得注意的是,子类拥有的是父类非private的成员变量、属性和方法,但是可以调用的是父类非private的成员变量、属性、方法和构造方法。(构造方法是爹借给儿子的,不是继承)代码示例如(2)
(6)抽象类
用abstract修饰的类,具有类的一般作用,但是无法实例化,可以看作信息不足不足以实例化的类。抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。抽象类表示的是一种继承关系,一个类只能继承一个抽象类。
用(2)的代码稍作修改,进行示例:
public abstract class father {
//现在父类变成了抽象类
int age;//所有成员变量和属性都可以使用
double height,weight;
public father(){
}//无参和有参构造器都可以使用
public father(int age,double height,double weight){
this.age=age;
this.height=height;
this.weight=weight;
}
//普通方法也可以使用
public void getup(){
System.out.println("起床了");
}
public void print(){
System.out.println("年龄:"+age+",身高:"+height+"cm,体重:"+weight+"kg");
}
//抽象方法 没有方法体 ()后面直接跟分号
public abstract void walk();
}
public class son extends father{
//子类继承抽象类
public son(){
}//构造器任然可以调同父类构造器
public son(int age,double height,double weight){
super(age,height,weight);
}
//注意!必须重写抽象类中的抽象方法!
public void walk(){
System.out.println("走路");
}
}
public class javaexample {
public static void main(String[] args) {
//实例化子类对象 父类是抽象类 抽象类无法实例化
son xiaoming = new son(15,170,60);
//调用各个方法 都可以使用
xiaoming.getup();
xiaoming.print();
xiaoming.walk();
}
}
结果如下:
抽象方法和方法重写
抽象方法:如上面代码所示,抽象方法即用abstract修饰的方法,其只有修饰词、方法名和(),没有方法体。继承抽象类之后,必须重写抽象类中的抽象方法,除非声明自己也是抽象类才可以不重写。(抽象类继承抽象类)
方法重写:子类继承父类中的方法后,可以在自己的类中重新编写该方法,返回值和形参都不能改变。(外表不变,内心不同)
方法重写规则:
1、参数列表与被重写方法的参数列表必须完全相同。
2、返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类。
3、访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为protected。
4、父类的成员方法只能被它的子类重写。
5、声明为 final 的方法不能被重写。(留坑待填)
6、声明为 static 的方法不能被重写,但是能够被再次声明。(留坑待填)
7、子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
8、子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
9、重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。(留坑待填)
10、构造方法不能被重写。
11、如果不能继承一个类,则不能重写该类的方法。
重写和重载的区别
重载 | 重写 | |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可减少删除,不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
二、接口的继承
(1)接口的概念
上面讲到,Java中并不能让一个类继承多个类,但是当我们想要让一个类“一口吃成一个胖子”该怎么办?这时候可以使用接口。
接口是一种抽象类型,一个类通过继承一个接口,从而实现接口里所有的抽象方法。接口不是类,尽管二者编写方式很相似。类描述的是对象的属性和方法,而接口则包含类要实现的方法。
(2)接口的特点
1、接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有抽象方法。接口既是一种便利,也是一种约束。
2、接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
3、接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
4、接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
5、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
(3)接口和类的异同
相同之处:
1、一个接口可以有多个方法。
2、接口文件保存在 .java 结尾的文件中,文件名使用接口名。
3、接口的字节码文件保存在 .class 结尾的文件中。
4、接口相应的字节码文件必须在与包名称相匹配的目录结构中。
不同之处:
1、接口不能用于实例化对象。
2、接口没有构造方法。
3、接口中所有的方法必须是抽象方法。
4、接口不能包含成员变量,除了 static 和 final 变量。
5、严格意义上接口不是被类继承了,而是要被类实现。
6、接口支持多继承。
(4)接口和抽象类的区别
1、抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
2、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
3、 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
4、一个类只能继承一个抽象类,而一个类却可以实现多个接口。(干爹可以认多个)
(5)接口的声明
interface 接口名 [可选 extends 其他接口名]{
声明变量
抽象方法
}
代码示例:
public interface animal {
public void eat();//抽象方法
public void sleep();
}
interface lion extends animal{
//接口继承接口
public void hunt();//自己的抽象方法
}
(6)接口的实现
接口必须在一个类中实现,让这个类重写接口的所有抽象方法。
代码示例:
public interface animal {
public void eat();
public void sleep();
}
interface lion extends animal{
public void hunt();
}
public class lionking implements lion{
/*虽然只实现了lion接口,
但是lion继承了animal,
所以二者的抽象方法都需要重写
*/
public void eat(){
System.out.println("吃肉");
}
public void sleep(){
System.out.println("打盹");
}
public void hunt(){
System.out.println("打猎");
}
}
public class javaexample {
public static void main(String[] args) {
lionking simba=new lionking();//实例化类
simba.hunt();
simba.eat();
simba.sleep();//调用方法
}
}
//代码写在同一个包中
结果如下:
多接口继承
一个类只能继承一个父类,但是接口可以继承多个接口,extends后可以跟多个其他接口。
interface rabbit extends animal,furry,herbivorous……{
抽象方法1;
抽象方法2;
……
}