继承关系
定义: Java中继承,需要使用extend关键字;
目的: 简化代码结构,将一类事物的共性提取到父类中,子类直接继承即可,不用再重复的实现相同的功能代码;更改时,直接更改父类一处代码即可,便于维护
Demo
释义:当前有两个类,分别是猫和企鹅;分别的情况如下:
猫:
属性:性别、年龄、名字、声音
方法:无参和全参构造方法,以及属性的获取和设置方法
企鹅
属性:性别、年龄、名字、颜色
方法:无参和全参构造方法,以及属性的获取和设置方法
根据上述实现的代码如下
猫
public class Cat {
private String gender;//性别
private int age;//年龄
private String name;//名字
private String sound;//声音
public Cat(){}
public Cat(String gender, int age, String name, String sound) {
this.gender = gender;
this.age = age;
this.name = name;
this.sound = sound;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
}
企鹅
public class Penguin{
private String gender;//性别
private int age;//年龄
private String name;//名字
private String color;//颜色
//无参构造
public Penguin() {
}
//全参构造
public Penguin(String gender, int age, String name, String color) {
this.gender = gender;
this.age = age;
this.name = name;
this.color = color;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
分析:
在上面两个类中,猫、企鹅都对
属性:性别、年龄、名字
进行了重复的定义,还实现了相同的set/get方法,导致代码重复
其次,当我需要新增一个狗的类时,它也是动物,也有性别、年龄、名字属性时,我们还需要重复去实现和定义
结论:我们可以定义一个父类,比如动物,使得其他猫、狗、企鹅等类,在创建时,自动就拥有相同的属性和方法,不用再重新去写了
使用extend后
动物Animal 类
public class Animal {
private String gender;//性别
private int age;//积蓄
private String name;//名字
public Animal(){}
public Animal(String gender, int age, String name) {
this.gender = gender;
this.age = age;
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
猫
public class Cat extends Animal{
private String sound;//声音
public Cat(){}
public Cat(String gender, int age, String name, String sound) {
super(gender, age, name);
this.sound = sound;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
}
企鹅
java
public class Penguin extends Animal{
private String color;//颜色
//无参构造
public Penguin() {
}
//全参构造
public Penguin(String gender, int age, String name, String color) {
super(gender, age, name);
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
调研示例:
使用子类给父类的属性进行赋值,以及有参创建对象;
public class test {
public static void main(String[] args) {
Cat cat = new Cat();
cat.setName("肥妞");
Cat allCat = new Cat("雌",3,"小名妞妞","喵喵喵");
System.out.println(cat.getName());
System.out.println(allCat.getName()+",今年"+allCat.getAge()+"岁");
}
}
结论1: 上述代码表示,子类继承父类后,可以通过子类使用父类的属性和方法
注意1: Java代码中,只允许单继承,即一个子类只能有一个父类;只能extend一次;
注意2: 当有继承关系时,创建子类对象时,会优先创建对应的父类对象,再创建子类对象;
注意3: 所有的Java类都往上追朔,最后都能追溯到同一个父类,Object.class;这个类是所有的根类或者说超类;
子类继承父类后,不能继承的内容
1.必须是父类私有属性和私有方法(即被private修饰的方法或者属性)不能被继承
2.子类和父类不在同一个包下时,default修饰的内容不能被继承使用
3.构造方法不能被继承,可以被调用
super关键字
1.super是直接父类对象的引用
释义:
A extend B; B extend C
在A中调用super,只能调用到B的属性和方法
2.可通过super来访问父类中被子类覆盖的方法或者属性
释义:
人类是猿猴的一种,猿猴有爬树的技能,人类继承了这种技能,但是与猿猴本身的技能已经不一样了,这个时候作为一个人类调用爬树的技能则使用的是人类自身的方法;如果要使用原始的猿猴的技能,则需要特别的使用super来调用
注意: 当有继承关系,创建子类时,会默认使用super调用父类的构造方法,调用父类无参构造时可以省略不写,要写时super必须放在构造方法的第一行;且不能与this();同时使用
引申 子类在创建对象时,如果不指定父类的构造函数,会默认调用父类的无参构造,所以我们在代码实现时,创建了有参构造,就要求必须创建无参构造;否则子类将找不到父类的无参构造,报错;
重写
场景条件 必须要存在继承关系,当父类中的方法无法满足子类的需求时,可以使用在子类重新实现该继承方法的逻辑,这个过程就是重写;
Demo
由于任何类最终都继承与object类,我们就用Object的toString()方法示例
toString()该方法是获取对象的名字+@+hash码值的16进制表示,简单理解为其名字的字符串即可
创建类OverWrite,区分OverWrite重写和不重写两种情况,调用OverWrite.hashCode()结果来看区别
OverWrite不重写时:
public class OverWrite {
private String name;
private String high;
private int age;
}
调用结果:
public class test {
public static void main(String[] args) {
OverWrite overWrite = new OverWrite();
System.out.println(overWrite.toString());
//重写前:com.chen.oop.inherit.OverWrite@677327b6
}
}
OverWrite重写时:
public class OverWrite {
private String name;
private String high;
private int age;
@Override
public String toString(){
return "重写方法之后,就打印我";
}
}
调用结果:
public class test {
public static void main(String[] args) {
OverWrite overWrite = new OverWrite();
System.out.println(overWrite.toString());
//重写后:重写方法之后,就打印我
}
}
注意事项
1.重写方法必须与被重写方法,有相同的方法名称、参数列表与顺序、和返回类型
2.并且重写方法的访问权限必须大于等于被重写方法
3.重写相当于子类自己重新实现一遍继承到的方法,如果无法被继承,则不能被重写,即不能被@Override标注;
4.特别注意:静态方法可以被继承,但是不能被重写;
抽象类
抽象类–即某些类不具备被实例化的意义,是一类对象的抽象概括,
比如:人、动物、宠物;没有一种动物叫动物即没有实际的对象
1.抽象类使用abstract关键字定义
2.抽象类不能进行实例化,即不能new创建对象
3.抽象类中的某些方法需要子类进行更丰富的实现,父类实现没有意义
则通过abstract关键字修饰,定义为抽象方法,其没有方法体;
4.使用abstract修饰的方法,是抽象方法;
5.抽象类中的方法,不一定是抽象方法;有抽象方法的类,一定是抽象类
6.子类继承抽象类,必须将抽象类中的方法进行实现,或者将子类也定义为抽象类
final
1.final修饰变量,标识变量值不可变
2.final修饰方法,表示方法不可以被重写
3.final修饰类,表示该类不能被继承
Object类
native修饰的方法指的是原生方法,即直接操作系统内核的方法,通常是用C语言写的,也就是JDK中,存在的一些原生方法,是直接调用的C语言等操作系统底层的方法;
1.toString();打印包信息和hasCode处理过的值
2.equals();Object底层实现是==;必须要重写,在java中的String、Integer等都重写了改方法,是直接比较的两个值
==比较的是两个基本类型的值,或者引用类型的地址值;
3.notify();是线程激活的方法
4.wait();是线程等待方法
5.finalize();是jvm中用于判断对象是否还有引用,是否可以回收的方法
6.clone克隆一个对象
多态
定义:调用同一个的方法,由于参数类型一致,但对象的具体实现是不一致的,从而使得程序执行不同的命令
实现多态条件
1.要有继承关系
2.子类方法必须重写父类方法
3.父类引用指向子类对象
Demo
释义:下面有四个类,宠物类-Pet;Dog继承Pet;Cat继承Pet;Person类的对象通过调用宠物类的eat()方法,实现相同的引用,不同的实例对象,执行不同的程序;Pet、Dog分别都对Pet的eat()方法进行重写;
实现方式
1.使用父类作为方法的形参实现多态
2.使用父类作为方法返回值实现多态
Pet
public abstract class Pet {
public abstract void eat();
}
Dog
public class Dog extends Pet{
@Override
public void eat() {
System.out.println("狗吃东西");
}
}
Cat
public class Cat extends Pet{
@Override
public void eat() {
System.out.println("猫吃东西");
}
}
Person
public class Person {
// public void eat(Dog dog) {
// dog.eat();
// }
//
// public void eat(Cat cat) {
// cat.eat();
// }
public void eat(Pet pet) {
pet.eat();
}
public static void main(String[] args) {
Person p = new Person();
Pet dog = new Dog();
Pet cat = new Cat();
p.eat(dog);
p.eat(cat);
}
}
注意: INSTANCEOF可以用来进行实例对象的类型判断
**多态作用:**为了提高代码的可维护性和可扩展性,方便代码逻辑编写
引用类型转换
当父类需要转换成子类时,需要进行强制转换;但在强制转换前,需要先判断父类引用指向的子类对象;无法确定,将导致运行中报错;判断方式:instanceof
当子类需要向父类转换的时候,直接自动转换,无须进行判断;