day20
思考
父类中含有一个无参的test方法,子类含有一个带参的test方法
问题:子类中的带参test方法与父类的无参test方法之间是什么关系?
package com.saas; public class Father { public void test(){System.out.println("this is test method in Father class");} }package com.saas; public class Son extends Father{ /*** 当前的这个test方法与父类Father类中的无参test方法之间毫无关系* 最多是当前类中含有一个从父类Father继承过来的无参test方法与当前类自己定义的带参test方法之间构成方法的重载* @param n*/public void test(int n){System.out.println("this is test method with param in Son class");} }tips:
Son类中的带参test方法与父类Father中的无参test方法直接没有关系
Son类中的带参test方法与Son类中从父类Father继承过来的无参test方法之间构成方法重载的关系
继承
语法:
class 子类 extends 父类 {类体} // 定义子类时,显式地继承父类
使用关键字extends代表了一种继承关系,不能单纯从类名上进行判断是否是继承关系
应用:
产出继承关系后,子类可以使用父类中的非私有属性和方法,子类也可以定义自己所特有的属性和方法
好处:
既提高代码的复用性,有提高的可扩展性
特点:
Java的类只能是单继承,一个类最多只能继承一个父类,但是可以实现多级继承
package com.saas; public class Person { String name;int age; public void talk(){System.out.println("i am " + name + ", i am " + age + " years old.");System.out.println("talking....");} }package com.saas; public class Student extends Person{ public void study(){System.out.println("study ...");} }package com.saas; public class JavaStudent extends Student{ @Overridepublic void study() {System.out.println("open idea...");super.study();} public void javaStudy(){System.out.println("i like java");System.out.println("i am studying...");} }package com.saas; public class TestStudent { public static void main(String[] args) {Person p = new Person(); p.name = "baoyu";p.age = 18; p.talk();System.out.println("---------------------"); // p.study(); System.out.println("===================="); Student s = new Student(); s.name = "daiyu";s.age = 16; s.talk();System.out.println("---------------------");s.study();System.out.println("---------------------"); // s.javaStudy(); System.out.println("===================="); JavaStudent j = new JavaStudent(); j.name = "xiren";j.age = 16; j.talk();System.out.println("--------------------");j.study();System.out.println("--------------------");j.javaStudy();} }JavaStudent类直接继承自Student类
Student类直接继承自Person类
所以JavaStudent类的直接父类是Student
Student的直接父类是Person
但是JavaStudent类在继承Student类的同时,不能再继承Person类,因为Java是属于单继承
但是JavaStudent类继承自Student类,而Student类继承自Person类,这是属于多级继承,这个是被允许的
注意C++语言是允许多继承的
其中study方法是Student类中创建的方法,只能有Student类以及JavaStudent子类可以访问,其父类Person中并不含有study方法,所以study方法只能是Student的对象或者是Student的子类对象JavaStudent的对象来进行访问
其中javaStudy是JavaStudent类中定义的特有的方法,该方法只在类JavaStudent中定义,所以只能有JavaStudent类型的对象来访问,其父类Student不能访问,其父类的父类Person也不能访问该方法
不可继承
构造方法
类的构造方法,只负责创建本类对象,不可继承
private修饰的属性和方法
访问修饰符用private类修饰的成员,无法实现继承
父子类不在同一个包package中时,default修饰的属性和方法
修饰符default所修饰的成员在不同包下不能被访问
package com.saas; public class Teacher { public Teacher(){System.out.println("this is Teacher constructor.");} }package com.saas; public class JavaTeacher extends Teacher{ public JavaTeacher(){System.out.println("this is JavaTeacher constructor");} }package com.saas; public class TestTeacher { public static void main(String[] args) {Teacher t = new Teacher();System.out.println("=================");JavaTeacher j = new JavaTeacher();} }运行结果如下
this is Teacher constructor. ================= this is Teacher constructor. this is JavaTeacher constructor我们发现,创建子类对象时,执行了父类的构造器方法
但是我们不能说创建子类对象的同时创建一个父类对象
只不过我们需要通过父类构造器来初始化子类对象
package com.saas; public class JavaTeacher extends Teacher{ public JavaTeacher(){super(); // 一个类中的构造器,如果不调用任何其他构造器时,将会默认调用父类的无参构造器System.out.println("this is JavaTeacher constructor");} public void giveLesson(){System.out.println("打开idea");} }一个类中的构造器定义内部,如果不显式的调用任何构造器,则默认会调用其父类的无参构造器
修饰符 本类 同包 非同包子类 其他 private √ × × × default √ √ × × protected √ √ √ × public √ √ √ √ 从上到下,作用范围越来越宽泛
但是要注意一个问题是,访问修饰符要把握注意一个原则,够用原则
思考
子类中是否可以定义父类相同的方法?
可以定义与父类方法名相同,参数列表也相同的方法,最终会出现方法的重写
不可以定义与父类拥有相同的方法名和参数列表,只是返回值不一样的方法,这里会出现“二义性”,编译报错
package com.saas.oo2; public class Father { int money = 100000; public void printMoney(){System.out.println(money);} public void test(){System.out.println("this is test in Father");} }package com.saas.oo2; public class Son extends Father{ int money = 200000; @Overridepublic void printMoney() {System.out.println(super.money); // 100000System.out.println(this.money); // 200000System.out.println(money); // 200000System.out.println(super.money + this.money);} // public int test(){ // 不能在子类中定义与父类相同方法名和参数列表的方法,仅仅只是返回值不同,编译会报错,会出现二义性 // System.out.println("this is test in Son"); // return 0; // } }package com.saas.oo2; public class Test { public static void main(String[] args) {Father fa = new Father(); fa.printMoney(); System.out.println("====================="); Son s = new Son(); s.printMoney();} }
方法的重写
override: 也可以叫做方法的覆盖
子类修改从父类继承过来的方法,当父类提供的方法无法满足子类需求的时候,可在子类中定义和父类相同的方法进行重写
原则:
方法名称,参数列表,返回值类型都必须与父类完全相同
访问修饰符可以与父类的访问修饰符相同或者是更宽泛,不可以小于父类的访问修饰符
子类重写父类的方法后,调用时应该调用子类重写后的方法,最终应该表现为子类重写之后的表现形式
package com.saas.oo2; public class Father { int money = 100000; public void printMoney(){System.out.println(money);} public void test(){System.out.println("this is test in Father");} }package com.saas.oo2; public class Son extends Father{ int money = 200000; @Overridepublic void printMoney() {System.out.println(super.money);System.out.println(this.money);System.out.println(super.money + this.money);} public void test(int n){ // 不能在子类中定义与父类相同方法名和参数列表的方法,仅仅只是返回值不同,编译会报错,会出现二义性System.out.println("this is test in Son"); // return 0;} }Son类中含有一个带int参数的test方法,但是Son类还有一个看不见的从父类Father继承过来的无参的test方法
所以Son类中带参test方法与看不见的无参的test方法之间构成了方法的重载关系
Son类中的带参test方法与父类的无参的test方法之间毫无关系
Super关键字
在子类中,可以直接访问从父类继承到的属性和方法,但如果父子类的属性或方法存在重名(属性遮蔽,方法重写)时,需要加以区分,才可以专项访问
super关键字可以在子类中访问父类的成员属性和成员方法
使用super.的形式可以访问父类的实例属性和实例方法
父子类的同名属性不存在重写关系,两块空间同时存在,子类会遮蔽父类的属性,需使用不同的前缀进行访问,当前对象访问可以使用this,其中this可以省略,默认就是this,如果想要访问父类的属性,必须通过super.来访问父类的成员属性