Java基础笔记(十六)——继承

继承

提取出一些共性特征,作为父类,子类就可以继承父类的这些开放成员,子类再添加自己独有的属性和方法。如果再有类具有这些共同特征,也可继承这个父类。

特点:1.利于代码复用     2.缩短开发周期

继承是一种类与类之间的关系。

使用已存在的类的定义作为基础建立新类。

子类(派生类)——|>父类(基类)

新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类的特征(即继承全部开放特征)。

满足“A is a B”的逻辑关系。如:猫和狗都继承动物类,学生和老师都继承人类。

继承的实现(extends)

父类

class Animal{

  //公共的属性和方法

}

子类,只能继承一个父类

class Dog extends Animal{

      //子类特有的属性和方法

}

class Cat extends Animal{

}

子类可以访问父类非私有成员【把父类的非私有(private修饰但提供了getter/setter方法不是私有)成员(属性和方法)当自己的用】。

父类不可以访问子类特有成员(即时public也不行)。

方法重写&方法重载

先回顾一下方法重载

1.同一个类中

2.方法名相同,参数列表不同(参数顺序、个数、类型),与参数名无关。

3.与方法返回值类型,访问修饰符无关。

方法重写:子类也具有父类的方法,但实现的功能有所不同,需要重写。即与父类同名的方法。

1.有继承关系的子类中。

2.子类重写父类的方法。

3.返回值类型,方法名,参数列表(参数类型、顺序、个数)都有与父类继承的方法相同,与方法的参数名无关(参数名相同与否均可)。

注:返回值类型,可以是子类类型。父类方法的返回值是父类类型,子类重写方法时,其返回值类型既可以是父类类型,也可以是子类类型,但只能向下兼容,不能向上兼容,不能是Object类

如:父类  public Animal create(){ return new Animal();}

子类   @Override  

          public Dog create(){ return new Dog();}

4.子类方法的访问修饰符的访问范围需要大于等于父类的访问范围。private<default<protected<public

当子类重写父类方法后,子类对象调用的是重写后的方法,子类定义与父类同名的方法,要重写;子类可以定义与父类重名的属性。

super:父类对象的引用

子类可以把父类的开放成员(属性和方法)当作自己的用,子类包括继承父类的方法和自己重写父类的的方法。在子类的方法中,调用其它其它成员方法,在包含父类方法以及重写父类的方法情况下,子类肯定是调用重写的方法,那么如果想要调用父类的方法,而不是重写的那个方法,可以用super关键字来调用。如:super.eat();    super.setAge(3);      父类的属性可以用super调用,或者子类直接用就行。假如父类有name属性,子类不再定义了,如果成员方法或构造方法中用name属性,可以直接用或者super.name。

当然了,如果父类的方法没有被重写,子类对象和子类方法中在调用父类方法时如同自己的一样,子类在调用父类的开放属性时也是同自己定义的一样去使用。

父类的构造方法不允许被继承,也就不允许被重写了。

在有继承关系的程序初始化顺序:

在Java中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。

父类静态成员——>子类静态成员——>父类对象构造——>子类对象构造

静态成员【静态变量(也就是static成员属性)和静态代码块】,其中访问修饰符不影响成员加载顺序,谁先谁后与书写位置有关。

假设静态变量在静态代码块前面:(如果出现位置相反,就反过来)

父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量(成员属性)、父类构造代码块、父类构造函数、子类非静态变量、子类构造代码块、子类构造函数。

(1)静态优先非静态,静态属于类加载,只初始化一次,非静态属于对象,随着对象的创建可能会初始化多次。

(2)父类优先于子类进行初始化。Object类是超类(顶级父类。

(3)成员变量按出现顺序进行初始化,即使在方法中,也在任何方法被调用前(包括构造方法)先初始化。

构造方法的调用必须放在构造方法里,子类构造(包括带参构造)默认调用父类无参构造方法,如果要调用父类带参构造,可以通过super(参)调用父类允许被访问的其它构造方法。super必须在子类构造方法中的第一行。如:super(name,month);

super小结:

代表父类引用。

-访问父类成员方法   super.print();

-访问父类属性          super.name;

-访问父类构造方法   super();

(1)子类的构造的过程中必须调用其父类的构造方法(一层一层往上找,直到Object类)。

(2)如果子类的构造方法中没写super,则系统默认调用父类的无参构造方法,没显式写无参构造的,系统默认提供。

(3)如果父类中写了带参构造却没写无参构造,在子类的构造方法中,又没写super(参),则编译出错。【因为父类写带参构造了,系统就不会再提供无参构造了,而子类不写super(参),就会默认去调用父类的无参构造去,找不到,就出错。】如果父类既写了无参构造又写了带参构造,子类的构造方法中不写super,默认调用父类无参构造,写了super();也是调用无参构造,写了super(参),调用带参构造。其中子类的构造方法包括带参构造和无参构造都符合上述说法,创建对象时调用哪个构造,哪个构造都要遵守上述规则。super();就是调用父类无参构造,可写可不写,super(参)是调用指定的父类的带参构造。

(4)使用super();   super(参);   必须放在子类构造方法中的第一行。

super&this

在构造方法(有参构造)中写this(); 是先调用同类中的无参构造,this();也必须写在第一行。所以构造方法间调用时,this与super不能共存。

this:当前类对象的引用

-访问当前类的成员方法

-访问当前类的成员属性

-访问当前类的构造方法

-不能在静态方法中使用

super:父类对象的引用

-访问父类的成员方法

-访问父类的成员属性

-访问父类的构造方法

-不能在静态方法中使用

Object类

-Object类是所有类的父类。

-一个类没有使用extends关键字明确表示继承关系,则默认继承Object类(包括数组)。

-Java中的每个类都可以使用Object中定义的方法。【Object类是java.lang包里的(String、System...),此包系统默认加载,不要手动import】

-Object类中的equals方法和"=="是一样的,看地址是否相同,即是否指向同一个对象。String类中重写了Object类中的equals方法,比较对象的内容是否相同。

public class TestOne {
    public static void main(String[] args){
        Animal one=new Animal("小one",2);
        Animal two=new Animal("小one",2);
        //equals测试:继承Object类中的equals方法时,比较的是两个引用是否指向同一个对象。
        boolean flag=one.equals(two);
        System.out.println("one和two的引用比较:"+flag);
        System.out.println("one和two的引用比较:"+(one==two));
        System.out.println("==============================");
        //String类重写了Object类的equals方法,比较的是对象的内容是否相同
        String str1=new String("hello");
        String str2=new String("hello");
        flag=str1.equals(str2);
        System.out.println("str1和str2的引用比较:"+flag);
        System.out.println("str1和str2的引用比较:"+(str1==str2));
    }
}

//运行结果
小one2岁
小one2岁
one和two的引用比较:false
one和two的引用比较:false
==============================
str1和str2的引用比较:true
str1和str2的引用比较:false

那如何比较两个对象的内容值?

需要重写Object类中的equals方法

在Animal类中重写equals方法,使得比较对象的内容

public boolean equals(Object obj){
        if(obj==null)   //如果传入的对象为空,防止出现NullPointerException
            return false;
        Animal temp=(Animal)obj; //把传入的对象obj强转成Animal类型
        if(this.getName().equals(temp.getName())&&this.getAge()==temp.getAge()){
            return true;
        }
        else
            return false;
    }

//运行结果
one和two的引用比较:true
one和two的引用比较:false
==============================
str1和str2的引用比较:true
str1和str2的引用比较:false

在Animal类中重载equals方法,使得比较对象的内容,不用类型强制转换,直接传入Animal类型

public boolean equals(Animal animal){
        if(animal==null)
            return false;
        if(this.getName().equals(animal.getName())&&this.getAge()==animal.getAge()){
            return true;
        }
        else
            return false;
    }

//运行结果
one和two的引用比较:true
one和two的引用比较:false
==============================
str1和str2的引用比较:true
str1和str2的引用比较:false

如果重写和重载这两段代码都放在Animal类中,主函数中对象调用的是后者,因为后者通过Animal类型参数重载了equals方法,对象调用时会自动定位类型匹配方法。

Object类中的toString方法

返回这个类的字符串表现形式:类名+@+地址哈希值

(1)输出对象名时,默认会直接调用类中的toString

(2)继承Object中的toString方法时,输出对象的字符串表现形式:类型信息+@+地址信息

(3)子类可以通过重写toString方法的形式,改变输出的内容以及表现形式

在测试类中

public class TestOne {
    public static void main(String[] args){
        Animal one=new Animal("小one",2);
        System.out.println(one.toString());
        System.out.println(one);
    }
}

//运行结果
Animal@26cbb7db
Animal@26cbb7db

在Animal类中重写toString方法

public class Animal {

    private String name;
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Animal(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println(name+age+"岁");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString(){   //重写toString方法
        return "昵称:"+this.getName()+";年龄:"+this.getAge();
    }
}

//运行结果
小one2岁
昵称:小one;年龄:2
昵称:小one;年龄:2
原文地址:https://www.cnblogs.com/tendo/p/10501069.html