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();
}
}
欢迎留言讨论。我只是一个学习的学生,很多东西可能还知道的不是很全面,希望大家多多留言交流