面相对象——继承
概念
在java中继承的概念就是,为多个类将共性继续抽取书写父类(进行类的分类),子类继承父类继承父类所有非私有的属性与方法
将大量类共性(书写与行为)进行抽取定义的父类,被抽取相同属性与方法的类称之为这个类的子类,这个类则称之为所有被抽取书写与行为的类的父类
语法
使用extends关键字将子类与父类关联
修饰符 class 子类类名 extends 父类类名{方法体}
package com.yunhe.day1019;
//父类 拥有子类共性(属性、行为)
public class Father {
public String name;
public int age;
public void sayHello(){
System.out.println("我叫"+name+" 今年"+age+"岁");
}
}
package com.yunhe.day1019;
//子类继承父类 可以继承父类的属性与方法
public class Son1 extends Father{
//子类在继承父类的属性与方法外也可以额外定义自己的属性与方法
public String color;
public void study(){
System.out.println("上学");
}
}
package com.yunhe.day1019;
public class Test {
public static void main(String[] args) {
Son1 s1=new Son1();
s1.name="子类";
s1.age=18;
s1.sayHello();
//注意:子类继承父类是可以使用父类的属性与方法,而不是将父类的属性方法保存到自己的内存
//当进行方法与属性的调用时,首先先去自己的内存空间查找,如果没有根据继承查找父类进行使用
Son1 s2=new Son1();
s2.name="子类2";
s2.age=19;
s2.sayHello();
//不同对象会创建不同的父类对象保存数据
//在创建子类对象时也会创建对应的父类对象
}
}
Object类
Java的继承形式被称为单继承(single inheritance),因为每一个Java类都只能有一个超类。所有类的共同基类是Object类
Object是所有类的父类,所有的类都直接或间接的继承于Object
子类创建对象原理
super关键字
super用于指代父类对象,在子类中调用父类的方法或属性
调用父类构造方法
super(参数列表)
调用父类方法
super.方法名(参数列表)
调用父类属性
super.属性名
在调用父类方法与属性时使用与this类似,只有在子类中存在于父类相同的方法与属性时使用super进行区分,否则可以直接使用属性或方法进行操作
方法的重写
发生在子类中,子类从父类继承的方法不能满足子类的功能需求时,使用方法的重写,将从父类继承的方法重写
在子类中创建与父类修饰符 返回值类型 方法名 参数列表都相同但方法体不同的方法
方法重写的规则:
要求子类修饰符范围必须大于或等于父类
返回值 方法名 参数列表必须一致
在重写的方法上加注释@Override 这样在进行方法重写时,系统会最书写的格式进行检查
@Override重写注释
用于对其标注的方法进行重写格式的验证
重写Override与重载Overload的区别
1.书写位置的区别
重载发生在本类中,重写发生在继承过程子类中
2.方法访问权限修饰符的区别
重载修饰符可以为任意修饰符,重写修饰符必须大于或等于父类修饰符
3.返回值类型的区别
重载返回值类型可以为任意类型,重写返回值类型与父类必须相同
4.方法名与原方法(父类方法)必须一致
5.参数列表的区别
重载参数列表必须不同,重写参数列表个数、顺序、类型必须全部相同
final关键字
修饰变量
修饰全局变量:
修饰的变量必须进行初始化赋值,不能修改
修饰局部变量:
修饰的变量不使用可以不赋值,但是只能赋值一次,使用必须赋值
修饰类
被final修饰的类不能被继承,但是可以创建对象,并且创建对象的属性与方法没有影响,final修饰类只影响类的继承
修饰方法
被final修饰的方法可以被继承但是不能被重写,final修饰方法只影响方法继承后的重写
修饰对象
与修饰变量相同,保存的相应对象的地址不能修改,但是对象对应属性可以进行修改。
总结:
1)子类继承父类,继承非私有的属性与方法
2)使用父类的属性与方法存储在父类对象
3)在创建子类对象时会为其创建一个对应的父类对象
4)子类除了可以继承父类属性方法外也可以定义额外的属性与方法
5)每个类只能有一个父类(java中的继承是单继承的)
6)如果一个类没有显式的继承任何类,那么这个类默认继承Object类
7)final修饰表示最终的对当前影响不大,影响的是后续操作
多态
概念
同一类的不同子类形态。可以声明,父类对象变量保存子类对象的形式
现实生活中存在很多多态的例子。
例如:水在100摄氏度的高温下是气体,在常温下是液体,在0摄氏度以下是固体。这里的多态是指一个对象具有多种形态
OOP中的多态与之类似。
同一个引用类型,使用不同的实例可以执行不同的操作,即父类引用子类对象——向上转型。
java中的多态理解为另一种数据类型转换
//宠物类
public class Pet {
public String name = "无名氏"; // 宠物昵称
public Pet(String name){
this.name=name;
}
public void eat(){ }
}
//狗类
public class Dog extends Pet{
public Dog(String name) {
super(name);
}
@Override
public void eat() {
System.out.println("狗"+name+"吃骨头");
}
}
//猫
public class Cat extends Pet{
public Cat(String name) {
super(name);
}
@Override
public void eat() {
System.out.println("猫"+name+"吃鱼");
}
}
//主人类
public class Master {
public void food(Pet pet) {
pet.eat();
}
}
//测试类
public class Test {
public static void main(String[] args) {
Master m=new Master();//主人对象
//向上转型
//声明父类变量 保存子类对象
//jvm在调用方法时会自动根据实际对象调用方法
Pet dog=new Dog("大黄");
Pet cat=new Cat("花花");
m.food(dog);
m.food(cat);
}
}
多态的使用
1、必须发生继承
只有发生继承多个对象才能进行联系
2、向上转型
声明父类变量保存子类对象,这样才能使用同一个变量表示多个不同相关联的变量,jvm在进行使用时会根据不同对象进行使用
3、子类必须重写父类方法
如果多个子类没有重写父类方法,在使用方法时,如果不重写父类方法,那么调用的还是父类方法,多态没有意义,并且由于声明的是父类变量所以只能调用父类声明过的方法
子类对象存储至父类变量时,与子类一同创建的父类对象可以直接赋值,但子类中额外的属性与方法在声明的父类变量中并没有进行声明,父类变量会帮子类对象进行存储但是,不能使用
向上转型
声明父类变量保存子类对象(类似于自动类型转换)
向下转型
声明子类变量保存父类对象(类似于强制类型转换)
向下转型成功的前提条件:当前父类是由要转换的子类对象向上转型得来的(这个对象曾经就是这个类的对象)
总结:
1、多态发生的条件继承、向上转型、重写
2、只能使用子类重写父类的方法以及父类特有的属性与方法
3、向下转向成功的前提:曾经发生过向上转型
多态的优点与缺点
优点:提高了代码的维护性与扩展性
缺点:只能在继承后的子类中使用,并且只能使用子类重写父类的方法而不能使用子类特有的方法
抽象类
在java开发过程中存在不能拥有具体对象的类,这些类同性时可以作为其余类的父类,因为可以代表多个类,所以如果可以创建对象,那么创建对象的类别很难划分,这个时候就需要使用抽象类关键字abstract进行修饰,将使用abstract修饰的类称之为抽象类,同理。使用abstract修饰的方法称之为抽象方法
抽象类与抽象方法的特点
1、 抽象方法没有方法体连{}都没有
抽象方法就是不知道怎么实现的方法,但是我们可以书写除方法体外的代码,所以抽象方法将方法体省略其余正常书写,由子类进行方法体的完善
//宠物类
public abstract class Pet {
public String name = "无名氏"; // 宠物昵称
public Pet(String name){
this.name=name;
}
public abstract void eat();
}
2、子类继承后抽象方法必须实现
在正常类中方法体已被书写,如果子类没有重写方法体,那么默认调用父类方法,但是在抽象方法中没有方法体,这个方法可以理解为未完成的方法,类似于声明后未赋值的变量,所以不能使用
//老鼠类
public class Mouse extends Pet{
public Mouse(String name) {
super(name);
}
@Override
public void eat() {
System.out.println("老鼠"+name+"吃大米");
}
}
3、一个类中如果存在抽象方法那么这个类一定是抽象类
4、抽象类不一定有抽象方法
5、抽象类不能创建对象但是可以声明变量
所有的类都有构造方法,如果没有显式的定义,系统会为其默认添加无参构造方法,但是被abstract修饰的类可以理解为进行了限制,不能由开发者手动调用new的方式进行构造方法的使用,但是如果子类可以通过super(参数)的方式进行调用
接口
接口在Java中是最重要的概念之一,它可以被理解为一种特殊的类,是由全局常量和公共的抽象方法所组成。
需要注意的是,在接口中的抽象方法必须定义为public访问权限,这是不可更改的。
接口其实本质上已经不是类了
接口的特点
1、接口不可以被实例化,不能有构造方法。
接口不是一个类
2、接口中的所有成员变量都是public static final
接口不是类所以不能书写类似继承的属性
3、接口中的方法都是抽象方法,接口中的方法会自动使用public abstract修饰。
在接口中不能写方法体,但是声明方法时可以直接使用 返回值类型 方法名(参数列表);的形式
4、一个类可以同时实现多个接口。
接口不是类无需遵循类的单继承而且接口使用的是实现implements 所以不是继承
5、实现类必须实现接口中的所有方法。
如果实现类中存在没有实现的方法那么这个类应为抽象类,不能被使用
6、接口可以继承接口(接口可以继承多个接口)
接口不是类所以无需遵循java中类的单继承
7、接口中不能出现静态方法,因为absctrant 不能修饰static static的方法是不能被继承的
虽然说接口的实现类是以实现方式重写方法,但是其实本质还是由接口继承抽象方法并重写,所以遵循static修饰的方法不能被继承的原则,但由于实现类必须实现接口中所有抽象方法,所以不允许使用static
//接口
public interface BossWork {
//接口中只能书写全局静态常量与静态方法
//所有方法默认使用 public abstract进行修饰(如果没写会默认添加)
public void one();
abstract void two();
void three();
public abstract void four();
//接口可以理解为老板安排的工作
}
//另一个接口
public interface BossWork2 {
void add();
}
//接口的实现
//通过implements关键字将接口进行关联
//接口不是类所以可以多实现
public class My implements BossWork,BossWork2{
//实现类可以被使用的情况
//1、实现了所有接口的抽象方法
//2、将实现类当做抽象类创建子类继承重写所有抽象方法
@Override
public void one() {}
@Override
public void two() {}
@Override
public void three() {}
@Override
public void four() {}
@Override
public void add() {}
}
//接口不是类所以可以多继承
//现在BossAllWork这个接口拥有BossWork,BossWork2这两个接口中所有抽象方法
public interface BossAllWork extends BossWork,BossWork2{
}
接口与抽象类在实际开发过程中都由程序员进行编写
接口的作用
1、在程序开发初期对程序需要书写的功能做一个全面的定义
2、便于开发与维护
当程序书写完毕,进行维护时,可以通过接口快速了解相应类具体功能
抽象类与接口的区别
相同:
1、都可以书写抽象方法
2、都不能通过new关键字创建对象,都可以用来声明对象
不同:
1、抽象类既可以书写抽象方法也可以书写普通方法
2、抽象类可以书写任意属性,接口中只能书写全局静态常量
3、抽象类中可以定义构造方法(系统会默认添加无参构造方法),接口中不能定义构造方法(系统不会添加无参构造方法)
4、抽象类使用子类继承重写的方式实现抽象方法,拘泥于java类的单继承,接口使用实现类实现的方式不是类的继承所以可以多实现,接口不是类,所以接口与接口之间可以多继承