本章概述
本章属于面向对象第三章的内容,主要讲解继承、super、方法重写、抽象类、抽象方法、final、Object类等知识点。
目录
一、继承
1、为什么要使用继承?
使用继承优化后:
子类和父类是is-a的关系
2、继承是什么?
-
类是对对象的抽象,继承是对某一批类的抽象,从而实现对现实世界更好的建模。
-
提高代码的复用性!
-
extends的意思是“扩展”。子类是父类的扩展
-
不同的叫法:超类、父类、基类、子类、派生类
3、如何使用继承?
使用继承
--编写父类
--编写子类,继承父类
--一个类只能继承一个父类
4、课堂Demo【重点掌握】
子类 Dog.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 15:24
* @Description: netclass03.extend
* @version: 1.0
*/
public class Dog extends Pet {
// private String name;
// private int age;
// private String gender;
private String sound;
public Dog(){
// super();
}
// public Dog(String name){
// super(name);
// }
//
// public Dog(int age,String gender){
// super(age,gender);
// }
public Dog(String name, int age, String gender, String sound) {
// super();
// super(name);
// this(age,gender);
super(name,age,gender);
// this.name = name;
// this.age = age;
// this.gender = gender;
this.sound = sound;
}
// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
//
// public int getAge() {
// return age;
// }
//
// public void setAge(int age) {
// this.age = age;
// }
//
// public String getGender() {
// return gender;
// }
//
// public void setGender(String gender) {
// this.gender = gender;
// }
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
public void show(){
// System.out.println("name:" +this.name +" age:" +this.age +" gender:" +this.gender +" sount:" +this.sound);
System.out.println("name:" +this.getName() +" age:" +this.getAge() +" gender:" +this.getGender() +" sount:" +this.sound);
}
@Override
public void print(){
System.out.println("Dog print... ...");
// super.print();
}
}
子类 Penguin.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 15:25
* @Description: netclass03.extend
* @version: 1.0
*/
public class Penguin extends Pet {
// private String name;
// private int age;
// private String gender;
private String color;
public Penguin(){
}
public Penguin(String name, int age, String gender, String color) {
super(name,age,gender);
// this.name = name;
// this.age = age;
// this.gender = gender;
this.color = color;
}
// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
//
// public int getAge() {
// return age;
// }
//
// public void setAge(int age) {
// this.age = age;
// }
//
// public String getGender() {
// return gender;
// }
//
// public void setGender(String gender) {
// this.gender = gender;
// }
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void show(){
// System.out.println("name:" +this.name +" age:" +this.age +" gender:" +this.gender +" color:" +this.color);
System.out.println("name:" +this.getName() +" age:" +this.getAge() +" gender:" +this.getGender() +" color:" +this.color);
}
}
父类Pet.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 15:33
* @Description: netclass03.extend
* @version: 1.0
*/
public class Pet {
private String name;
private int age;
private String gender;
public Pet(){
// super(); //指向顶级父类Object
System.out.println("Pet 空构造器... ...");
}
// public Pet(String name){
// this.name= name;
// }
//
// public Pet(int age,String gender){
// this.age = age;
// this.gender = gender;
// }
public Pet(String name, int age, String gender) {
System.out.println("Pet(String name, int age, String gender)... ...");
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public /*static*/ void print(){
System.out.println("Pet print... ...");
}
private void test(){
System.out.println("Pet test... ...");
}
}
测试类PetTest.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 15:25
* @Description: netclass03.extend
* @version: 1.0
*/
/*
* 继承:
* 表示父类跟子类之间的关系
* 当两个类或者多个类具备相同的属性和方法的时候,可以提取出来,变成父类,子类可以继承
*
* 子类跟父类是is-a的关系
*
* 使用:
* 1、使用继承的时候需要使用extends关键字
* 2、使用继承关系之后,父类中的属性和方法都可以在子类中进行使用(非私有属性和非私有方法)
* 3、java中是单继承关系(如果包含多个父类,同时父类中包含重名方法,无法决定该调用谁)
*
*
* super:是 直接父类 对象的引用
* 用途:
* 1、可以在子类中调用父类中被子类覆盖的方法 super.父类方法名称
* 2、当super在普通方法中使用的话,可以任意位置编写
* 3、当super在构造方法中使用的话,会调用父类的构造方法,一定要将super放在第一行
* 4、在构造方法中super关键字和this关键字(指的是不能同时使用this关键字调用重载的构造方法)不能同时出现
* 5、父类中私有的属性和方法都不能被调用,包括构造方法
* 6、子类的构造方法中都会默认使用super关键字调用父类的无参构造方法,因此在定义类的时候,无论自己是否自定义了
* 其他构造方法,最好将无参构造方法写上
* 7、如果构造方法中显式的指定了super的构造方法,那么无参的构造方法就不会被调用
*
* 总结:
* 1、在创建子类对象的时候一定会优先创建父类对象
* 2、所有的java类都具备同一个顶级父类(老祖宗),称之为Object,是所有类的根类
*
* 重写:(覆盖)override
* 必须要存在继承关系,当父类中的方法无法满足子类需求的时候可以选择使用重写的方式
* 注意:
* 1、重写表示的是子类覆盖父类的方法,当覆盖之后,调用同样的方法的时候会优先调用子类
* 2、重写的方法名称,返回值类型,参数列表必须跟父类一致
* 3、子类重写的方法不允许比父类的方法具备更小的访问权限
* 父类 public 子类 public
* 父类 protected 子类 public protected
* 父类 default 子类 public protected default
* 父类的静态方法子类可以进行调用,但是子类不可以重写
* */
public class PetTest {
public static void main(String[] args) {
// Dog dog = new Dog();
// dog.name = "xiaohei";
// dog.setName("小白");
// dog.setAge(10);
// dog.setGender("雄性");
// dog.setSound("汪汪汪~~");
// dog.show();
// dog.print();
Dog dog = new Dog("小白",10,"雄性","汪汪汪~~");
dog.print();
// dog.name = "小黑";
// dog.test();
// Dog dog = new Dog();
// Penguin p = new Penguin("小白",11,"雌性","olive");
// p.show();
}
}
2、java中只有单继承,也就是从子类出发只能有一个直接父类。课堂代码【重点掌握】
父类1--Father1.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 16:12
* @Description: netclass03.extend
* @version: 1.0
*/
public class Father1 {
public void test(){
System.out.println("Father1 test... ...");
}
}
父类2--Father2.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 16:12
* @Description: netclass03.extend
* @version: 1.0
*/
public class Father2 {
public void test(){
System.out.println("Father2 test... ...");
}
}
子类--SubClassTest.java
package netclass03.extend;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 16:13
* @Description: netclass03.extend
* @version: 1.0
*/
public class SubClassTest extends Father1/*,Father2*/ {
public static void main(String[] args) {
// Father1 father1 = new Father1();
// father1.test();
SubClassTest sct = new SubClassTest();
sct.test();
}
}
3、其他代码--课堂Demo【重点掌握】
PetClassTest.java
package netclass03;
import netclass03.extend.Pet;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 17:01
* @Description: netclass03
* @version: 1.0
*/
public class PetClassTest extends Pet {
public static void main(String[] args) {
PetClassTest pct = new PetClassTest();
pct.print();
}
}
Tiger.java--演示在类中创建set,get方法时,如果出现boolean类型的成员变量,get方法要以is开头。
package netclass03;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/10 - 01 - 10 - 14:54
* @Description: netclass03
* @version: 1.0
*/
public class Tiger {
private String name;
private int age;
private boolean isAnimal;
public Tiger(){
}
public Tiger(String name, int age, boolean isAnimal) {
this.name = name;
this.age = age;
this.isAnimal = isAnimal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isAnimal() {
return isAnimal;
}
public void setAnimal(boolean animal) {
isAnimal = animal;
}
}
二、继承的理解和super【课堂Demo同上】
1、super是直接父类对象的引用。
2、可以通过super来访问父类中被子类覆盖的方法或属性。
3、普通方法:
没有顺序限制。可以随便调用。
4、构造函数中:
任何类的构造函数中,若是构造函数的第一行代码没有显式的调用super(...);那么
Java默认都会调用super();作为父类的初始化函数。 所以你这里的super();加不加
都无所谓。
5、super实例代码
public class Test {
public static void main(String[] args) {
new ChildClass().f();
}
}
class FatherClass {
public int value;
public void f(){
value = 100;
System.out.println
("FatherClass.value="+value);
}
}
class ChildClass extends FatherClass {
public int value;
public void f() {
super.f();
value = 200;
System.out.println("ChildClass.value="+value);
System.out.println(value);
System.out.println(super.value);
}
}
6、理解继承:
a、子类访问父类成员
使用super关键字代表父类对象
---- 访问父类构造方法
super(); super(name);
在子类构造方法中调用且必须是第一句
---- 访问父类属性
super.name;
---- 访问父类方法
super.print();
b、子类可以继承父类的所有资源吗?
不能被继承的父类成员有哪些?
---- 不能直接访问private成员
---- 子类与父类不在同包,使用默认访问权限的成员
---- 构造方法不能被继承
c、访问修饰符protected
---- 可以修饰属性和方法
---- 本类、同包、子类可以访问
d、访问修饰符总结
e、多重继承关系的初始化顺序是怎样的?
1、父类属性---->2、父类构造方法---->3、子类属性---->4、子类构造方法
f、理解继承示例代码
public class TestExtends {
public static void main(String[] args) {
Mammal m1 = new Mammal();
m1.puru();
m1.eat();
}
}
class Animal {
String eyes="眼睛";
String name="无名";
public void eat(){
System.out.println("动物吃东西!");
}
}
class Mammal extends Animal {
//哺乳
public void puru(){
eyes=“嘴巴”;
System.out.println("小动物吃奶!");
}
}
g、在何处使用继承?
何时使用继承?
---- 继承和真实世界类似
---- 只要说“猫是哺乳动物”,猫的很多属性、行为就不言自明了
---- 藏獒是一种狗
符合is-a关系的设计使用继承
---- 继承是代码重用的一种方式
将子类共有的属性和行为放到父类中
h、代码分析
class Car {
private int site = 4; //座位数
Car(){
System.out.println ("载客量是"+site+"人);
}
public void setSite(int site){
this.site = site;
}
void print(){
System.out.println ("载客量是"+site+"人);
}
}
class Bus extends Car {
Bus(int site){
setSite(site);
}
}
public class BusTest{
public static void main(String[] args) {
Bus bus = new Bus(20);
bus.print();
}
}
i、小结
---- 通过继承可以简化类的定义,实现代码的重用
---- 子类继承父类的成员变量和成员方法,但不继承父类的构造方法
---- java中只有单继承 ,没有像c++那样的多继承。多继承会引起混乱,使得继承链过于复
杂,系统难于维护。就像我们现实中,如果你有多个父母亲,那是一个多么混乱的世界啊。多继
承,就是为了实现代码的复用性,却引入了复杂性,使得系统类之间的关系混乱。
---- java中的多继承,可以通过接口来实现
---- 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。
三、方法重写【课堂Demo同上】
1、在子类中可以根据需要对从基类中继承来的方法进行重写。
2、重写方法必须和被重写方法具有相同方法名称、参数列表和返回类型。
3、重写方法不能使用比被重写方法更严格的访问权限。(由于多态)
4、重写示例代码
public class TestOverride {
public static void main(String[] args) {
Animal animal = new Animal();
animal.shout();
Dog dog = new Dog();
dog.shout();
}
}
class Animal{
void shout(){
System.out.println("发出声音!");
}
}
class Dog extends Animal {
void shout(){
System.out.println("旺旺旺!");
}
}
5、小结:
---- 构造方法也会被重写吗?
不能被继承,因此不能重写
---- 方法重写的规则
方法名相同
参数列表相同
返回值类型相同或者是其子类;
访问权限不能严于父类
---- 方法重载与方法重写的区别
---- super关键字来访问父类的成员
---- super只能出现在子类的方法和构造方法中
---- super调用构造方法时,只能是第一句
---- super和this不能同时出现在构造方法中
---- super不能访问父类的private成员
---- super和this都不能再static方法中
四、抽象类、抽象方法
1、课堂Demo【重点掌握】
父类 Pet.java
package netclass04.abstracts;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 14:36
* @Description: netclass04.abstracts
* @version: 1.0
*/
public abstract class Pet {
private String name;
private int age;
public Pet(){
}
public Pet(String name,int age){
this.name = name;
this.age = age;
}
//抽象方法
public abstract void print();
public void show(){
System.out.println("Pet show... ...");
}
}
子类 Dog.java
package netclass04.abstracts;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 14:39
* @Description: netclass04.abstracts
* @version: 1.0
*/
public class Dog extends Pet{
private String gender;
@Override
public void print() {
System.out.println("dog print... ...");
}
}
测试类 PetTest.java
package netclass04.abstracts;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 14:41
* @Description: netclass04.abstracts
* @version: 1.0
*/
/*
* java中的对象是对现实世界的具象化,但是在现实世界中,某些类并不具备实例化的意义,因此可以定义为抽象类
*
* 抽象类:
* 1、创建抽象类的时候需要添加 abstract 的关键字
* 2、不能进行实例化,也就是不能new对象
* 3、抽象类中的某些方法需要子类进行更丰富的实现,父类实现没有意义,此时可以将抽象类
* 中的方法定义为抽象方法,没有具体的实现,只包含方法名称,返回值,参数列表,访问修饰符
* 4、使用abstract关键字修饰的方法叫做抽象方法,可以不写方法的实现
* 5、子类在继承抽象父类的时候,必须要将父类中的抽象方法进行实现或者将子类也定义为抽象类
* 6、有抽象方法的一定是抽象类,但是抽象类中不一定包含抽象方法
*
*/
public class PetTest {
public static void main(String[] args) {
Dog dog = new Dog();
dog.print();
// Pet pet = new Pet();
}
}
五、final
1、课堂Demo【重点掌握】
FinalDemo.java
package netclass04.abstracts;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 14:54
* @Description: netclass04.abstracts
* @version: 1.0
*/
/*
* final的使用:
* final可以修饰变量:
* 表示变量的值不可变
* final可以修饰方法:
* 表示方法不可以被重写
* final可以修饰类:
* 表示类不可以被继承
*
*
*/
public /*final*/ class FinalDemo {
private String name;
// public FinalDemo(){
// super();
// }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static final int num = 10;
public final void show(){
System.out.println("FinalDemo... ...");
}
public static void main(String[] args) {
// FinalDemo fd = new FinalDemo();
// fd.num = 20;
// FinalDemo.num = 20;
// num = 20;
// System.out.println(num);
final FinalDemo fd = new FinalDemo();
fd.show();
// fd = new FinalDemo();
fd.setName("jason");
System.out.println(fd.getName());
}
}
FinlaSubClass.java
package netclass04.abstracts;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 14:59
* @Description: netclass04.abstracts
* @version: 1.0
*/
public class FinalSubClass extends FinalDemo{
// @Override
// public void show(){
//
// }
}
六、Object类
1、Object类是所有类的父类
一个类如果没有使用extends显性的继承另外一个类,那么这个类就继承自Object类。
2、源码解析(涉及到Object中常用的10个方法)
getClass()、hashCode()、equals(Object)、clone()、toString()、notify()、notifyAll()、wait()、wait(long)、wait(long,int)
finalize()方法为过时的方法或者说是不推荐的方法,主要作用是标识在堆中的对象哪些是没有被引用的,方便JVM中的GC进行垃圾回收。
3、对象的比较—==和equals()
a、==:
---- 比较两基本类型变量的值是否相等
---- 比较两个引用类型的值即内存地址是否相等,即是否指向同一对象。
b、equals() :
两对象的内容是否一致
c、自定义类须重写equals(),否则其对象比较结果总是false。
通过阅读Object源码可知,equals()方法的实现是用==完成的
Object源码摘抄
public boolean equals(Object obj) { return (this == obj); }
4、Object课堂Demo【重点掌握】
package netclass04.abstracts;
import java.util.Objects;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 15:14
* @Description: netclass04.abstracts
* @version: 1.0
*/
public class Teacher{
private String name;
private int age;
private double salary;
public Teacher() {
}
public Teacher(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
// @Override
// public boolean equals(Object o){
// Teacher t =(Teacher) o;
// return (this.name == t.name && this.age == t.age && this.salary == t.salary);
// }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Teacher teacher = (Teacher) o;
return age == teacher.age &&
Double.compare(teacher.salary, salary) == 0 &&
Objects.equals(name, teacher.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
// @Override
// public String toString(){
// return "name:" +this.name +" age:" +this.age +" salary:" + this.salary;
// }
public static void main(String[] args) {
Teacher t1 = new Teacher("张飞",28,9000);
// Teacher t2 = t1;
Teacher t2 = new Teacher("张飞",28,9000);
// System.out.println(t1 == t2);//true false
// t2.setName("赵云");
System.out.println(t1.equals(t2));//true false
System.out.println(t1);
}
}
七、总结
1、继承深化
a、父类方法的重写:
---- 方法名、形参列表相同。
---- 返回值类型和异常类型,子类小于等于父类。
---- 访问权限,子类大于等于父类
b、构造方法调用顺序:
---- 根据super的说明,构造方法第一句 总是:super(…)来调用父类对应的构造方法。
---- 先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
八、作业
1、上机练习--课堂Demo【重点掌握】
某汽车租赁公司出租多种车辆,车型及租金情况如下:
编写程序实现计算租赁价
案例分析:
a、发现类
MotoVehical(机动车,抽象类)、Car、Bus
b、发现类的属性
---- MotoVehical:no(车牌号),brand(品牌)
---- Car:type(型号)
---- Bus:seatCount(座位数)
c、发现类的方法
---- MotoVehical:calcRent(int days) 抽象方法
---- Car:Car(no,brand,type) 构造方法
---- Bus:Car(no,brand,seatCount) 构造方法
d、优化设计,编写程序
机动车类:MotoVehical.java
package netclass04.abstracts.homework;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 16:23
* @Description: netclass04.abstracts.homework
* @version: 1.0
*/
public abstract class MotoVehical {
private String no;
private String brand;
public MotoVehical(){
}
public MotoVehical(String no, String brand) {
this.no = no;
this.brand = brand;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
//抽象方法(根据天数计算租金)
public abstract int calcRent(int days);
}
轿车类:Car.java
package netclass04.abstracts.homework;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 16:25
* @Description: netclass04.abstracts.homework
* @version: 1.0
*/
public class Car extends MotoVehical {
private String type;
public Car(){
}
public Car(String no,String brand,String type){
super(no,brand);
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public int calcRent(int days) {
if(this.type.equals("0")){
return 600 * days;
}else if(this.type.equals("1")){
return 500 * days;
}else if(this.type.equals("2")){
return 300 * days;
}else{
System.out.println("您输入的车型不存在!");
return 0;
}
}
}
客车类:Bus.java
package netclass04.abstracts.homework;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 16:28
* @Description: netclass04.abstracts.homework
* @version: 1.0
*/
public class Bus extends MotoVehical {
private int seatCount;
public Bus(){
}
public Bus(String no,String brand,int seatCount){
super(no,brand);
this.seatCount = seatCount;
}
public int getSeatCount() {
return seatCount;
}
public void setSeatCount(int seatCount) {
this.seatCount = seatCount;
}
@Override
public int calcRent(int days) {
if(this.seatCount > 16){
return 1500 * days;
}else{
return 800 * days;
}
}
}
测试类:MotoVehicalTest.java
package netclass04.abstracts.homework;
/**
* @Auther: Yu Panpan
* @Date: 2022/1/12 - 01 - 12 - 16:30
* @Description: netclass04.abstracts.homework
* @version: 1.0
*/
public class MotoVehicalTest {
public static void main(String[] args) {
// MotoVehical moto = new MotoVehical();
Car car = new Car("豫A 8888888","别克","0");
int total1 = car.calcRent(5);
System.out.println("租金为:" +total1);
Bus bus = new Bus("豫A 6666666","金杯",16);
int total2 = bus.calcRent(5);
System.out.println("租金为:" +total2);
}
}
2、上机练习