目录
继承(extends)
定义
说明
作用
方法的重写
定义
重写关键点
方法重写与重载的区别
练习
练习1(方法继承与重写的简单练习)
练习2(方法继承与重写的进阶练习)
This的使用
定义
作用以及注意事项
super引用
定义
super关键点
super与this关系
继承链的属性值内存分析
思考
图解分析
继承(extends)
定义
子类继承父类,目的子类扩展父类的属性以及方法,就是为了实现代码的复用
1.子类可以继承父类的有权限访问的属性以及方法
2.所有的引用类型都默认继承了超类Object(所有的引用类型的超父类为Object【祖宗类】)
说明
1.子类继承父类的所有东西?不是 ;应该是子类有权限继承的属性和方法,所以,一般来说父类中的属性和方法设置为public。
2.Java中只有单继承,没有多继承,但是有继承链
举例:Doctor --> Person --> Object
作用
1、实现代码复用、减少代码冗余
2、方便维护
3、多态的前提
方法的重写
定义
子类重写父类的方法(子类覆盖父类的方法),凸显出子类的行为特征
方法重写跟修饰符、方法名、参数列表、返回值类型都有关系
【两同--方法名、方法参数列表、一大--权限修饰符、两小---返回值类型,异常类型】
重写关键点
1.方法名相同、方法参数列表相同
2.和方法修饰符、返回值类型有关
3.子类重写父类的方法,子类方法的权限修饰符比父类的大或者相等
4.子类重写父类的方法,子类的返回值类型比父类的小或者相等【引用类型】【基本数据类型要一致】
5.子类重写父类的方法,子类的抛出的异常类型要比父类的小或者相等
注意:当子类中有和父类一样的私有化方法,那么子类的私有化方法是一个普通方法,并不是重写了父类的方法
方法重写与重载的区别
1.重写:子类重写父类方法,凸显出子类的行为特征;
重载:在同一个类中,同一种行为的不同的体现
2.方法重写存在于继承链中,方法重载存在于同一个类中
3.方法重写是和修饰符以及返回值是有关系的,而方法重载是没有关系的
4.方法重写方法名和参数列表是一样的,但是方法重载是方法名一致,参数列表不一致
练习
练习1(方法继承与重写的简单练习)
定义一个动物类Animal name、sex、age--定义eat方法()
//动物类
public class Animal {
// name、sex、age
public String name;
public String sex;
public int age;
// --定义eat方法()
void eat() {
System.out.println("Animal eat....");
}
//方法重写跟修饰符、方法名、参数列表、返回值类型都有关系【两同、一大、两小】
public Object test() throws Exception {
return "";
}
}
--定义一个鸟类Bird,继承动物类,子类重写父类的eat方法
--在鸟类中定义一个移动方法move()
public class Bird extends Animal {
//方法重写
//子类重写的方法的权限修饰符大于等于父类的方法
@Override//方法重写的标志注解
public void eat() {
System.out.println("Bird eat....");
}
//定义一个移动方法
public void move() {
System.out.println("鸟通过飞行进行移动!");
}
//方法重写,主要目的是突出子类的行为特征【体现子类与父类的行为不一致】
@Override//方法重写的标志注解
public String test() throws Exception {
return "";
}
}
--定义一个狗类Dog,继承动物类,子类重写父类的eat方法
public class Dog extends Animal {
public void eat() {
System.out.println("Dog eat....");
}
}
--定义一个鸵鸟类ostrich 继承鸟类 ,重写鸟类的move方法
//鸵鸟继承鸟类
public class Ostrich extends Bird {
// 定义一个移动方法
public void move() {
System.out.println("鸵鸟通过奔跑进行移动!");
}
public void move(int hours) {
System.out.println("鸵鸟通过奔跑进行移动"+hours+"小时");
}
//鸵鸟重写动物父类中的eat方法
@Override
public void eat() {
System.out.println("Ostrich eat....");
}
}
测试类
public class AnimalMain {
public static void main(String[] args) {
// Animal
Animal animal = new Animal();
animal.eat();
// 创建一个子类的对象
Bird bird = new Bird();
bird.eat();
}
}
练习2(方法继承与重写的进阶练习)
父类:汽车Car:
车型、载人数量、载货重量
--载客方法(乘客人数)
--载货方法(货物重量)
//父类 汽车类
public class Car {
// 属性车型、载人数量、载货重量
public String type;
public int num;
public double weight;
// --载客方法(乘客人数)
public void CarryPassenger(int carryNum) {
System.out.println("当前乘客人数为:" + carryNum);
}
// --载货方法(货物重量) 吨
public void CarryProduction(double carryWeight) {
System.out.println("当前载货重量为:" + carryWeight + "吨");
}
}
轿车:famCar
重写父类的载客方法【设置载客条件:当乘客数量满足2人则启动】
class famCar extends Car {
// 重写父类的载客方法【设置载客条件:当乘客数量满足2人则启动】
public void CarryPassenger(int carryNum) {
if (carryNum > num) {
System.out.println("载客人数超载,请注意安全!");
return;// 结束方法
}
if (carryNum >= 2) {
System.out.println("小轿车载客人数满足,开始出发!");
}
}
}
大巴车:Bus
重写父类的载客方法【设置载客条件:当乘客数量满足20人则启动】
class Bus extends Car {
// 重写父类的载客方法【设置载客条件:当乘客数量满足20人则启动】
public void CarryPassenger(int carryNum) {
if (carryNum > num) {
System.out.println("载客人数超载,请注意安全!");
return;// 结束方法
}
if (carryNum >= 20) {
System.out.println("大巴的载客人数满足,开始出发!");
}
}
}
货车:Truckt
重写父类的载货方法【设置载货条件:当载货量达到3吨则启动】
定义载货的重载方法(运送利润金额)【设置载货条件:当运送利润金额达到3000元则启动】
class Truckt extends Car {
// 重写父类的载货方法【设置载货条件:当载货量达到3吨则启动】
@Override
public void CarryProduction(double carryWeight) {
if (carryWeight > weight) {
System.out.println("载货重量超载,请注意安全!");
return;// 结束方法
}
if (carryWeight >= 3) {
System.out.println("货车载货重量满足,开始出发!");
}
}
// 定义载货的重载方法(运送利润金额)【设置载货条件:当运送利润金额达到3000元则启动】
public void CarryProduction(int price) {
if (price >= 3000) {
System.out.println("货车单次运送利润金额达到3000元,开始出发!");
}
}
}
测试类
public class CarMain {
public static void main(String[] args) {
// 使用货车运送物资
Truckt truckt = new Truckt();
truckt.type = "大东风";truckt.num = 4;truckt.weight = 20;
truckt.CarryProduction(5.5);
// 使用货车运送商品【单次利润为5000元】
truckt.CarryProduction(5000);
}
}
This的使用
定义
this表示的是调用当前方法的实例对象的引用[谁调用了这个方法,则this就表示为谁]
this:在哪里使用?构造器中、非静态方法中
作用以及注意事项
1、用于区分同名的成员变量和局部变量
// 就近原则:当前代码块中找--》当前类中找 --》往父类-曾父类。。找 --》
//若没找到则编译错误
// 用于区分同名的成员变量和局部变量
public ItGuy(String n, double w) {
name = n;//会去先找当前代码块有无name,再到当前类,再到父类...祖宗类
wealth = w;
}
2、在本类的非静态方法中调用非静态的属性以及方法可以省略对象,原因是省略this.
// 在非静态方法中调用非静态属性及方法时,可以省略this.
public void test() {
System.out.println(this.name);//Cannot use this in a static context
test1();// 相当于this.test1();
}
3、可以使用this调用本类另一个构造器,但是要注意构造器的调用必须要在构造器的第一行。
public ItGuy(String id, String name, double wealth) {
this(name, wealth);//Constructor call must be the first statement in a constructor
this.id = id;
}
// this也可以用调用本类中的另一个构造器,并要放在第一行!
public ItGuy(String name, double wealth) {
this.name = name;//this表示调用当前方法的引用对象
this.wealth = wealth;
}
注意:this不能在static修饰的代码块中使用(原因:this是一个对象的引用,是真实存在的;在static的代码块中this不能指向明确的真实对象)
super引用
定义
super表示为调用了当前方法的对象的父类对象的引用【父类的引用对象】
super关键点
重点:在java中创建对象时,首先会先创建父类的对象,再创建本类的对象
1.super可以调用父类的构造器,必须要在构造器的第一行
2.super可以调用父类的属性和方法
3.父类的成员变量存放在父类的对象,而不是在子类的对象中;
4.而子类中定义的成员变量,还是存放在子类的对象中
【成员变量由始至终都是只有一个】
super与this关系
1.super和this一样,都表示为一个对象引用,所以都不能在静态代码块中使用
2.在构造器中super();写和不写都一样,因为系统会默认调用父类的无参构造器创建父类的对象
public class Person {
public String id;
public String name;
public double wealth;
public void eat() {
System.out.println("Person 吃饭");
}
public Person(String id, String name, double wealth) {
super();
this.id = id;
this.name = name;
this.wealth = wealth;
}
public Person() {
super();
}
}
public class Student extends Person {
//2、super可以用于调用父类的构造器【在创建一个类之前,会先创建该父类的对象引用】
// 创建一个stu,先创建Object,再创建Person、最后才是student
public Student(String id, String name, double wealth) {
super();//super(); 写和不写都是存在的【默认都是调用父类的无参构造器】
this.id = id;
this.name = name;
this.wealth = wealth;
// super(id, name, wealth);//与上面三行同一个作用
}
public Student() {
super();
}
public void eat() {
System.out.println("Student 吃饭");
}
//定义一个方法用于调用父类的eat方法
//1、用于调用父类的方法及属性
public void superEat() {
super.eat();
}
}
//测试类,测试如何调用父类方法
public class PersonMain {
public static void main(String[] args) {
//
Student stu = new Student("001", "zhang", 456);
stu.eat();//调用子类(当前类的方法)
stu.superEat();//调用父类的方法
}
}
继承链的属性值内存分析
思考
在继承链中,变量是否有重写?this.name和super.name的关系是怎么样以及结果是怎么样 ?
答案:是没有重写变量的概念,只有非静态成员变量是属于哪个类的对象
【顺序问题:现在子类对象中找,如果子类对象中没有则认为是父类对象的】
//继承链值测试类
public class Student extends Person {
public String name;
public Student(String id, String name, double wealth) {
super();//super(); 写和不写都是存在的【默认都是调用父类的无参构造器】
this.id = id;
this.name = name;
this.wealth = wealth;
}
public Student() {
super();
}
public void superEat() {
System.out.println("this.name="+this.name);//zhang
//当前有name属性,构造器给当前name赋值,所以super没有赋值到,为null
System.out.println("super.name="+super.name);//null
//当前类无id属性,根据顺序,去找父类id赋值,因此子类父类都有值
System.out.println("this.id="+this.id);//本类无id,去父类person找id
System.out.println("super.id="+super.id);
}
}
//测试类,测试如何调用父类方法
public class PersonMain {
public static void main(String[] args) {
Student stu = new Student("001", "zhang", 456);
stu.superEat();//调用方法测试值
}
}
图解分析
如果子类有定义,先调用子类的并赋值。(即为这里的name)