java基础day_05(this关键字、封装、super关键字,方法重写)

this关键字

this:传递对象值

this表示当前对象的意思,指向当前被调用的对象,即谁调用,this就指向代表谁

当前哪个对象被创建,this就代表当前对象

this可以用来调用属性、调用方法、调用构造方法

比如Student stu1=new Student();

调用对应的构造方法时,this.name =name;

里面的this就代表的是对象stu1,把用户输入的name值传递并赋值给stu1的属性name

this调用属性

this调用属性的时候,指向的是当前对象

public class Person {
    String name;

    //和谁聊天的方法
    //this表示当前对象的意思,指向方法的当前调用对象
    //谁调用,就指向谁
    //this在方法中使用的时候,如果方法中存在和属性同名的局部变量
    //加上this可以表示指向对象的属性
    public void say(String name){

        System.out.println(this.name + "和" + name +"正在聊天!");
    }

    public Person() {
    }
    //构造方法中的this,在调用属性的时候
    //表示,将来通过这个构造方法创建的对象的属性的值就是传入的值
    //this就是指向创建的对象
    public Person(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "张三";
        p1.say("王五"); //张三和王五在聊天

        Person p2 = new Person();
        p2.name = "李四";
        p2.say("王五"); //李四和王五在聊天

        Person p3 = new Person("张无忌");
        Person p4 = new Person("赵敏");
    }
}

this在使用的时候,如果方法中存在和属性同名的局部变量,加上this可以表示指向对象的属性。

this调用成员方法

public class Student {

    public void say(){
        System.out.println("学生在说话!");
    }
    public void say(String name){
        System.out.println("学生在和" + name + "说话");
    }

    public void sleep(){
        say();
        //this调用当前类的成员方法的时候,可以省略不写
       // this.say();
        this.say("张三");
       // System.out.println("学生在说话!");
        System.out.println("学生在睡觉!");
    }

    public static void main(String[] args) {

        Student s = new Student();
        s.sleep();
    }
}

this在普通方法中也可以使用,同样表示指向当前对象。

可以通过this关键字调用当前类的成员方法(方法里调用另一个方法)

this调用构造方法

当对象被创建时,就会触发构造方法(不论对象是否被赋值)

this调用构造方法,this只能写在构造方法的第一行

this调用构造方法时:不可以出现相互调用(或者形成死循环),同时一个构造方法里不能有多个this,只能有一个this,并且this在第一行

关于this到底在调用哪个构造方法(看参数列表)

构造方法可以调用普通方法,

普通方法中,不能通过this关键字调用构造方法

但是普通方法本身是可以调用构造方法的(即在普通方法中可以创建一个对象)

public class Demo01 {
    String name;
    int age;

    public Demo01(){
        this("jack"); //调用的是name参数的构造方法
        System.out.println("这是无参构造!1");
    }
    public Demo01(String name) {
        this(20); //这个调用的是age参数的构造
        System.out.println("这是参数为name的构造方法!2");
    }
    public Demo01(int age) {
        this.show();//调用的 普通方法show
        System.out.println("这是参数为age的构造方法!3");
    }
    public void show(){
        //普通方法中,不能通过this调用构造方法
        //this("jack");
        //普通方法中,创建通过new关键字创建对象是允许的
        Student s = new Student();
        System.out.println("这是普通方法!4");
    }
    public static void main(String[] args) {
        new Demo01();  //
    }
}

封装的定义,封装的使用,封装的目的

封装的定义:

封装其实是对象的一种隐藏技术

目的:将对象的属性和方法隐藏起来,同时隐藏一些不想暴露的属性和一些方法的使用细节

用户或者其他对象就不能看到功能的实现,也不能修改这些被隐藏的功能

将来只能通过指定的接口去调用对象的方法,从而达到通信的目的

封装使用目的:为了将设计者和使用者分开

使用者不需要知道实现的细节,只需要设计者提供的方法来访问对象就可以了

封装的使用:封装通过private 关键字来使用(也叫私有化),将这个方法或者属性私有化

问题: 私有化之后的属性,无法被对象直接调用,怎么完成赋值和 值的获取?
对象属性的赋值 :
1,通过 全参的构造方法 赋值
2,通过在类中设定 set方法,对象调用set方法,来完成对象的赋值
获取对象的属性值:
在别的类中,想要获取属性的值,只能通过get方法来获取
总结 :
属性在私有化之后,一般需要给属性指定getter/setter方法
如果类和类之间需要产生属性的数据交互,那么就可以通过 getter/setter方法

public class School {
    //属性
   private String schoolName;
   private int  studentNumber;
   private int teacherNumber;
   private int classNumber;

   //set方法,就是普通方法 ,返回值为空,需要传入参数用来设置属性值
   public void setSchoolName(String schoolName){
       this.schoolName = schoolName;
   }
   public void setStudentNumber(int studentNumber){
       this.studentNumber = studentNumber;
   }
   public void setTeacherNumber(int teacherNumber){
       this.teacherNumber = teacherNumber;
   }
   public void setClassNumber(int classNumber){
       this.classNumber = classNumber;
   }

   //声明get方法,方法存在返回值,方法没有参数,方法中有return
    public String getSchoolName(){
       return schoolName;
    }
    public int getStudentNumber(){
       return studentNumber;
    }
    public int getTeacherNumber(){
        return teacherNumber;
    }
    public int getClassNumber(){
        return classNumber;
    }


    //构造方法

    public School(String schoolName, int studentNumber, int teacherNumber, int classNumber) {
        this.schoolName = schoolName;
        this.studentNumber = studentNumber;
        this.teacherNumber = teacherNumber;
        this.classNumber = classNumber;
    }

    public School() {
    }

    //定义一个普通方法,将对象的信息展示
    public void show(){
        System.out.println("学校的名称:" + schoolName +
                            ",学校的学生数量:" + studentNumber +
                            ",学校的老师数量:" + teacherNumber +
                            ",学校的教室数量:" + classNumber);
    }
    
    public static void main(String[] args) {
       //在同一个类的main方法中,对象是可以正常调用属性的
        School school = new School();
        school.schoolName = "南京大学";
        System.out.println(school.schoolName);
    }
}
public class SchoolTest {
    public static void main(String[] args) {
        School s1 = new School();
        //private私有化的属性,在不同类中,属性不能被对象直接调用
        //s1.schoolName = "南京邮电大学";

        //创建对象,并且给对象赋值的方式:
        //1,通过全参的构造方法
        School s2 = new School("南京邮电大学",
                8000, 1000,
                2000);
        //赋值之后的对象的私有化的属性,仍然无法直接调用
        //System.out.println(s2.schoolName);
        //对象的普通方法中,可以接收到对象的赋值
        s2.show();

        //2,通过setter方法去完成属性的赋值
        School s3 = new School();
        s3.setSchoolName("南京大学");
        s3.setStudentNumber(10000);
        s3.setTeacherNumber(2000);
        s3.setClassNumber(4000);
        s3.show();
        //想去获取到某个属性值,不能直接通过点的方式拿到
        //也可以通过在类中声明一个普通方法,将属性值返回
        //通过设置getter 方法将,属性返回
        String schoolName = s3.getSchoolName();
        System.out.println(schoolName);
        System.out.println(s3.getStudentNumber());
        System.out.println(s3.getTeacherNumber());
        System.out.println(s3.getClassNumber());
    }
}

整理:

//set方法
public void setSchoolName(String schoolName){//需要传入参数,但是不需要返回值
        this.schoolName = schoolName;
}
//get方法
    
public String getSchoolName() {//不需要传入参数,但是需要有对应的返回值
    return schoolName;
}

小练习:编写一个私有化的学校类,通过上述的私有化数值赋值方法和获取方法完成对应的操作

(set和全参构造方法来赋值,get方法来获取值)

定义的School类(私有属性)

public class School {
    private String schoolName;
    private int schoolNumber;
    private int teacherNumber;
    private String schoolAddress;

    public School() {
    }
    //定义一个普通方法,把对象的信息全部展示
    public void show(){
        System.out.println("学校名称是"+schoolName+" 学校编号是"+schoolNumber+" 老师编号是"+teacherNumber+" 学校地址是"+schoolAddress);

    }

    public School(String schoolName, int schoolNumber, int teacherNumber, String schoolAddress) {
        this.schoolName = schoolName;
        this.schoolNumber = schoolNumber;
        this.teacherNumber = teacherNumber;
        this.schoolAddress = schoolAddress;
    }

    public void setSchoolName(String schoolName){//需要传入参数,但是不需要返回值
        this.schoolName = schoolName;
    }

    public void setSchoolNumber(int schoolNumber){
        this.schoolNumber=schoolNumber;
    }
    public void setTeacherNumber(int teacherNumber){
        this.teacherNumber = teacherNumber;
    }
    public void setSchoolAddress(String schoolAddress) {
        this.schoolAddress = schoolAddress;
    }

    public String getSchoolName() {//不需要传入参数,但是需要有对应的返回值
        return schoolName;
    }
    public String getSchoolAddress(){
        return  schoolAddress;
    }

    public int getSchoolNumber() {
        return schoolNumber;
    }

    public int getTeacherNumber() {
        return teacherNumber;
    }

    public static void main(String[] args) {
        School school = new School();
        //在同一个类中,私有化属性可以通过 对象名.属性 的方式来赋值和获取值,但是别的类就不能直接获取了,需要通过set和get方法
       school.schoolName="清华大学";
        System.out.println(school.schoolName);
    }

}

对应的schoolTest测试类

public class SchoolTest {
    public static void main(String[] args) {
        School s1 = new School();
      //在别的类中,之前定义的私有属性不能被创建的对象直接调用赋值了

        //私有化对象调用和赋值

        //1.通过全参的构造方法去赋值:通过方法里面输出的方式间接调用属性。
        School s2 = new School("南京邮电大学", 1001, 2000, "南京");
        //私有化的属性不能通过 对象名.属性的方式获取值(不管之前有没有被赋值,都不可以直接调用)
        s2.show();

        //2.使用get和set方法来进行属性获取和属性的赋值 (在对应的类中)           set--设置,赋值   get--获取
        //set方法就是一种普通方法,返回值为空,但是需要参数传入设计属性值
        School s3 = new School();
        s3.setSchoolName("南京大学");
        s3.show();//通过set方法也可以完成私有化属性赋值的效果
        s3.setSchoolAddress("南京");


        //私有化属性在其他类中同样不可以直接通过对象名.属性名来获取数值
        //同样的跟赋值一样,也可以通过在类中声明普通方法,调用普通方法来获取属性返回值。
        //定义一个get方法,来获取私有化属性的值
       //get和set方法的作用就是将来完成各个类之间的信息传递与交互(以后的属性都是私有化的)
        System.out.println(s3.getSchoolName());

        //总结:属性在私有化之后,1只能通过全参构造方法调用定义的普通方法来赋值
        //2.通过在类中设定set方法来实现私有化属性的赋值

        //而私有化属性值的获取只能通过get方法来进行获取




    }
}

包的引用、常用包

包:成为package,就是用来存放类的文件夹

一般,在创建类的时候,一般在类文件的第一行出现,内容是类存在于项目的src目录下所有的路径(从src开始)

包的取名:一般包以公司倒置的域名作为前缀,再加上项目名,包一般都是用小写名字(没有大写字符)

java.long包下的类可以不用导包

导包一定不能导错包,因为将来会用到很多包,而有很多同名的类方法是在不同的包下的,导错了包会报错。

当导入了两个名字相同但是包不同的对象

其中一个对象会自动把包名当做前缀加在对象前面用以区分

常用包:
java.util

java.sql

java.io

导包:使用 import 关键字

访问控制符

分为两种:

访问控制修饰符

java中访问控制修饰符可以用来保护类,变量,方法(构造方法)被访问的情况

private:私有的  在同一个类中可以被调用,不可以修饰类(类本身定义出来就是给别人用的)

private可以修饰构造方法,但这样以后只有类本身自己可以使用该构造方法

default: 默认的(不需要声明,什么都不写)在类所在的同一个包下可以被调用访问,可以修饰类,变量,方法(包括构造方法)等等

protected:受保护的  在不同包里无法使用,在同一个包下可以被访问和调用,或者其子类都可以被访问,不可以修饰类,可以用来修饰变量,方法

public :公共的 所有位置都可以访问被public修饰的类,变量,方法等

非访问控制修饰符

static, final , abstract , synchronized ,volatile

static修饰符的用法

static修饰成员变量

内存组成(栈,堆,方法区)

1.static修饰的变量是该类的所有对象共享的,可以用来在对象之间共享数据(节省空间)(static修饰的属性值存放在方法区的静态区里,当对象要被打印输出时,系统就会去静态区找现在的值,然后直接输出)

可以修饰成员方法和变量。被修饰的方法成为类方法,修饰的变量成为类变量,直接使用

类.方法名or 类.属性名直接调用

public class Student {
    String name;
    int age;
    static String className; //静态的属性,对象共享

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


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

        System.out.println(Student.className);
        //System.out.println(Student.name);

        Student s1 = new Student();
        s1.name = "张三";
        s1.age = 20;
        s1.className = "1班";
        System.out.println(s1);

        Student s2 = new Student();
        s2.name = "李四";
        s2.age = 22;
        System.out.println(s2);

        Student s3 = new Student();
        s3.name = "王五";
        s3.age = 21;
        System.out.println(s3);

        Student s4 = new Student();
        s4.name = "王五";
        s4.age = 21;
        s4.className = "2班";
        System.out.println(s4);
    }
}
public class StaticDemo {
    static int num;

    public static void main(String[] args) {
        num++;
        StaticDemo s1 = new StaticDemo();
        s1.num++;
        StaticDemo s2 = new StaticDemo();
        s2.num++;
        StaticDemo.num++;
        System.out.println(num); //4
    }
}

static修饰成员方法

static修饰方法,随着类的加载而加载,比如main方法,优先于对象存在,即使没有创建这个类的对象,也可以通过类名调用类中的static方法,被类的所有对象共享

静态方法中,只能访问静态成员变量和 静态方法

public class StaticDemo01 {
    //普通变量
    int number01 = 100;
    //静态变量
    static int number02 = 200;

    public void say(){
        
    }
    
    public static void show(){
        //静态方法中,不能使用非静态的成员变量
        //System.out.println(number01);
        System.out.println(number02);
        //静态方法中,也不能调用非静态的成员方法
        //say();
    }
    //main方法也是静态方法
    public static void main(String[] args) {
       // say();
       // System.out.println(number01);
        System.out.println(number02);
        show();
    }
}

static修饰代码块

代码块分类:

1.局部代码块:定义在方法中,用于限定变量的局部周期

2.构造代码块:声明在类中的成员位置,一般在调用构造方法之前会执行构造代码块(在创建对象之前,或者说是在构造方法执行之前)

3.静态代码块:也是声明在类中的成员位置,多了static修饰符,一般在类加载的时候就会被调用,而且只会执行一次

创建一个对象时,先加载类(静态代码块先执行并且只执行一次)然后执行构造代码块(在构造方法执行之前,即在创建对象之前)。

小案例:查看哪个限制性那个后执行

public class StaticDemo02 {
    static {
        //静态代码块,只执行一次(类加载的时候就执行)
        int a=100;
        System.out.println(a);
    }
    {
        //构造代码块
        int b=200;
        System.out.println(b);
    }
    public  StaticDemo02(){
        System.out.println("构造方法");//因为构造方法是在构造代码块后面执行
    }
    {
        int c=300;
        System.out.println(c);//构造代码块,在创建对象之前执行(构造方法执行之前)
    }
    static {
        int b= 400;//静态代码块,类加载的时候就执行
        System.out.println(b);

    }

}

测试类代码如下

public class StaticTest {
    public static void main(String[] args) {
        {
            int e = 500;//依照代码执行顺序,代码在s2对象创建之前,所以先执行
           System.out.println(e);

        }
        StaticDemo02 s2 = new StaticDemo02();
        StaticDemo02 s3 = new StaticDemo02();
        /* 代码执行结果为如下
        500
        100
        400
        200
        300
        构造方法
        200
        300
        构造方法
        * */
    }
}

继承的定义、继承的好处、如何继承、继承的特征

定义 :

把多个类中,相同的成员提取出来,定义到一个独立的类中。

然后让当前类和独立类之间产生关系,使当前类具有独立类中的成员内容,这种关系,称为继承

有了继承关系后,当前类称为子类,独立类称为父类

写法:

用extends 关键字来实现继承

class 子类名 extends 父类名{}

继承的好处:

1.提高代码的复用性,也可以提高代码的维护性(代码如果有问题,只需要改一个类就行)

2.继承让类与类之间产生了一个关系,是将来学习多态的前提

继承的缺点:

继承会让类的耦合性增强,父类一但发生改变,就会影响到跟他相关的类

会去打破封装性(父类的属性和方法不能设定为private类型,不可封装,否则子类找不到相关父类属性和方法,无法继承)而子类可以通过supper关键字访问父类的构造方法(得到私有属性)或者子类通过调用从父类继承的getter/setter 方法,来完成子类属性和方法的赋值和调用

如果父类的属性和方法被私有化之后,那么就不能继承了(爸爸的私房钱不能给儿子用)

如果想要使用父类的构造方法,必须现在子类中定义自己的构造

然后再通过特殊的方法来访问直接继承的父类的构造方法(super关键字)

super(name,age,gender)

super(name,age, ..............构造方法里的私有化属性)

构造方法没有办法被继承

super表示父类的意思(super只能使用在直接父类上,多重继承不生效)

父类私有化之后,创建子类对象,怎么使用父类的私有属性?

方法一:子类通过super访问父类的构造方法之后,就可以被哪来实例化对象的时候赋值使用了

方法二:子类调用从父类继承的getter/setter 方法,来完成子类属性和方法的赋值和调用

重点:因此不管有没有继承,只要有setter和getter方法,就可以通过getter/setter(或者继承过来),间接完成私有的属性和方法的赋值和调用

java语言里只允许单继承,只能继承一个类,但是可以多重继承

什么时候可以使用到继承?

当两个类之间满足  xxx is a xxxx 关系是时,可以使用继承

继承之后的成员关系

1.成员变量的关系:

如果子类成员变量名和父类变量名不一样,子类调用的就是子类自身的变量名,如果子类的成员变量名和父类的成员变量名一样,这个时候调用的也是自己自身的成员变量

2.成员方法的关系:

成员方法也是类似,子类的成员方法和父类的成员方法,那子类调用的就是自己的成员方法,如果子类的成员方法和父类的成员方法同名,子类还是优先执行调用自己的成员方法。

总结:子类先找自身,再找父类(先找自己有没有,有就直接运行自己的,如果自己没有,再使用父类的)

不管是不是同名的,子类都先优先找自己的,自己的找不到再继承父类的,因此子类继承父类的属性并赋值时,其实是赋值给自己的,而不影响父类的

3.构造方法的关系

只要有继承关系,子类都会默认的访问父类的无参构造,(子类的无参构造访问父类的无参构造)

如果父类没有无参构造,那么代码会报错

如果报错可以怎么解决?

1、给父类加上无参构造

2、子类使用super去访问(父类没有无参构造,则一定声明了其他有参构造)

这个时候子类就可以通过super访问父类的有参构造,但是这个时候子类就不可以使用无参构造创建对象了,只能跟父类一样使用有参构造,创建对象的时候一定要赋值。

如果父类不提供无参构造,那么子类就必须要使用super关键字,而不能使用无参构造创建对象

基本总结:

1.子类继承父类,被继承的父类也被成为超类(基类),子类可以继承父类的所有属性和方法,私有的可以间接继承,不能直接访问

2.java中一个类只能有一个父类(只能继承一个),但是允许多重继承,从而实现继承多个类的效果

3.如果一个创建了一个类,但是这个类没有继承别的类,该类也是继承Object类的

这也是为什么一个新创建的类一开始就有一些现成方法可以使用(其实是继承了Object类得来的)

Object类是所有类的始祖类

4.子类可以拓展属性、方法

5.继承提升了代码的复用性。


 

                             

super

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

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

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

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

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

super调用父类的属性

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

super调用父类的构造方法

必须要写在子类构造方法的第一行(第一句)super()只能写在第一行

写法:super()

1.关于无参构造的调用,子类的无参构造就会默认访问父类的无参构造(即super括号里不赋值)

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

为什么?

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

2.关于有参构造的调用

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方法

//动物类
public class Animal {

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


public class Dog extends Animal {
    private String name;

    public Dog(String type, String color, String name) {
        super(type, color); //通过super访问父类的构造方法
        this.name = name;
    }
    public void show(){
        super.show(); //调用父类的show方法
        System.out.println("我的名字是:" + name);
    }
}

public class DogTest {
    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关键字,不能共存

方法重写的定义

概念:

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

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

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

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

子类为什么要重写父类方法?

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

即父类定义的方法功能太少了,子类会对其进行重写,对父类方法进行扩充

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("父类的私有方法");
    }
}



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("子类重写父类的私有方法");
    }
}

案例:父类Animal

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

    public Animal() {//父类的无参构造一定要写,因为当子类的有参构造里面没有显示super(参数)调用父类的有参构造的话,那么子类的有参构造会默认访问父类的无参构造
    }

    public Animal(String type, String color) {//父类必须要有全参构造,子类才能通过super(带参数的)访问父类这里的带参构造
        this.type = type;
        this.color = color;
    }
    public void show(){
        System.out.println("我的种类是:"+this.type+"我的颜色是:"+this.color);
    }
    public static  void method04(){
        System.out.println("父类的静态方法");
    }
    private void method05(){
        System.out.println("父类的普通方法,子类要重写成静态方法");

    }
}

子类Dog


public class Dog extends Animal{
    private String name;
    public Dog(){
        super();

    }
    public Dog(String type,String color,String name){
        super(type, color); //通过super访问父类的构造方法
        this.name=name;

    }

//    @Override
//    public void show() {
//       super.show();//可以通过super直接调用父类方法,下面再进行扩展
//        System.out.println("我的名称是:"+this.name);
//    }

    @Override//重写注解(用来标识子类重写了父类的方法,如果注解报错,说明重写失败(不存在重写) )

    public void show(){//也可以直接重写父类方法,将其覆盖掉(子类重写方法,参数列表必须一样)
       System.out.println("我的名称是:"+this.name);
    }
//    @Override
//    public static void method04(){
//        System.out.println("子类的静态方法");//子类无法重写父类的静态方法,而且一般子类不会重写父类的静态方法
//    }
//    @Override
//    private void method05(){//对于父类的私有方法,子类也不能重写
//
//    }
    //父类的普通方法,子类也不能定义成静态方法并重写(static静态方法是属于类的,会跟随类的加载而加载,而子类重写以后会寻找父类的静态方法,
    // 但是父类没有该方法,而且静态方法也不能被重写)

}

方法重写的应用

equals()方法重写

直接使用object 的equals方法(是直接返回地址值),因此自己在实际开发中,需要重写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 + '\'' +
                '}';
    }
}



toString()方法重写

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

Object类中的toString()方法如下,表示返回当前类的包名+类名 +@+当前对象hashCode值的16进制

image.png

所以输出对象的时候,最后的结果就是一串值

image.png

 所以将来,类中,一般都会重写toString()方法

相关面试题 :

1,方法重写与方法重载的区别是什么?
方法重写是指继承关系中,子类对于父类同名方法(同样参数列表)的覆盖,本质上是一种继承关系。

而方法重载是指在同一个类中,存在多个同名的方法,方法名相同但是参数列表不同(参数的个数,参数的排列顺序以及参数类型不同),方法的访问修饰符和返回值类型是否相同不作为方法重载的判定点(不影响方法重载)。方法重载包括构造方法重载和普通方法重载。

2,==和equals()方法区别

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

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

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

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

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

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

String类的equals()方法

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

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

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

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值