继承、封装、多态

1.继承

在了解继承之前,我们先get一下什么是子,什么是父?
一般来说,儿子是继承了父亲或母亲的基因而产生的生命结晶
在Java中其实也相似,为什么是相似呢?因为在Java中只有父的概念,没有母的概念
也就是说,子类继承了父类特有的功能
OK,说到这些,我们再聊继承的子类和父类问题
继承的简介
多个类中存在相同属性和行为,将这些内容提取到单独的一个类中
那么就多个类无需再定义这些属性和方法,只需要使用继承就可以使用父类的属性和方法
关键字:
	extends
格式:
	class 子类名 extends 父类名
好处:
	提高代码的复用性
	提高代码的维护性
	让类与类之间产生关系,是多态的前提

类与类之间产生关系的弊端:增强了类的耦合性(父类改变就会改变所有继承的子类)
开发的原则:
低耦合,高内聚
耦合:类与类之间的关系
内聚:自己完成某件事的能力
Java中继承的特点
		A:只支持单继承不支持多继承(c++就支持多继承)
		B:Java支持多层继承(继承体系)
注意事项:
	A:子类只能继承父类所有非私有成员(成员方法和成员变量)
	B:子类不能继承父类的构造方法,但是可以通过super关键字去访问构造方法
	C:不要为了部分功能而去继承。
什么时候用继承?
	继承其实体现的是一种"is a"的关系(包含关系)
从类的结构看继承
	成员变量:
		继承中成员变量的关系:
				A:子类中的成员变量和父类的成员变量名称不一样,访问谁就用谁
				B:子类中的成员变量和父类的成员变量名称一样,就近原则
				在子类方法中访问一个变量的查找顺序:
					a:在子类方法的局部范围找,有就使用
					b:在子类的成员范围找,有就使用
					c:在父类的成员范围找,有就使用
					d:如果还找不到就报错。
	成员方法:
		继承中成员方法的关系:
			A:子类中的方法和父类中的方法声明不一样的情况,属于基本正常情况
			B:子类中的方法和父类中的方法声明一样的情况:
				通过子类调用,如果子类有就调用
				如果子类没有找父类的
				父类没有就报错
			C:方法重写:
					子类中出现和父类中方法声明一模一样的方法,方法重写最终调用子类的方法
		方法重写的注意事项:
				A:父类中的私有方法不能被重写
					因为父类私有方法可以继承,但是无法访问
				B:子类重写父类方法时,子类的访问权限不能更低
					public是最大的访问权限
				C:父类的静态方法,子类也必须用静态方法进行重写,静态的方法算不上重写
	构造方法:
		继承中构造方法的关系:
				子类的所有构造方法都会默认去访问父类的无参构造方法
				原因:因为子类会继承父类的数据,可能还会使用父类的数据
					所以子类初始化之前,一定要先完成父类的数据初始化
					子类不能继承父类的构造方法怎么做呢?
					子类每一个构造方法的第一条语句都是super()//会访问父类的无参构造
				注意事项:
					如果父类没有无参构造方法(定义有参,默认无参自动取消),那么子类的构造方法会出现什么现象?
					*报错!
				解决方法:
					A:在父类中加一个无参
					B:通过使用super关键字显示的调用父类的带参构造
					C:子类通过this去调用本类的其他构造方法,其他构造方法内必须有super关键字去调用父类的有参构造。

继承的体现:

//定义学生类
class Student{
	int age;
	String name;
	public Student(){
	}
	public void eat(){
		System.out.println("吃饭");
	}
}
//定义老师类
class Teacher{
	int age;
	String name;
	public Teacher(){
	}
	public void eat(){
		System.out.println("吃饭");
	}
}
	class Person{
		String name;
		int age;
		pubilc Person(){
		}
		public void eat(){
			System.out.println("吃饭");
		}
	}
	//定义学生类
class Student extends Person{
	int age;
	String name;
	public Student(){
	}
}
//定义老师类
class Teacher extends Person{
	int age;
	String name;
	public Teacher(){
	}
}

2.封装

聊封装之前,我们还是来说一说一些思想吧,学了继承,确实可以将很多功能给重复利用起来,可是当很多类都具有耦合性后,只要别人一修改我父类的内容,我的子类就有挂掉的可能,
可能还是有人不懂,我们把自己定义的那些类当做是一个别人看不懂或者看不到的文件,只有main方法所在的类是给别人用于测试功能的,那么,当我调用子类是不是都挂了,我的属性都变了,怎么得到正确的结果呢?	

就像这样:

class Person{
	String name="张三";
	 int age=5;
	 int num;
}
class Student extends Person{
	public void show() {
		num=10/age;
		System.out.println("姓名:"+name+"年龄"+age+"num:"+num);
	}
}
public class AbstractDemo {
	public static void main(String[] args) {
		Student s=new Student();
		s.age=0;
		s.name="???";
		s.show();
	}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at CSDN代码测试.Student.show(AbstractDemo.java:43)
	at CSDN代码测试.AbstractDemo.main(AbstractDemo.java:53)
通过对象可以给成员变量赋值,可以赋值一些非法的数据
所以要对数据进行判断
但是一般每个方法都有具体的功能,如果我每个方法都要去进行判断,那功能就变得很杂
我们也不能写在main的类中啊,有main的类一般只用于创建对象,调用方法
所以Java就有了封装这个概念,将不想被改变的数据或方法定义成私有的,只能在本类中访问,通过访问器去访问私有数据的同时,进行判断,这个传入的数据是否合理,
如果合理,就将值赋值给相应的属性,否则就不行
	所以就要用权限访问private
	让成员变量必须通过本类方法来调用;
	
好处:隐藏实现细节,提供公共的访问方式
	提高了代码的复用性
	提高安全性
封装的原则:
	将不需要对外提供的内容都隐藏起来
	把属性隐藏,提供公共方法对其访问
class Person{
	private String name="张三";
	private int age=5;
	private int num;
	public Person() {}//这里需要注意,因为子类没写构造方法(ps:因为懒),所以系统会默认给子类分配一个无参构造
	//还记得super这个关键字吗?super()代表访问父类的无参构造,所以,如果只写父类的有参构造,就会报错,写了有参构造就默认没有无参构造了,必须写一个无参构造
	public Person(String name, int age, int num) {
		super();
		this.name = name;
		this.age = age;
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		if("".equals(name)) {
			System.out.println("数据异常");
		}else {
			this.name = name;
		}
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		if(age>0) {
			this.age = age;
		}else {
			System.out.println("数据异常");
		}
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
			this.num = num;
	}
	
}
class Student extends Person{
	public void show() {
		setNum(10/getAge());
		System.out.println("姓名:"+getName()+"年龄"+getAge()+"num:"+getNum());
	}
}
public class AbstractDemo {
	public static void main(String[] args) {
		Student s=new Student();
		s.setAge(0);
		s.setName("");;
		s.show();
	}
}
数据异常
数据异常
姓名:张三年龄5num:2

3.多态

还是老样子先说思想:
	多态是什么意思呢?就是说,当用户想使用类去代表谁的时候它就可以代表谁,我们首先回顾上面的两种特性:继承和封装,继承解决了代码的复用问题,提升了代码的扩展,
	封装是把一些数据隐藏起来防止被篡改,那么多态就是在封装和继承的基础上,实现重写,这样虽然行为相同,但是具体实现不同,
	就好比走路,袋鼠和猫都会走路,那猫和袋鼠走路能一样吗?袋鼠和猫都属于动物的领域,那袋鼠不算动物还是猫不算动物?
	所以说,为了解决这个问题,提出了多态的概念
多态概述:
	同一个对象在不同的时刻表现出来的不同状态
	举例:(反着念,如果你非要正着念)
	猫 m=new 猫()//猫是猫(一只是猫的猫)
	动物 d=new 猫()//猫是动物(一只是猫的动物)
多态的前提:
	A:要有继承关系
	B:要有方法重写(其实可以不写,但是不写无法体现多态,无意义)
	C:要有父类引用指向子类对象

多态中的成员访问特点:
	A:成员变量:编译父亲的(看父类是否有该调用方法
							使用父亲的,输出父亲的)
		编译看左边,运行看左边
	B:构造方法
		创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化
	C:成员方法:编译父亲的,使用儿子的(因为儿子重写了该方法)
		编译看左边,运行看右边
	D:静态方法:
		编译看左边,运行看左边。
		(静态和类相关,算不上重写,所以,访问的还是左边的)
总结起来一句话:多态中只能访问父类已有的内容,如果子类重写了父类的内容(属性不能重写),就使用子类的

多态的好处:
	A:提高了代码的维护性(继承就可以保证)
	B:提高了代码的扩展性
	多态可以解决在某种条件下不知道具体事物的属性,只知道行为
	可以使用多态进行扩展。

多态的弊端:
	A:不能使用子类的特有功能
	解决方法:把父类的引用赋值给子类(向下转型)
	Fu f=new Zi()
	Zi z=(Zi)f//必须加强制转换,否则就不兼容

对象间的转型问题:
	向上转型:
		Fu f=new Zi()
	向下转型:Zi z=(Zi)f;//必须满足f可以转换为Zi

父类被重写问题
有人说:父类被重写了,那我如果想要使用父类的方法不就没办法了,其实并非如此
1.创建父类对象,使用父类对象调方法
2.使用super.方法名,在子类中也可以使用父类的被重写方法
class Person{
	private String name";
	private int age;
	private int num;
	public Person() {}
	public Person(String name, int age, int num) {
		super();
		this.name = name;
		this.age = age;
		this.num = num;
	}
class Student extends Person{
	public void method() {
		System.out.println("子类show");
	}
}
public class AbstractDemo {
	public static void main(String[] args) {
		Person per=new Student();
		per.method();
		
	}
}

欢迎留言讨论。我只是一个学习的学生,很多东西可能还知道的不是很全面,希望大家多多留言交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值