寒桥笔记-Java

JAVA学习笔记(四)

2017-04-27  本文已影响22人  寒桥

继承要解决的问题
什么是继承关系
子类继承了父类的哪些成员
方法覆盖
方法重载(Overload)和方法覆盖(方法重写 Override)的区别
supper关键字
子类初始化过程
super应用场景和各种隐藏现象
Object类
Object类常用的方法

1.继承要解决的问题

2.什么是继承关系:

基于某个父类对对象的定义加以扩展,而产生新的子类,子类可以继承父类原来的某些定义,也可以增加原来父类没有的定义,或者复写父类中的某些特性。从面向对象的角度来说:继承是一种从一般到特殊的关系,是一种“is a”的关系,即子类是对父类的扩展,是一种特殊的父类。

在Java语言中,存在多个类的时候,我们使用“extends”关键字来表示子类和父类之间的关系。
语法格式:在定义子类的时候来表明自己需要扩展于哪一个父类。

public class 子类类名 extends 父类类名
{
    编写自己特有的状态和行为
}
// super class 基类/超类/父类/被拓展类  extends关键字
// 父类存储的共性:共同的特征(状态/行为)
// 子类存储的特性:自己特有的特性(状态/行为)
// 继承关系解决的是:代码重复的问题
class People {
    String name;  // 姓名
    int    age;   // 年龄
    public void sleep() {}
}

// 老师 sub class 子类/拓展类
class Teacher extends People {String level; // 级别}

// 学生
class Schoolmate extends People {String number; // 学号}

// 员工
class Employee extends People {String hireDate; // 入职时间}

// 引出继承关系
public class ExtendDemo {
    public static void main(String[] args) {}
}

3.子类继承了父类的哪些成员

先写父类还是先写子类:
一般的,在开发过程中先编写多个自定义类,写完之后,发现多个类之间存在共同的代码,此时可以抽取出一个父类,以后做开发都是基于框架/组件来做的,是在别人的基础之上继续做开发。定义新的类去继承于框架/组件中提供的父类。

子类继承父类之后,可以拥有父类的某一些状态和行为(子类复用了父类的功能或者状态)那么子类到底继承了父类的哪些成员(根据访问修饰符来判断):

4.方法覆盖

子类拓展了父类,可以获得父类的部分方法和成员变量,当父类的某一个方法不适合于子类本身特征的时候,此时子类需要重新定义父类的方法,并重写方法体

class Bird {
    public void fly() {
        System.out.println("我在飞翔");
    }
}

class Penguin extends Bird {
    // 重新定义fly  方法的覆盖/复写 override
    @Override // 判断当前子类的方法是否覆盖了父类的方法
    public void fly() {
        System.out.println("我不会飞");
    }
}


public class OverrideDemo {
    public static void main(String[] args) {
        Penguin p = new Penguin();
        // 先从子类中寻找fly方法,如果找不到继续从父类中找,Bird中还没有就去Object中找,
        // 如果还找不到,编译就报错
        p.fly();
    }
}

5.方法重载(Overload)和方法覆盖(方法重写 Override)的区别

6.supper关键字

this 表示当前对象
super 表示当前对象的父类


内存分配示意图.png
class Bird {
    public void fly() {
        System.out.println("我在飞翔");
    }
}

class Penguin extends Bird {
    @Override
    public void fly() {
        System.out.println("我不会飞");
    }

    // 在子类中某一个方法中,去调用父类被覆盖的方法
    public void say() {
        // 调用Bird类中
        System.out.println("我在唱歌");
        // 调用当前类的fly方法
        this.fly();
        System.out.println("+++++");
        // 调用父类Bird类中的fly方法
        super.fly();
    }
}

public class OverrideDemo {
    public static void main(String[] args) {
        Penguin p = new Penguin();
        p.say();
    }
}

7.子类初始化过程

在创建子类对象时的执行顺序是:先进入子类构造器,然后在构造器中会先调用父类构造器(创建父类对象),再执行子类构造器代码。默认调用的是父类的无参构造器

class Bird {
    Bird(){
        System.out.println("父类构造器调用");
    }
    public void fly() {
        System.out.println("我在飞翔");
    }
}

class Penguin extends Bird {
    Penguin(){
        System.out.println("子类构造器");
    }

    @Override
    public void fly() {
        System.out.println("我不会飞");
    }

    // 在子类中某一个方法中,去调用父类被覆盖的方法
    public void say() {
        // 调用Bird类中
        System.out.println("我在唱歌");
        // 调用当前类的fly方法
        this.fly();
        System.out.println("+++++");
        // 调用父类Bird类中的fly方法
        super.fly();
    }
}

public class ExtendsDemo {
    public static void main(String[] args) {
        Penguin p = new Penguin();
        p.say();
    }
}

打印结果:

父类构造器调用
子类构造器
我在唱歌
我不会飞
+++++
我在飞翔
class Bird {
    Bird(String s){
        System.out.println("父类构造器调用");
    }
    public void fly() {
        System.out.println("我在飞翔");
    }
}

class Penguin extends Bird {
    // 父类对象没有无参构造器,这时候必须先调用super(paraments),也就是说子类构造器的创建一定要有父类构造器
    Penguin(){
        super("你好");
        System.out.println("子类构造器");
    }

    @Override
    public void fly() {
        System.out.println("我不会飞");
    }

    // 在子类中某一个方法中,去调用父类被覆盖的方法
    public void say() {
        // 调用Bird类中
        System.out.println("我在唱歌");
        // 调用当前类的fly方法
        this.fly();
        System.out.println("+++++");
        // 调用父类Bird类中的fly方法
        super.fly();
    }
}

public class ExtendsDemo {
    public static void main(String[] args) {
        Penguin p = new Penguin();
        p.say();
    }
}
// 动物
class Animal {
    // 要尽量私有化
    private String name;
    private int age;

    Animal() {
        System.out.println("Animal构造器");
    }

    Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
}

// 鱼
class Fish extends Animal {
    private String color; // 颜色

    Fish() {
        super(); // 对super的调用必须是构造器中的第一个语句
        // 其实存在一个隐式的父类无参构造器方法,即使父类中没有无参的构造器,编译也不会报错
        // 如果父类没有没有提供无参构造器,在子类中要显示调用父类的有参构造器
        // 但是如果父类中是有参数的构造器,在这里调用父类无参构造器编译器就会报错,提示没有找到参数
        // 如果父类的无参构造器经过private修饰,在子类中同样是无法调用的
        // 如果父类中既有无参构造器也有有参构造器,那么在子类中调用父类构造器就会去找相应的是否有参数的构造器
        System.out.println("Fish构造器");
    }

    // 重载一个带参数的构造器
    Fish(String name, int age, String color) {
        super(name, age); // 调用父类的构造器这句话必须作为子类构造器的第一句话
        this.color = color;
    }

    public void description() {
        // System.out.println(super.getName() + ", " + this.color);
        // 这里的super可以省略,因为子类找不到getName()方法会去父类中找
        System.out.println(getName() + ", " + this.color);
    }
}

public class SubClassDemo {
    public static void main(String[] args) {
        // 创建鱼对象
        Fish fish = new Fish("尼莫", 10, "橘黄色");
        // 在创建子类对象时的执行顺序:先进入子类构造器,然后在子类构造器中会
        // 先调用父类构造器(创建父类对象),再执行子类构造器代码
        fish.description();
    }
}

8.super应用场景和各种隐藏现象

class SuperClass{
    public String name="superclass.name";

    public static void method(){}
}
class SubClass{
    public int name=18; // 隐藏了父类的name字段

    public void doWork() {
        boolean name = false; // 隐藏调用本类中的字段
        System.out.println(name); // 根据就近原则,打印出来的结果是false
        System.out.println(this.name); // 打印出来的结果是18
        System.out.println(super.name);  // 打印出来的结果是superclass.name
    }

    public static void method(){} // 隐藏不叫覆盖
}

static不能和this以及super共存.

9.Object类

10.Object类常用的方法

public class Demo {
    public static void main(String[] args) {
        String str = new String("AA");
        String str1 = new String("AA");
        String str2 = "AA";
        System.out.println(str.equals(str1)); // true
        System.out.println(str.equals(str2)); // true
        // 两个字符串比较只要内容相同就相等,说明String类中覆盖了equals方法

        Object o1 = new Object();
        Object o2 = new Object();
        System.out.println(o1.equals(o2)); // false
        System.out.println(o1 == o2); // false 因为每次new都是一个新的内存空间
    }
}
Object类中toString的实现:

public String toString() {
    return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
}
class User {
    private int age;
    private String name;

    User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return this.name + ", " + this.age;
    }
}

public class ExtendsDemo {
    public static void main(String[] args) {
        User u = new User("xiaoming", 16);
        System.out.println(u); // com.example.ExtendsDemos.User@74a14482
        // 覆盖toString()方法后,这时打印出来的结果是xiaoming, 16
    }
}
上一篇下一篇

猜你喜欢

热点阅读