一、继承思想的引出
将学生和工人的共性描述提取出来,单独进行描述
只要让学生和工人与单独描述的这个类有关系,就可以了。
二、继承作用
1.提高了代码的复用性
2.让类与类之间产生了关系,有了这个关系,才有了多态的特性
注意:①千万不能为了获得其他类的功能,简化代码而继承
必须是类与类之间所属关系才可以继承,所属关系是 is a
②java中只支持单继承,java支持多重继承
多继承容易带来安全隐患:当多个父;类中定义了相同功能,当功能内容不同时,子类对象不确定运行哪一个
但是java保留这种机制,用另一种体现形式来完成表示,多实现
例如:
class A
{
void show(){
System.out.println("a");
}
}
class B
{
void show(){
System.out.println("b");
}
}
class C extends A,B{}
C c=new C();
c.show();//不确定调用哪个类中的同名函数
三、如何使用一个继承体系中的功能呢?
想要使用体系,先查阅父类的描述,因为父类中定义的是该体系中共性功能。通过了解共性功能,就可以知道该体系的基本功能
这个体系已经基本可用了
四、具体调用创建对象
在具体调用时,要创建最子类的对象。理由:①有可能父类不能创建对象(如抽象类)②创建子类对象可以使用更多的功能,也包括基本的都可以使用
三四总结:查阅父类功能,创建子类对象使用功能
类中成员:
1.变量
如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量用this,子类要访问父类中的同名变量用super
super的使用和this的使用几乎一致。
this 代表的是本类对象的引用。super代表父类对象的引用
简单分三种情况:①全私有②非私有③无重名。
public class person {
public String country;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public String country;
private String name;
public void study() {
System.out.println("good study");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*
* 子类成员和父类私有成员同名,若直接使用,使用的是子类变量this.name
* 要使用父类变量,则用到super关键字,super.name,因为一个类中定义的属性应该私有
* (private),所以要用到getter方法super.getName()
*
*/
public void show() {
System.out.println(name);
System.out.println(super.getName());
//System.out.println(getName());这样写也可以
}
/*
* 子类成员和父类非私有成员同名
*/
public void show1() {
System.out.println(this.country);
System.out.println(super.country);
}
/*
* 子类成员变量中无同名的,继承父的
*/
public void show2() {
System.out.println(super.getAge());
}
public static void main(String[] args) {
worker w=new worker();
w.setName("张三");
/*
* 子类成员和父类私有成员同名
*/
w.show();
/*
* 子类成员和父类非私有成员同名
*/
w.country="cn";
w.show1();
/*
* 子类成员变量中无同名的,继承父的
*/
w.show2();
}
}
2.函数
对新写功能,没啥可说的,主要说下覆盖
当子类出现和父类一模一样的函数时,当子类对象调用该函数时,会运行子类函数的内容。
如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖)
当子类继承了父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致(覆盖的条件)
这时,没有必要定义新功能,而是使用覆盖特殊,保留父类的功能定义,并重写功能内容。
覆盖的作用:提高程序的扩展性
举个栗子:对(子类虽具备该功能,但是功能的内容却和父类不一致)理解
父类:人 speak(){s.o.p(“会说话”)}
子类:英国人 speak(){s.o.p(“会说英国话”)}
都是说话,没必要定义新的功能,覆盖即可
举个栗子:对提高程序的扩展性的理解
手机不断升级,不能修改源码,因为调用等会带来更多的修改。对来电显示功能进行拓展
父类:手机 show(){ s.o.p("numer")}
子类:新型手机 show(){ s.o.p("numer");
s.o.p("picture");
s.o.p("name");
}
对函数的功能进行拓展填充
父:public void show () {
System.out.print("country="+country);
System.out.print(" name="+name);
System.out.print(" age="+age);
}
子:public void show () {
super.show();//有些被覆盖函数的内容,在覆盖函数中也可以用,调用方法super.
若不加super就会是死循环,发生内存溢出
System.out.print(" salary="+salary);
}
写覆盖时的注意事项:
①子类覆盖父类,必须保证子类函数权限大于等于父类函数权限,才可以覆盖,否则编译失败
②静态只能覆盖静态的。(加载类时,非静态不加载)【知道即可,编程不用】
记住:重载:只看同名函数的参数列表
重写:子父类方法要一模一样(“三同一不低” 子类和父类的方法名称,参数列表,返回类型必须完全相同,而且子类方法的访问修饰符的权限不能比父类低)
③编程注意一个问题
父: int show(){执行语句;}
子:void show ( ){执行语句;}
子.show();//会出现编译错误。首先这不是覆盖,子继承父类,子类此时相当于有两个函数int show(){} void show(){}
虚拟机不知道执行哪个,所以出现编译错误。
3.构造函数
①特点:在对子类对象进行初始化时,父类的构造函数也会执行,那是因为子类的所有构造函数默认第一行有一条隐式的语句super()
(若重载了无参构造函数,则执行这个)
若父类重载了含参的构造函数(就不再含无参隐式了),则子类构造函数中,就不再含隐式语句super(),此时,必须指定要调用父类哪个构造函数。
②为什么子类一定要访问父类中的构造函数?
因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据初始化的。
如果要访问父类中指定的构造函数,可以通过手动定义super语句来指定(若写super()写在子构造函数的第一行)
③小应用:对访问父类中指定的构造函数,可以通过手动定义super语句来指定理解
父:class person
person(String name){this.name=name;}//构造函数
void show(){}
子:class strudent extends person
strudent(String name){
要执行这条语句this.name=name;,因为父类已经完成了这个函数,子类就可以继承或者在方法体中调用这个方法
所以可以用super(name)来完成,子构造函数内调用父构造函数不用.
}
void method(){ super.show(); //子普通构造函数调用父普通构造函数, super. }
④this(),super(),若写只能写在构造函数的第一行
就出现一个问题,若两者在子类中都想写,应该怎么办?
父:person
person(){ 执行语句;}
person(int x) {执行语句;}
子:student
student(){执行语句;}//含隐式的suer()
studetn(int x){this();执行语句;}
student s=new student(2);//其实this(),super(),都执行到了。
结论:子类的所有构造函数,默认都会访问父类中无参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类需要通过super语句或者this语句来指定要访问父类中的构造函数 。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类的构造函数。
子类中至少有一个构造函数会访问到父类中的构造函数