Java Day8

Java

day8——2023.8.15

super

定义:super在调用的时候,指的是当前类对象的父类

因为父类的属性私有化之后,不能直接被子类调用,这时候就可以通过super关键字完成调用

super可以用来调用父类的属性,成员方法还有构造方法

super只能出现在子类的普通方法和构造方法中

super在子类中构造方法中,只能出现在第一行代码中

super调用父类的属性

super调用父类的属性,不能调用父类的私有属性,所以将来用super调用父类属性的用法其实很少用,只能调用没有私有化的属性

子类通过super调用父类的构造方法

写在子类构造方法的第一行

写法 : super();

​ 1,关于无参构造的调用,子类的无参构造会默认访问父类的无参构造

​ 如果子类的有参构造,没有显示的访问父类的有参构造,其实也会默认访问父类的无参构造

​ 为什么?

​ 因为子类继承父类、可能会使用父类的数据,所以在子类初始化之前,得先完成父类数据的初始化

​ 2,关于有参构造的作用

​ 子类可以通过在super()中传入参数的形式,完成对父类有参构造方法的调用

子类通过super调用父类的普通方法

子类可以在构造方法或者普通方法中,通过super调用父类的普通方法

写法 : super.方法名();

public class Person {
     String name; //姓名
     int age;  //年龄
     String gender;  //性别

    //父类的无参构造被注释,子类就无法使用父类的无参构造了
    public Person() {

    }

    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

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

    public void show(){
        System.out.println("我的姓名:" + name
                            + ",我的年龄:" + age
                            + ",我的性别:" + gender);
    }
}


public class Emp extends Person{ //员工类
    String deptName; //部门名称,一种扩展

    public Emp() {
        //子类的无参构造,默认会去访问父类的无参构造
        super();
        super.show();
    }

    public Emp(String name, int age, String gender, String deptName) {
        super(name,age,gender);
        //super(name, age);
        this.deptName = deptName;
    }

    public void show() {

    //  通过super调用父类的普通方法
        super.show();
        System.out.println("我所在的部门:" + deptName);
    }
}


public class TestEmp {
    public static void main(String[] args) {
        Emp emp = new Emp();
        emp.deptName = "研发部";
        emp.name = "张三";
        emp.age = 20;
        emp.gender = "男";
        emp.show();

        Emp emp1 = new Emp("李四", 22, "男", "财务部");
        emp1.show();

    }
}

创建一个动物类,作为父类 ,有私有化 种类、颜色两个属性,有一个show方法,作为动物的介绍 介绍内容为 : 我的种类是:xx,我的颜色是:xx 声明一个 小狗类,作为子类,有姓名 私有化属性作为扩展 ,子类也有一个show方法,并对父类的show方法做一个扩展,添加一条输出语句: 我的名字是:xx 要求 :通过全参的构造方法,实例化一个狗类对象,并调用show方法

package com.iweb.airui369.day07;

public class Animal {
    private String kind;
    private String color;

    public Animal() {
    }

    public Animal(String kind, String color) {
        this.kind = kind;
        this.color = color;
    }
    public void show(){
        System.out.println("我的品种是:" + kind + ",我的颜色是:" + color);
    }
}


package com.iweb.airui369.day07;

public class Dog extends Animal{
   private String name;


    public Dog(String kind, String color, String name) {
        super(kind, color);
        this.name = name;
    }

    @Override
    public void show() {
        super.show();
        System.out.println("我的名字是:" + name);
    }
}


package com.iweb.airui369.day07;

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("柯基","黑色","旺财");
        dog.show();
    }
}
super和this的区别

this指的是当前对象的引用
super指的是父类对象引用
super关键字:

​ super.父类属性名: 调用父类的属性

​ super.父类方法名: 调用父类的方法

​ super() : 调用父类的无参构造函数

​ super(参数): 调用父类有参构造函数

this的用法 :

​ this.属性名 :调用当前对象的属性 (局部变量和成员变量冲突)

​ this.方法名 : 调用当前对象的方法

​ this() : 调用当前类的无参构造

​ this(参数) : 调用当前类的有参构造
如果构造函数的第一行不是this()或者super()。系统默认添加super()

​ this和super关键字,不能共存

方法重写

概念:子类继承父类,子类重写父类的方法,方法名相同,参数列表相同,返回值类型相同或者是父类方法返回值的子类,访问修饰符不能严于父类,不能抛出比父类更多的异常

父类的私有方法不能被重写

父类的静态方法,不能被子类重写,

如果子类定义了和父类相同的静态方法或者私有方法,都会被当做子类自己的方法

子类为什么要重写父类方法?
一般是因为父类方法的功能不能满足子类的需求,然后子类对于父类方法做出扩展

package com.iweb.airui369.day07;

public class Father {
    public void method01(){
        System.out.println("这是父类的普通方法");
    }
    public Father method02(){
        return new Father();
    }
    public void method03(int a,int b){
        System.out.println("父类中带参数的方法");
    }
    public static void method04(){
        System.out.println("父类的静态方法");
    }
    private void method05(){
        System.out.println("父类的私有方法");
    }
}




package com.iweb.airui369.day07;

public class Son extends Father{
    @Override
    public void method01() {
        System.out.println("这是子类的方法");
    }
    //子类重写的方法的返回值,可以和父类相同
    //或者是父类返回值的子类
    @Override
    public Son method02() {
        return new Son();
    }
    //@Override //用来标识子类的方法重写了父类方法的
    //method03参数和父类的参数不一样,这个方法仍然可以声明
    //但是这个时候,它和父类方法没有关系,
    // 只是子类自己的一个普通方法
    public void method03(int a) {
        System.out.println("子类的方法");
    }
    //@Override
    //子类可以声明和父类相同名称的静态方法,
    //但是它们之间的关系并不是重写,
    //一般子类很少去写和父类同名的静态方法,除非想要将
    //父类的静态方法在子类中隐藏
    public static void method04(){
        System.out.println("子类的静态方法");
    }
    //@Override
    //父类的私有方法不能被子类重写
    private void method05(){
        System.out.println("子类重写父类的私有方法");
    }
}
方法重写的应用
equals()方法重写
public class Student {
    private int sid;  //学号
    private String name;  //姓名
    private String className; //班级

    public Student() {
    }

    public Student(int sid, String name, String className) {
        this.sid = sid;
        this.name = name;
        this.className = className;
    }

    @Override
    public boolean equals(Object obj) {
        //如果比较的两个对象,地址值相同,它们就是同一个对象
        if (this == obj){
            return true;
        }
        //如果传入的参数,不是一个Student对象,直接返回false
        //通过 instanceof  可以判断某个对象是否是指定类的实例
        //  用法 : 对象名  instanceof  类
        if (!(obj instanceof Student)){
            return false;
        }
        //判断传入的对象的属性和当前对象的属性的值,是否都是相同的
        //传入的参数会被当做是Object类型,将传入的参数,转为Student
        Student o = (Student) obj;
        if (this.sid == o.sid &&
                this.name.equals(o.name) &&
                this.className.equals(o.className)){
            return true;
        }
        return false;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", name='" + name + '\'' +
                ", className='" + className + '\'' +
                '}';
    }
}



public class StudentTest {
    public static void main(String[] args) {
        //创建两个相同对象
        Student s1 = new Student(10010, "张三", "1班");
        Student s2 = new Student(10010, "张三", "1班");
        System.out.println(s1);
        //使用== 比较引用类型,比较的是地址值,返回false
        System.out.println(s1 == s2);  //false

        //在Object类中,提供了一个equals()方法,用来比较对象之间是否相同的
        //将来,如果想比较对象是否相同,那么就得用equals()方法
        //两个相同的对象,我们调用equals比较,希望返回true,但是返回false
        //这是因为Object类中的equals()方法,底层代码还是== 做比较,
        //如果想要equals()方法可以比较对象的具体的属性,就需要重写equals()方法
        System.out.println(s1.equals(s2));
    }

}
toString()方法

当对象在被输出的时候,默认的会访问这个对象类的toString()方法,如果类中没有,就默认访问Object类中的toString()方法。

Object类中的toString()方法如下,表示返回当前类的包名+类名 +@+当前对象hashCode值的16进制
在这里插入图片描述
所以输出对象的时候,最后的结果就是一串值
在这里插入图片描述
所以将来,类中,一般都会重写toString()方法

相关面试题
1.重载和重写的区别

重载是指在同一个类中,根据参数的类型、个数或顺序,定义多个同名但签名不同的方法。重载的方法可以有不同的返回类型。重载通常用于提供相似但功能不同的操作。

重写是指在继承关系中,子类重新定义(覆盖)了父类中已有的方法。重写要求方法名、参数列表和返回类型完全相同。通过重写,子类可以改变父类方法的实现,从而实现自己的特定行为。

重载是在同一个类中根据参数的不同定义多个同名方法,用于提供相似但功能不同的操作;而重写是子类重新定义并覆盖父类中已有的方法,用于改变方法的实现。

2.==和equals()方法的区别

== 可以用来比较基本类型和引用类型

​ 比较基本类型的时候,比较的是值

​ 比较引用类型的时候,比较的是对象的地址值

equals()方法,是Object类中的方法,一般用来比较对象是否相同

​ 底层代码其实还是 ==,所以如果想要使用equals()方法,一般会重写equals()方法

​ 重写就是将对象的属性挨个比较,看看是否相同,重写之后可以用来比较对象是否相同

String类的equals()方法

重写了Object类中的equals()方法,底层的原理就是将需要比较字符串转为字符数组之后,利用循环,一个个比较数组中的字符值是否相同

3.为什么重写equals()方法,一定要重写hashCode()方法?

因为在Java中,相同的对象,它的hashCode值必须也是相同的

所以在重写equals()方法的同事,要重写hashCode()方法,为了保证他们的hashCode值也相同

抽象类

概念

继承中,将多个共同的内容,提取到一个类中,但是有些共同方法,方法声明是一样的,具体的实现不一样(每个具体的对象在做具体的操作的时候,功能实现不同),如果出现这种情况,这个方法就需要被定义的抽象方法

​ 抽象方法就是具有方法名,但是没有具体的方法实现(没有大括号)

​ 如果一个类中存在抽象方法,那么该类 就是抽象类

抽象类特点

写法:抽象方法或者抽象类通过abstract关键字修饰

特点:抽象类不能实例化

​ 抽象类中,可以没有抽象方法,但是有抽象方法的类一定是抽象类

​ 抽象类的子类,必须是一个抽象类或者是一个普通类,普通类必须重写抽象类中的所有抽象方法

抽象类的成员属性

​ 成员属性 : 可以有变量,也可以有常量

​ 成员方法:有抽象方法,普通方法,静态方法

​ 构造方法 :有构造方法,抽象类不能实例化,所以构造方法一般提供给子类访问使用

public abstract class Animal {
    private String name;
    final int age = 20;


    public Animal(String name) {
        this.name = name;
    }

    public Animal() {
    }

    //抽象方法,声明为抽象方法的类,必须是抽象类
    // 加上abstract关键字,完成方法和类的声明
    public abstract void eat();

    public void sleep(){
        System.out.println("动物会睡觉!");
    }

    public static void show(){
        System.out.println("动物会说话!");
    }

    
}


//子类继承抽象类之后,子类要么是抽象类,要么就要实现父类中的所有抽象方法
public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鱼~");
    }
}



public class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("狗吃骨头~");
    }
}


public class AnimalTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
        cat.sleep();
        cat.show();

        Dog dog = new Dog();
        dog.eat();
        dog.sleep();
        dog.show();
        
        //抽象类不能实例化
       //Animal animal = new Animal();
        //抽象类中可以定义静态方法,也可以通过类名直接调用
        Animal.show();
    }
}

多态

在这里插入图片描述

概念

一个对象,在不同时刻体现出来的不同状态

Java中多态的表示方式

父类的引用指向子类的对象

父类 对象名 = new 子类();

public class Person {
    public void say(){
        System.out.println("人类会说话!");
    }

    public void show(){
        System.out.println("这是父类的show方法");
    }
}


public class Student extends Person {

        @Override
        public void show(){
            System.out.println("这是子类的show方法");
        }
        public void show1(){
            System.out.println("这是子类特有的show1方法");
        }
}


public class PersonTest {
    public static void main(String[] args) {
        //多态创建Person对象
        //父类的引用指向子类的对象
        Person person = new Student();
        person.say();   //作为父类形态,可以调用父类特有的方法
       // person.show1();   //不能调用子类特有的方法
        person.show(); // 作为子类形态,可以调用子类重写父类的方法
    }
}
多态的特点

前提条件:1.有继承或者实现关系

​ 2.有方法的重写

​ 3.有父类或者父接口的引用指向子类对象

多态的分类

1,具体类的多态

class Fu{}

class Zi extends Fu{}

Fu f = new Zi();

2,抽象类的多态

abstract class Fu{}

class Zi extends Fu{}

Fu f = new Zi();

3,接口多态

interface Fu{}

class Zi implements Fu{}

Fu f = new Zi();

多态关系中成员访问特点

成员变量 :直接看等号的左边,左边是谁,优先找谁,没有向上找,找不到就报错

​ 编译看左边,运行看左边

成员方法:先从等号的左边找,左边不存在,就报错,运行的时候看new的是谁,就找谁

​ 编译看左边,运行看右边

构造方法:子类的构造默认会访问父类构造

多态的好处

多态可以提高代码的维护性(继承)

多态可以提高代码扩展性(多态体现)

public abstract class Emp {
    public abstract void work();
}

public class Teacher extends Emp{

    @Override
    public void work() {
        System.out.println("老师在讲课!");
    }
}

public class Assistant extends Emp {

    @Override
    public void work() {
        System.out.println("助教在辅导");
    }
}

public class EmpTest {
    public static void main(String[] args) {
        //没有多态,创建对象,关心的是通过哪个类创建的对象调用的work方法
        Teacher emp1 = new Teacher();
        emp1.work();
        Assistant emp2 = new Assistant();
        emp2.work();

        //多态的方式创建,关注点是work方法的调用,其他的东西我不关心
        Emp emp3 = new Teacher();
        emp3.work();
        Emp emp4 = new Assistant();
        emp4.work();
    }
}
多态的缺点

父类引用不能使用子类特有功能,子类可以当做父类使用,父类不能当做子类使用

多态的转型

多态中,父类引用不能使用子类特有功能,所以,要将父类对象做转型

多态的转型,分为向上转型和向下转型
在这里插入图片描述

多态的分类

面向对象中,根据代码执行时刻的不同,将多态分为 编译时多态 和 运行时多态

编译时多态是静态的,一般指的是方法的重载,根据参数列表来区分不同的方法,通过编译之后就会变成不同的方法

运行时多态是动态的,它是通过动态绑定来实现的,通过方法的重写来体现的,也就是之前讲解的面向对象的多态性

练习

请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。

创建一个Bird类继承Animal类,重写eat()方法输出一条语句“鸟儿 吃虫”,特有方法fly()输出鸟儿飞翔"

在Test类中向上转型创建bird对象,调用eat()方法。然后向下转型调用fly()方 法。

public class Animal {
    public void eat(){
        System.out.println("吃东西");
    }
}


public class Bird extends Animal {
    @Override
    public void eat() {
        System.out.println("鸟儿 吃虫");
    }
    public void fly(){
        System.out.println("鸟儿 飞翔");
    }
}


public class Test {
    public static void main(String[] args) {

        Animal bird = new Bird();
        bird.eat();


        Bird bird2 = (Bird) bird;
        bird2.fly();
    }
}

final关键字

概念 :final表示最终的意思,可以用来修饰类、方法、变量

特点 :

​ 1,final修饰的类,不能被继承 (String类不能被继承)

​ 2,final修饰的方法,该方法不能被重写

​ 3,final修饰的变量,该变量不能被重新赋值,final修饰的变量就是常量,一般final修饰的变量需要指定初始值

public class Father {
    public int num = 10;  //普通的变量
    public final int num2 = 20;  //常量

    public final void test01(){
        System.out.println("父类的final方法");
    }

}


public class Son extends Father {

    String name;

    public void show(){
        num = 100;
        //num2是常量,无法重新赋值
        //num2 = 1000;
        System.out.println(num);
        System.out.println(num2);
    }
    //子类不能重新父类的final方法
    //public void test01(){
    //    System.out.println("子类的方法");
    //}
}


public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.show();

       final int a = 10; //final修饰的局部变量也是常量
       // a = 100;   //不能被重新赋值
        System.out.println(a);


        Son son1 = new Son();
        son1.name = "张三";
        System.out.println(son1.name);


        final Son son2 = new Son();
        son2.name = "李四";
        System.out.println(son2.name);
        //final修饰的引用类型变量,变量中的属性值是可以被改变的
        son2.name = "王五";
        System.out.println(son2.name);
        //final修饰的引用的类型的变量,引用地址无法重新被赋值
        //son2 = new Son();
    }

    //final能不能修饰局部变量?修饰基本类型和引用类型的区别
    //final修饰的局部变量也是常量
    //final修饰的引用类型变量,变量中的属性值是可以被改变的
    //final修饰的引用的类型的变量,引用地址无法重新被赋值
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值