Day09 继承、super、this、抽象类

这篇博客详细介绍了Java中的继承概念、格式和成员变量访问特点,强调了方法的重写及其注意事项。文章还探讨了super和this关键字的用法,并通过案例解释了抽象类、抽象方法的定义与使用,以及在实际开发中的应用场景。
摘要由CSDN通过智能技术生成

#今日内容

  • 继承
  • 方法的重写
  • super
  • 抽象类

##01. 继承的概述

  • 什么是继承?
  • 建立继承关系后, 有什么特点?
  • 继承的好处是?
总结:
	1.
		让类与类之间产生了关系, 子父类关系
			
	2.
		子类就可以直接使用到父类中非私有的成员

	3.
		提高了代码的复用性
		提高了代码的维护性
		提高了代码的编写效率(注意不是提高了执行效率)
		是 多态 的前提
		
		
		
		弊端: 提高了代码的耦合性.

##02. 继承的格式

  • 实现继承是通过哪个关键字?
总结:

	1.  extends

			格式:

				class 子类 extends 父类类名 {

				}


示例代码:

	class Animal {
	    String name;
	    int age;
	    String color;
	}
	
	class Cat extends Animal{
	    public void catchMouse(){
	        System.out.println("抓老鼠");
	    }
	}
	
	class Dog extends Animal{
	    public void lookHome(){
	        System.out.println("狗看家");
	    }
	}


	什么时候使用继承:

		当发现多个类之间存在共性的内容, 就可以考虑将共性的数据 -> (向上抽取)

			抽取之前需要考虑一点, 类与类之间是否产生了一种is..a的关系

##03. 继承中成员变量的访问特点

  • 思考: 如果子父类中出现了重名的成员变量, 那么在调用的时候, 用子类的还是父类的?
总结: 子类的, 这里使用到了就近原则
  • 在继承的关系中, 如果成员变量重名, 创建子类对象的时候, 访问有两种方式:
总结:

	A : 直接通过子类对象访问成员变量

			Zi z = new Zi();
   			System.out.println(z.num);			// 就近原则


	B : 间接通过成员方法访问成员变量

			方法所属于谁, 使用的就是谁


			public class Test2_Extends {
			    public static void main(String[] args) {
			        Zi z = new Zi();
			        z.methodZi();				// 方法所属于子类, 使用的是num20
			        z.methodFu();				// 方法所属于父类, 使用的是num10
			    }
			}
			
			class Fu{
			    int num = 10;
			    public void methodFu(){
			        System.out.println(num);
			    }
			}
			
			class Zi extends Fu {
			    int num = 20;
			    public void methodZi(){
			        System.out.println(num);
			    }
			}

##04. 区分子类方法中重名的三种变量

  • 局部变量和成员变量重名, 成员变量和父类成员变量重名.
class Dad {
	String name = "建霖";
}
	
class Kid extends Dad {
	String name = "四葱";
	
	public void show() {
		String name = "五葱";
		System.out.println(super.name);	// 建霖
		System.out.println(name);		// 五葱
		System.out.println(this.name);	// 四葱
	}
}

##05. 继承中成员方法的访问特点

  • 继承中如果出现了重名的成员方法, 调用的时候. 执行的是?
总结: 子类的成员方法
		虽然是就近原则的效果, 但是这里有一个专业名字

			方法的重写.

##06. 继承中方法的覆盖重写_概念与特点

  • 重写和重载的概念:
总结:

	1. 重载 : overload 

			在同一个类中, 方法名相同, 参数列表不同, 与返回值无关.

						参数列表不同:

								1. 类型不同
								2. 个数不同
								3. 顺序不同

	2. 重写(覆盖 覆写) : override

			在子父类当中, 出现方法声明一模一样的方法

				方法声明 : 参数列表一致, 方法名也需要一致

##07. 继承中方法的覆盖重写_注意事项

  • 注意事项:
总结:

	1. 子类重写父类方法的时候, 需要保证方法声明一模一样

		@Override: 注解
			用来检测当前方法是否是一个重写的方法

	2. 子类重写父类方法的时候, 返回值类型需要[ 小于等于 ]父类的类型

		建议: 返回值类型一致

		Object : 所有类的祖宗

				所有的类都是直接或者间接的继承了Object
	3. 子类重写父类方法的时候, 访问权限必须[ 大于等于 ] 父类的权限
		从大到小依次为: 
			public -> protected -> 默认的 -> private
			
	4. 子类不能重写父类中私有方法

			子类无法继承父类的私有方法,连继承都做不到, 更不要说重写.

##08. 继承中方法的覆盖重写_应用场景.

  • 什么情况下需要使用方法的重写?
总结:

	当子类需要父类的功能, 而子类的方法又有自己特有的功能主体, 这时候就可以重写父类的方法
	 这样做既沿袭了父类的功能, 又定义了子类特有的内容.


	大白话理解:

			子类觉得父类的方法不好, 或者说是过于老旧, 那么就可以对父类的方法进行重写.
  • 再次举例, 手机的例子
代码:

		class Phone {
		    public void call(){
		        System.out.println("手机打电话");
		    }
		}
		
		class iOS6 extends Phone {
		    public void siri(){
		        System.out.println("speak English");
		    }
		}
		
		class iOS7 extends iOS6 {
		@Override
		    public void siri(){
		        super.siri();				//既有了speak English的功能
		        System.out.println("说中文");//又添加了自己的新功能
		    }
		}

##09. 继承中构造方法的访问特点

  • 问题: 构造方法可以继承吗?
总结: 不可以 ! 构造方法要求方法名与类名相同,大小写也要一致
  • 需要搞清楚的是子父类谁先完成初始化的问题
总结:

	 父类先完成初始化, 子类再完成初始化

		初始化一个对象, 使用的是构造方法

			子类在初始化的时候, 一定会先访问的到父类的构造方法! 从而完成父类的初始化.


	问题: 如何访问的父类构造方法?


		结论: 在每一个构造方法的第一行语句都默认隐藏了一句话 super();
  • 访问构造方法的注意事项
总结:

	1. super()可以访问父类的空参构造, 如果想要访问有参构造, 需要在super()内部传入参数

			例如: super(10);

	2. super()语句, 必须放在构造方法的第一行有效语句.

##10. super关键字的三种用法

总结:

	1. 成员变量
	
	2. 成员方法

	3. 构造方法


	格式记忆: 调用成员是super.  调用构造是super();

##11. this关键字的三种用法

总结:

	1. 成员变量
	
	2. 成员方法

	3. 构造方法


	格式记忆: 调用成员是this.  调用构造是this();

##12. super与this关键字图解

  • 看图说话
  • 案例演示继承的常见用法
需求:
	猫类 : 毛的颜色, 腿的个数
			吃饭, 抓老鼠

	狗类 : 毛的颜色, 腿的个数
			吃饭, 看家

##13. Java继承的三个特点

  • 思考问题: 一个类是否可以拥有两个爹?
  • 继承的特点
总结:
	1: Java中只支持单继承, 不支持多继承, 但是可以多层继承

问题:
	凭啥不支持多继承?

		如果支持多继承的话, 两个父类中要是有相同的方法, 但是方法的功能主体不同.
			这时候再创建对象调用方法, 就不知道该走那一段逻辑了.

例子:

	class A {
		public void method(){
			System.out.println("A....");
		}
	}
	
	class B {
		public void method(){
			System.out.println("B....");
		}
	}
	
	class C extends A, B{
		
	}

	C c = new C();
	c.method();		// 打印A...还是B... ? 懵了!

##14. 抽象的概念

  • 什么是抽象类?
  • 抽象类和普通的父类有什么区别?
  • 抽象方法又是什么?
总结:
	1. 

	2. 	抽象类当中可以定义抽象方法;
		普通的父类中不能定义抽象方法.因为抽象方法只存在于抽象类和接口中.
	
	3. 当我们将共性的行为抽取到一个父类当中


结论: 
	
	当我们将事物的共性向上抽取之后, 发现某些行为描述不清了, 而且这些行为还是强制要求子类去重写的.
	这时候就可以将该行为定义为抽象方法, 抽象方法一定要存活于抽象类或者是接口当中.		

##15. 抽象方法和抽象类的格式

  • 抽象方法定义格式
  • 抽象类定义格式
总结:

	1. public abstract void 方法名 ( 参数列表 ) {  ...  }			

	2. abstract 类名称 {   ...    }
	
	[ 注意事项 ] 要和接口中的内容区分开来. 在接口中, abstract是可以省略的, 但是在类中, abstract是绝对不能省略的.需要特别注意.

##16. 抽象方法和抽象类的使用

  • 重点: 抽象类不能创建对象, 所以使用的话, 主要关注的就是子类了.
  • 作为抽象类的子类
总结:

	1. 见17的总结

##17. 抽象方法和抽象类的注意事项

  • 抽象类不能实例化( 创建对象 )
  • 抽象类中有构造方法
  • 抽象类中可以没有抽象方法
  • 抽象类的子类
总结:

	1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
		理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
		
	2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
		理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。 
		
	3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
		理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
		
	4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
		理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有 意				 义。 

##18. 发红包案例_分析

  • 看图分析

##19. 发红包案例_实现

  • 用户类
public class User {

    private String name; // 姓名
    private int money; // 余额,也就是当前用户拥有的钱数

    public User() {
    }

    public User(String name, int money) {
        this.name = name;
        this.money = money;
    }

    // 展示一下当前用户有多少钱
    public void show() {
        System.out.println("我叫:" + name + ",我有多少钱:" + money);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
  • 群主类
public class Manager extends User {

    public Manager() {
    }

    public Manager(String name, int money) {
        super(name, money);
    }

    public ArrayList<Integer> send(int totalMoney, int count) {
        // 首先需要一个集合,用来存储若干个红包的金额
        ArrayList<Integer> redList = new ArrayList<>();

        // 首先看一下群主自己有多少钱
        int leftMoney = super.getMoney(); // 群主当前余额
        if (totalMoney > leftMoney) {
            System.out.println("余额不足");
            return redList; // 返回空集合
        }

        // 扣钱,其实就是重新设置余额
        super.setMoney(leftMoney - totalMoney);

        // 发红包需要平均拆分成为count份
        int avg = totalMoney / count;
        int mod = totalMoney % count; // 余数,也就是甩下的零头

        // 除不开的零头,包在最后一个红包当中
        // 下面把红包一个一个放到集合当中
        for (int i = 0; i < count - 1; i++) {
            redList.add(avg);
        }

        // 最后一个红包
        int last = avg + mod;
        redList.add(last);

        return redList;
    }
}
  • 群成员类
public class Member extends User {

    public Member() {
    }

    public Member(String name, int money) {
        super(name, money);
    }

    public void receive(ArrayList<Integer> list) {
        // 从多个红包当中随便抽取一个,给我自己。
        // 随机获取一个集合当中的索引编号
        int index = new Random().nextInt(list.size());
        // 根据索引,从集合当中删除,并且得到被删除的红包,给我自己
        int delta = list.remove(index);
        // 当前成员自己本来有多少钱:
        int money = super.getMoney();
        // 加法,并且重新设置回去
        super.setMoney(money + delta);
    }
}
  • 测试类
public class MainRedPacket {

    public static void main(String[] args) {
        Manager manager = new Manager("群主", 100);

        Member one = new Member("成员A", 0);
        Member two = new Member("成员B", 0);
        Member three = new Member("成员C", 0);

        manager.show(); // 100
        one.show(); // 0
        two.show(); // 0
        three.show(); // 0
        System.out.println("===============");

        // 群主总共发20块钱,分成3个红包
        ArrayList<Integer> redList = manager.send(20, 3);
        // 三个普通成员收红包
        one.receive(redList);
        two.receive(redList);
        three.receive(redList);

        manager.show(); // 100-20=80
        // 6、6、8,随机分给三个人
        one.show();
        two.show();
        three.show();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值