继承
一.什么是继承
继承是一个类继承另一个类,这个类拥有被继承的类中所有的成员方法(除了父类的构造方法)和属性;
继承是面向对象特征之一;
实现继承的类称为子类或者派生类,被继承的类称为父类,或者称为超类/基类(将多个类的共性内容提取出来所形成的类);
注意:被private修饰的成员方法和属性虽然被子类所继承,但是不能被子类直接调用,只能通过公有部分间接去访问
父类的构造方法不能被继承
子类构造方法的第一条语句,都是隐含地调用super(),如果父类中没有这种形式(无参)的构造函数,那么在编译的时候就会报错。
二.继承的格式:
class 子类名 extends 父类名{...
}
三.继承的好处:
1)提高了代码的复用性,解决了代码的臃肿(父类中列出子类所使用的大部分方法和属性,在子类中只需要写出部分特殊的方法,需要使用父类中的方法是可以直接去调用,不需要在子类中重复书写,解决了代码的臃肿)
2)它是多态的前提(多态的前提是必须要存在继承关系)
四.继承的特点:
1)子类继承父类,是继承了父类所有的东西(成员变量,成员方法,包括私有),但是子类不能直接使用私有的东西,只能通过父类的公共
部分间接去调用或访问
2)在Java中,只支持单继承,不支持多继承
但是支持多层继承
类和类之间的关系: 继承关系
类和接口之间的关系: 实现关系
代码实例
package org.westos.继承;
class Person{
private String name ;
public void study() {
System.out.println("学生在学习....");
}
public void teach() {
System.out.println("老师在讲课...");
}
public void work() {
System.out.println("程序员在coding...");
}
}
//学生类
class Student extends Person{}
class Programmer extends Person{}
class Teacher extends Person{}
//测试类
public class ExtendsDemo {
public static void main(String[] args) {
//调用study方法
Student s = new Student() ;
s.study();
System.out.println("--------------");
Programmer p = new Programmer() ;
p.work() ;
System.out.println("--------------");
Teacher t = new Teacher() ;
t.teach();
}
}
多层继承
package org.westos.继承;
class GrandFather{
public void function() {
System.out.println("我是爷爷...");
}
}
class Father extends GrandFather{
public void show() {
System.out.println("我是老子....");
}
}
//子类
class Son extends Father{ //只支持单继承
//子类有玩游戏的功能
public void playGame() {
System.out.println("儿子会玩绝地求生....");
}
}
//测试类
public class ExtendsDemo2 {
public static void main(String[] args) {
//测试Son类
Son s = new Son();
//访问爷爷类的功能
s.function();
//访问父类的功能
s.show();
//访问本类的功能
s.playGame();
}
}
五.注意事项
1)构造方法不能被继承,但是可以通过super关键字去访问
2)私有的可以间接地去访问
3)使用extends的条件
假设:有一个A类
class A{
public void show1(){}
public void show2(){}
}
有一个B类
class B{
public void show1(){}
public void method(){}
}
按照正常的情况:发现A类和B类中有共同的show1()方法,根据继承的概念,---->让B类继承A类
class B extends A{public void method(){}
}
没有问题,但是继承了A类,show1(),show2()共同被继承过来了,可能show2()并不是我想要的功能;对于这种情况不要使用继承
继承所体现的是一种"is a"的关系:
A是B的一种或者B是A的一种,这种情况下可以使用继承。水果
香蕉
苹果
橘子
人类
学生
老师
军人...
不要随意的使用继承,只有当存在"is a"的关系才去使用它..
Java开发设计原则:
低耦合,高内聚
耦合:也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性
就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。
通俗易懂说法:类和类之间的关系越紧密,其耦合性就越强,但是类的独立性就越差,对其他类的依赖性就强,这对
于程序开发是不利的,所以尽量降低各模块(各类)的耦合性
内聚:又称块内联系。是对模块功能强度的度量,即对模块内部各个元素之间彼此结合的紧密程度的度量。若一
个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。
通俗易懂说法:能用一个类完成的事情就不要使用多个类去完成,让尽可能少的类拥有尽可能多/强的功能。
在继承中,成员变量的名称问题
当子类继承父类的时候,子类和父类中的成员变量名不一致的情况,非常简单,分别输出就可以了;
当子类和父类中的成员变量名称一致的情况:
1)先到子类的局部位置找,如果找到了,就输出
2)没有找到,到子类的成员位置找,有就输出,
3)在子类的成员位置还没有找到,就直接去到父类的成员位置找,有就输出
4)如果还没有,则报错,不存在这个变量
代码示例
class Fu{
int num = 50 ;
public void method() {
int num = 100 ; //第三步 父类的成员位置
System.out.println(num);
}
}
class Zi extends Fu{
public int num2 =20 ;
int num = 30; //第二步 成员位置
public void show() {
int num = 60 ; //第一步 局部位置
System.out.println(num);
System.out.println(num2);
}
}
//测试类
public class ExtendsDemo {
public static void main(String[] args) {
//创建Zi类对象
Zi z = new Zi() ;
z.show();
}
}
六.关键字:super
Java提供了关键字:super : 代表的是父类的空间标识(父类的引用或父类的对象)
this和super关键字的用法:
成员变量:this:
this.成员变量; (访问当前类)
super:
super.成员变量;(访问父类)
构造方法:
this(); //访问当前类的无参构造
this(参数) ;//访问当前类的有参构造
super(参数);//访问父类的有参构造
成员方法:
this.方法名()
super.方法名()
代码实例:
package org.westos;
class Father{
int num = 100 ;
public Father() {
super();
}
}
class Son extends Father{
public int num = 50 ;
public void show() {
int num = 20 ;
System.out.println(num); //就近原则
System.out.println(this.num); //this代表了当前类的对象 :Son
System.out.println(super.num);//super代表了父类的引用
}
}
public class ExtendsDemo2 {
public static void main(String[] args) {
Son s=new Son();
s.show();
}
}
七.构造方法说明
分层初始化:
创建子类对象时:
1)如果子类的有参/无参构造方法中的第一句都没有给出super();语句,则默认先去访问父类的无参构造方法,然
后才会去执行有参/无参构造方法中的剩余语句。
2)如果子类的有参构造方法中第一句为super(参数);则会先去访问父类的有参构造方法,然后去访问子类有参构造方法中的剩余语句。
代码示例
package org.westos;
class Fu2{
public Fu2() {
System.out.println("父类无参构造方法....");
}
public Fu2(String name) {
System.out.println("父类的有参构造方法...");
}
}
class Zi2 extends Fu2{
public Zi2() {
super() ;
System.out.println("子类的无参构造....");
}
public Zi2(String name) {
super("affw") ;
System.out.println("子类的有参构造....");
}
}
public class ExtendsDemo2 {
public static void main(String[] args) {
Zi2 z = new Zi2() ;
System.out.println("---------------");
Zi2 z2 = new Zi2("高圆圆") ;
}
}
!!!
如果父类中的无参构造没有提供怎么办?
首先肯定会报错,那么我们应该如何去解决呢?
1)可以将父类的无参构造提供出来
格式:
public 父类名(){
......
}
2)可以使用super关键字去访问父类的带参构造/有参构造...
super(参数);
3)还可以在子类中通过this()去访问本类的无参构造,然后间接的去访问父类有参构造子类必须有一个有参构造/无参构造,目的是为了让父类进行初始化!
代码示例
class Father2{
// public Father2() {
// System.out.println("父类 无参构造...");
// }
public Father2(String name) {
System.out.println("父类的有参构造....");
}
}
//子类继承父类
class Son2 extends Father2{
public Son2() {
// super("随便给") ; //访问父类的有参构造
super("随便给") ;
System.out.println("子类的无参构造...");
}
public Son2(String name) {
// super("随便给") ;//访问父类的有参构造
this() ;
System.out.println("子类的有参构造..");
}
}
public class ExtendsDemo4 {
public static void main(String[] args) {
Son2 s = new Son2() ;
}
}
八.继承中访问成员方法的问题
1.当父类和子类的成员方法名不一致的情况下,分别调用,没有影响。
2. 当父类和子类中的成员方法名一致的情况下:
1)先在子类的成员位置找,如果有就调用2)如果没有找到,则在父类的成员位置找,有就调用,没有就报错
总而言之,当当父类和子类中的成员方法名一致时,采取就近原则,先去子类找,有就用,没有就去父类找,有就用,没有报个错就行了!!!
代码示例
package org.westos;
class Person2{
public void method() {
System.out.println("mehtod Person..");
}
public void show() {
System.out.println("show Person");
}
}
//学生类
class Student2 extends Person2{
public void function() {
System.out.println("function student...");
}
public void show() {
System.out.println("show student...");
}
}
public class ExtendsDemo2 {
public static void main(String[] args) {
Student2 s = new Student2() ;
s.method();
s.function();
s.show();
}
}