继承和抽象类
继承
继承概念和用法
-
继承是面向对象的三大特性之一
-
描述类的时候,我们如果发现几个类有重复的属性和方法我们就可以采用继承的方式来设计。
-
继承语法
使用extends关键字来继承
class 子类 extends 父类{
子类属性
子类方法
}
-
继承的特点
1.子类会把父类所有的属性和方法继承下来(暂时不考虑final)。
2.如果父类中包含了某些类中的共同的属性和行为,我们可以使用继承来设计程序。
3.子类使用extends关键字继承父类的共同属性以外,子类还可以有自己特有的属性或者方法。
4.父类更通用,子类更具体。
5.子类只能获得父类中的非private的属性,如果想要继承就得提供公共的set和get的方法。 私有的方法是无法继承下来的
6.java中只能做单继承,即每个类只能有一个直接父类
7.java支持多级继承
class A extends B{
}
class C extends A{
}
//学生是人类的一种,人类具有拥有姓名、性别、年龄等特征,吃饭的行为
//学生也有,学生可以继承人类的这些属性和行为,学生还有学习的行为
public class Person {//定义人类
public String name;//姓名
public String gender;//性别
public int age;//年龄
public void eat(){
System.out.println(name+"吃饭");
}
}
public class Student extends Person{//学生类
public void study(){
System.out.println(super.name+"在学习");
}
}
public class Test {
//测试类
public static void main(String[] args) {
Student s= new Student();
s.name = "张三";
s.eat();
s.study();
}
//张三吃饭
//张三在学习
}
继承的内存结构
总结:在类的继承结构中,如果创建一个子类的对象,那么在子类的对象的内部创建一个父类的对象,如果通过子类的对象访问属性的时候,子类中没有,就会到父类的对象中查找,如果调用方法的时候也是一样的,如果子类中没有,也会到父类中查找。
super关键字
1.子类通过默认构造器实例化的过程中父类的构造器先被调用,然后再调用子类的构造器,在子类构造器内部默认的调用super();
注意:如果父类带有有参数的构造器,并且没有显式的定义父类的默认构造器,默认构造器被覆盖,导致子类的构造器无法通过super()来做调用,就会编译报错,需要显式的定义父类的默认的构造器。
- 如果子类的构造器中调用了父类中的有参数的构造器,默认super()的调用就不会有了。不能在子类的构造器中调用两个super(…)
- super(…)的调用必须要放在方法的第一行。
- super可以表示父类的引用,我们可以使用super和this来区分父类和子类中同名的属性。
- 通过super访问父类成员的语法格式:
访问父类的构造方法:super(参数)
访问父类属性/方法:super.<父类属性/方法>
-
具有访问权限的限制,如无法通过super访问父类的private成员。
-
super只能出现在子类(子类的方法和构造方法)中,而不是其它位置。
重点:
-
理解super(…)对于父类构造器的调用
-
super表示子类内部的那个父类的对象的引用
this关键字
1.代表当前类的的指定实例的引用
2.可以区分同名的属性和局部变量
3.通过this可以调用同类中的构造器(this(), this(参数列表))
4.调用本类里面的属性, this.属性名,this.方法()
方法重写/覆盖(Overriding)
在子类继承父类时,子类的方法和父类的方法相同(访问修饰限制符, 返回值类型, 方法名, 参数列表),方法体不同。这种子类的方法将父类的方法覆盖叫做重写,也叫方法的覆盖。
方法名、参数列表、返回值类型相同,重写方法不能缩小被重写方法的访问权限。
重写和重载的区别:
-
重写(override):在父子类的继承中有相同的方法,唯一不同就是方法体,一般是父类的该方法满足不了子类的需求所以才发生重写。
-
重载(overload):重载是在同一个类中,有着相同的方法名但是参数的数据类型或者参数的个数不同这两个方法就是重载。重载的目的:节省类中的命名资源和提高代码的可读性。
public class Student extends Person{
public void study(){
System.out.println(name+"在学习");
}
public void eat(){//重写父类方法
System.out.println(name+"在吃鱼");
}
//张三在吃鱼
}
final关键字
-
如果final修饰在变量上,这个变量不能修改。
-
final修饰在属性上
权限修饰符 [static] final 数据类型 属性名 = 值;
属性名:一般采用大写,多个单词使用下划线来分隔。而且这种常量多定义在接口中。
如果final在属性上,要么直接给初始值, 要么在构造器中给初始化,如果存在多个构造器,每一个构造器里面都要有final这个属性的初始化。语法:
-
final修饰在方法上不能被复写
语法:
权限修饰符 final 返回值类型 方法名(参数列表){
方法体
}
-
修饰在类上
语法 final class 类名{
属性
方法
}
使用final来修饰的类是不可以被继承的。
抽象类
抽象类定义
在java中,当一个类的方法被abstract关键字修饰时,该方法称为抽象方法。抽象方法所在的类必须定义为抽象类。
当多个具体的实体类存在着共同的行为,但是有不同的表现,我们在父类继承过程中父类的方法具体实现不确定,但是能确定的是他们都有这种行为。我们要把这种行为方法作为抽象方法。
当一个方法被定义为抽象方法后,意味着该方法不会有具体的实现,而是在抽象类的子类中通过方法重写进行实现。
-
抽象类语法格式:abstract class<类名>{}
-
抽象方法语法格式:
[访问修饰符] abstract<返回类型><方法名>([参数列表]);
注意:抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类
抽象类的特点
1.抽象类不能被实例化。
2.抽象类必须被子类继承才能使用子类实例化。
3.继承了抽象类的非抽象类必须实现抽象类的所有抽象方法。
4.抽象类也可以继承抽象类,这样不需要实现父抽象类的方法。
abstract class Person{
//抽象的方法
public abstract void smoke();
}
abstract class Student extends Person{
public abstract void learn();
}
class Child extends Student{
public void learn(){
}
public void smoke(){
}
}
5.抽象类的抽象方法不能和private,final, static共存。