面向对象三大特性之继承
继承的概念
生活中的继承:父辈对子女的进行财产的赠与,父辈的赠与 子女的获得
程序中的继承:类与类之间满足is a关系 才能定义继承关系 是指 子类可以去获得父类中非私有的属性和方法
is a关系理解
保温杯 is a 杯子
桑豪 is a 人
电脑 is a 电器
里氏代换原则 要求必须满足 is a 关系才可以定义两个类的继承关系
继承语法
关键词: extends 继承
语法: 子类 extends 父类
代码:
public class Demo{
}
//狗 动物
class Dog extends Animal{
}
class Animal{
}
案例:
public class Demo{
public static void main(String[] args) {
//创建狗类对象
Dog d = new Dog();
d.name = "哈士奇";
d.age = 15;
d.eat();
}
}
//狗 动物
class Dog extends Animal{
}
class Animal{
//属性
String name;
int age;
//吃
public void eat() {
System.out.println("动物吃");
}
}
注意事项
1.构造方法不可以继承
2.不能为了代码的复用去定义不符合里氏代换原则的继承关系
案例:
桑邦豪
刘洋 教java 没头发
桑邦豪 extends 刘洋{
}
java继承的特点
特点:、
1.java是单继承 一个类只能有一个父类
2.java可以多层继承 子类中的属性和方法是其所有父类的属性和方法的叠加
单继承的必要性:单继承可以让类和类之间的关系变得简单 让类和类之间形成一个树状结构
树状的结构
爷爷()
爸爸 叔叔 大爷
你 亲弟弟 堂弟 堂哥
```jaba
### Java的继承的好处
1.提高了代码的复用性(次要的) 不能为了代码的复用性强制定义不符合里氏代换原则原则的继承关系
2.是多态的前提
### 访问修饰符
| 修饰符 | 本类 | 同包及同包子类 | 其他包子类 | 其他 |
| ------------------- | ---- | -------------- | ---------- | ---- |
| private 私有的 | * | | | |
| (default)默认的 | * | * | | |
| protected 受保护的 | * | * | * | |
| public 公开的 | * | * | * | * |
```java
案例:
package cn.baizhi.day09;
public class A {
public int a;
public void m1() {
System.out.println(a);
}
}
//同包
class B{
public void m2() {
A a = new A();
System.out.println(a.a);
}
}
//同包的子类
class C extends A{
public void m3() {
System.out.println(a);
}
}
=================================================================
package cn.baizhi.day09_1;
import cn.baizhi.day09.A;
//不同包子类
class D extends A{
public void m4() {
System.out.println(a);
}
}
//不同包 也没有继承关系
class E{
public void m5() {
A a = new A();
System.out.println(a.a);
}
}
方法的重写(Override)
概念:当父类中的方法的实现无法满足子类的需要,那么就需要在子类中定义和父类方法名相同参数列表相同但是方法的实现不同的方法,把这种现象叫做方法的重写(覆盖)
要求:
1.方法名相同
2.参数列表相同
3.访问权限相同或者更宽
4.返回值类型相同
特点:当子类对象调用被重写后的方法时,调用的是子类中覆盖以后的方法
注意:
1.方法的重写前提是存在继承关系,才会有子类重写父类的方法
2.private修饰的方法不能被继承,也就谈不上覆盖
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.eat();//狗汪汪的吃
}
}
class Animal{
public void eat() {
System.out.println("动物吃");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗汪汪汪吃");
}
}
案例:关于访问权限修饰符
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
}
}
class Animal{
void eat() {
System.out.println("动物吃");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗汪汪汪吃");
}
}
案例:关于private修饰的方法能不能被覆盖
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
}
}
class Animal{
private void eat() {
System.out.println("动物吃");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗汪汪汪吃");
}
}
案例:关于子父类间方法的重载
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
}
}
class Animal{
public void eat() {
System.out.println("动物吃");
}
}
class Dog extends Animal{
public void eat(String s) {
System.out.println("狗汪汪汪吃"+s);
}
}
总结重载(overload)和重写(override)
重载
1.方法名相同
2.参数列表不同
3.和修饰符返回值类型无关
重写
1.方法名相同
2.参数列表相同
3.返回值类型相同
4.访问修饰符权限相同或者更宽
创建对象的过程
在创建子类对象之前 会先创建父类对象 子类对象的创建是依赖于父类对象
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog(撒谎角度来看);
}
}
class Animal{
public Animal() {
System.out.println("动物类构造被调用");
}
}
class Dog extends Animal{
public Dog() {
super(累计收到啦看风景);
System.out.println("狗类的构造被调用");
}
}
总结创建对象的过程
之前:
1.分配空间并赋默认值
2.为属性进行初始化赋初始值
3.调用构造方法并赋值创建对象
现在:
分配空间
创建父类对象
父类属性赋默认值
1为父类属性进行初始化赋初始值
2调用父类的构造方法并赋值创建父类对象
创建子类对象
子类属性赋默认值
3为子类属性进行初始化赋初始值
4调用子类的构造方法并赋值创建子类对象
注意:如果一个类是多层继承 1 2 重复执行
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
}
}
class ShengWu{
public ShengWu() {
System.out.println("生物类的构造被调用");
}
}
class Animal extends ShengWu{
public Animal() {
System.out.println("动物类构造被调用");
}
}
class Dog extends Animal{
public Dog() {
System.out.println("狗类的构造被调用");
}
}
super关键字
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
}
}
class Animal{
//属性
String name;
int age;
//无参
public Animal() {
System.out.println("动物类无参构造被调用");
}
// 一参
public Animal(String name) {
System.out.println("动物类一参构造被调用");
}
//两参
public Animal(String name,int age) {
System.out.println("动物类两参构造被调用");
}
}
class Dog extends Animal{
public Dog() {
System.out.println("狗类的构造被调用");
}
}
存在问题:在创建子类对象的时候,默认调用的是父类中无参构造,无法调用父类有参的构造
super()和super(参数)
super():代表调用父类无参的构造
super(参数):调用父类有参的构造
作用:在子类构造方法中调用父类的构造方法
特点:
1.如果子类构造方法中的第一行没有this()或者this(参数),也不是super(参数) 默认是 super(),构造方法的第一行不是this(...)就是super(...)
2.super()和super(参数)只能在构造方法的第一行
注意: super()和super(参数)只能用在子类的构造方法中
案例: 关于 super()使用的位置
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.m1();
}
}
class Animal{
//属性
String name;
int age;
//无参
public Animal() {
System.out.println("动物类无参构造被调用");
}
// 一参
public Animal(String name) {
System.out.println("动物类一参构造被调用");
}
//两参
public Animal(String name,int age) {
System.out.println("动物类两参构造被调用");
}
}
class Dog extends Animal{
public Dog() {
super();
System.out.println("狗类的构造被调用");
}
public void m1() {
super();
}
}
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog("哈士奇");
}
}
class Animal{
//属性
String name;
int age;
//无参
public Animal() {
System.out.println("动物类无参构造被调用");
}
// 一参
public Animal(String name) {
this.name = name;
System.out.println("动物类一参构造被调用");
}
//两参
public Animal(String name,int age) {
System.out.println("动物类两参构造被调用");
}
}
class Dog extends Animal{
public Dog() {
super("金毛");
System.out.println("狗类的构造被调用");
}
public Dog(String name) {
super(name);
System.out.println("狗类的有参被调用");
}
}
总结:
this()和 this(参数):在一个类中的构造方法中调用其他的构造方法(本类)
super() 和 super(参数):在子类中调用父类的构造方法
super.
this.属性名:局部变量和成员变量重名问题(本类)
super.属性名:子类的成员变量和父类成员变量重名问题 访问的是子类的 直接父类 中的重名属性值
super 代表当前子类对象的父类对象的引用
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.m1();
}
}
class Animal{
int age = 10;//父类的成员变量
}
class Dog extends Animal{
int age = 20;//子类的成员变量
public void m1() {
int age = 30;//子类的局部变量
System.out.println(age);//30
System.out.println(this.age);//20
System.out.println(super.age);//10
}
}
案例:
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.m1();
}
}
class Animal{
int age = 10;//父类的成员变量
}
class Dog extends Animal{
public void m1() {
int age = 30;//子类的局部变量
System.out.println(age);//30
System.out.println(this.age);//10
System.out.println(super.age);//10
}
}
案例:关于直接父类和间接父类的属性名重名问题
public class Demo{
public static void main(String[] args) {
Dog d = new Dog();
d.m1();
}
}
class ShengWu{//间接父类
int age = 5;
}
class Animal extends ShengWu{//直接父类
int age = 10;//父类的成员变量
}
class Dog extends Animal{
public void m1() {
int age = 30;//子类的局部变量
System.out.println(age);//30
System.out.println(this.age);//10 5
System.out.println(super.age);//10 5
}
}