目录
一.继承
1.1 继承是什么?
继承,简单来说就是抽取共性以此实现代码的复用,能够在保持原有类特性的基础上进行扩展,增加新功能,从而产生新的类。
1.2 继承的实现
在java中,表示继承关系要用到extends关键字
修饰符 class 子类 extends 父类{
//....
}
接下来我们以狗和猫为例子来看继承的具体实现,首先抽取狗和猫的共性,创建父类的成员变量和成员方法
class Animal{//父类,含有狗和猫的共性元素 public int age; public String color; public String name; public void sleep(){ System.out.println(this.name+"正在睡觉"); } }
在分别创建Dog类和Cat类,添加自己特有的成员变量和成员方法
class Dog extends Animal{//狗类 public void wag(){ System.out.println(name+"正在摇尾巴"); } } class Cat extends Animal{//猫类 public void mimi(){ System.out.println(name+"正在喵喵叫"); } } class Main2{//主函数所在类 public static void main(String[] args) { Dog dog=new Dog(); Cat cat=new Cat(); dog.name="小白"; cat.name="大白"; dog.sleep(); dog.wag(); cat.mimi(); } }
1.3 继承的注意点
1.通过子类对象访问成员变量时,如果该成员变量在子类中有,则优先先访问子类的,如果子类没有,则访问父类,父类如果也没有,则编译报错(成员方法同理)。
2.假设子类中存在与父类中相同的成员时,可以使用super关键字在子类中访问父类相同名称的成员
3.一个类只存在单继承关系,即一个类不能继承多个类
1.4 子类与父类构造方法之间的关系
当子类的构造方法为无参构造方法时,在子类的构造方法中,第一句默认为super()(编译器自动添加),调用父类无参的构造方法
class Father{//父类 public Father() { System.out.println("调用了父类构造方法"); } } class Son extends Father{子类 public Son() { //默认含有super()语句 System.out.println("调用了子类构造方法"); } } class Main2{ public static void main(String[] args) { Son son=new Son(); } }
从输出结果来看,在创建子类对象时先调用了父类的构造方法,在调用了子类的构造方法,上述是无参构造方法时的情况,那么如果改为有参数的构造方法,又会怎么样呢?
class Father{ public String name; public Father(String name) { } } class Son extends Father{ public Son() { super("张三"); //当父类为有参数构造方法时,子类构造方法中不再默认包含super()语句,需要自己定义构造方法 } } class Main2{ public static void main(String[] args) { Son son=new Son(); } }
二.多态
2.1 多态是什么?
多态即多种形态,当不同的对象去完成相同的行为时显现出的不同的状态,就像狗和猫同样都会发出叫声,但是狗是汪汪叫,而猫是喵喵叫。
2.2 多态的实现
当传递不同类对象时,会调用传入对象类的方法
class Animal{ public String name; public void shout() { System.out.println(name+"正在叫"); } } class Dog extends Animal{ public void shout() { System.out.println(name+"正在汪汪叫"); } } class Cat extends Animal{ public void shout(){ System.out.println(name+"正在喵喵叫"); } } class Main2{//主函数 public static void shout(Animal animal) { animal.shout(); } public static void main(String[] args) { Dog dog=new Dog(); Cat cat=new Cat(); dog.name="小白"; cat.name="大白"; shout(dog);//调用Dog类的shout方法 shout(cat);//调用Cat类的shout方法 } }
这里可能会出现两个让人疑惑的点:
疑惑点1:主函数中shout方法的参数是Animal类的实例对象,为什么能够传入Dog类和Cat类的实例对象呢?
这其中就涉及到向上转型。向上转型,实际上就是创建一个子类对象,把他当做父类对象来用。就像以下代码的实现一样,且实现该代码编译器不会报错。这就解释为了为什么能够在父类Animal对象为参数时传入Dog类和Cat类的子类对象。
Animal animal=new Dog();//把Dog类对象赋值给父类对象
疑惑点2:在代码中Animal,Dog,Cat类都实现了shout方法,那么如果子类不实现shout方法,结果会是什么呢?
class Animal{ public String name; public void shout() { System.out.println(name+"正在叫"); } } class Dog extends Animal{ } class Cat extends Animal{ public void shout(){ System.out.println(name+"正在喵喵叫"); } } class Main2{ public static void shout(Animal animal) { animal.shout(); } public static void main(String[] args) { Cat cat=new Cat(); Dog dog=new Dog(); dog.name="小白"; cat.name="大白"; shout(dog); shout(cat); } }
由输出结果看,当Dog类没有实现shout方法时,调用的是父类Animal的shout方法,同理如果当子类实现了shout方法,但是需要参数时,调用的仍然是父类Animal的shout方法,由此我们得出如果要实现调用子类的shout方法,子类必须实现shout方法,并且和父类方法的实现必须一模一样(指的是方法,不包括方法中的代码),即子类要重写父类的方法。
重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等方法进行重新编写,且与父类方法原型保持一致
注:1.被重写的方法在子类中的访问权限不能比父类中低。(访问权限即修饰符:public>protected>default)
2.父类被static、private修饰的方法或者是构造方法都不能被重写