今日小记0306

方法的重写

子类中如果创建了一个与父类相同名称、相同返回值类型、相同参数列表的方法

只是方法体中的实现不同,以实现不同于父类的功能,扩展增强

这种方式被称为方法重写(override),又称为方法覆盖。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

Object类

Java里所有的类都有一个共同的父类Object,不管你愿不愿意都得继承他(默认继承,不用加extends)

此外,还有许多在这些类上+s的比如Objects类,表示是Object的工具类 备胎男

所以,如果你不重写方法(比如equals,toString等等)就会默认调用Object类里面的方法,产生不一样的结果!

比如Obj类里面的equals和String类里面的equals是不一样的!

toString类

用于输出类的值

在jdk帮助文档中给出明确介绍,会返回一个

getClass().getName() + '@' + Integer.toHexString(hashCode())

重写:

alt+ins 选择toString()即可

这里idea会让你选择输出类的属性,比如一个学生类,选择输出id,name,sex,里面的一种或几种

@Override
public String toString() {
    return "User{" +
            "uname='" + uname + '\'' +
            ", password='" + password + '\'' +
            '}';
}

hashcode类

C语言实现 没有源代码

为不同的对象返回不同的整数int 有些时候obj的hashcode就是你在内存中的地址(如果不重写)

如果重写 hashcode禁止相同!!确定对象的唯一性

每次重写hashcode的时候都会绑定一个equals方法

@Override
public int hashCode() {
    return Objects.hash(id, name);

equals类

如何比较两个对象 基本数据类型:值 引用数据类型:内存地址

== 比较地址 指针操作 Obj类里面equals比较的是值 源码用的还是==

case1

当我们遇到这种情况,比较两个对象是否相等?对象有很多元素,比如id,name,date,age...但是我们判断的唯一标准选择id即可。这时需要重写equals类。

@Override
public boolean equals(Object o) {
    if (this == o) return true;//先比较对象的内存地址是否相同
    if (o == null || getClass() != o.getClass()) return false;//对象是不是空,两个对象在不在一个类里面
    Star star = (Star) o;//强转obj=>star
    return idcard == star.idcard;
}
​
@Override
public int hashCode() {
    return Objects.hash(idcard, name, info);
}

上面这个代码建议把hashcode里面的参数和euqals保持一致 夫妻一体同心

case2

当然,如果要比较的对象是组合关系,比如下面这段。必须!!!重写自定义属性类的equals方法。否则就默认调用obj的equals(==)

public static void main(String[] args) {
    Computer mac = new Computer(111,"mac", new Cpu(11,"m1"));
    Computer win = new Computer(111,"win", new Cpu(11,"i7"));
    //内存地址不等
    System.out.println(mac==win);
    //属性的值
    System.out.println(mac.equals(win));
}

Computer类里的元素包含了Cpu类

class Computer{
    public int id;
    public  String name;
    public Cpu cpu;
​
    public Computer(int id, String name, Cpu cpu) {
        this.id = id;
        this.name = name;
        this.cpu = cpu;
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Computer computer = (Computer) o;
        return id == computer.id && Objects.equals(cpu, computer.cpu);//调用了cpu类的equals 如果不重写就调用obj的
        //int类型==
        //string类型equals str类重写
    }
​
    @Override
    public int hashCode() {
        return Objects.hash(id, cpu);
    }
}

cpu类

class Cpu{
    public int id;
    public String name;
​
    public Cpu(int id, String name) {
        this.id = id;
        this.name = name;
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cpu cpu = (Cpu) o;
        return id == cpu.id;
    }
​
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

case3

如果一个类有1000个属性。有8个对象,如何找到两个相等的呢?

答:先比较hashcode,再equals

这俩是夫妻 hashcode具有假唯一性(大部分的元素hashcode都不想等 但是不排除有相等的情况)

盒子原理:把三个苹果放到两个盒子中要求每个盒子至少有一个苹果 那么肯定有一个盒子中装了两个苹果

所以hashcode和euqals的重写是一起的,并且equals选择了哪些元素,hashcode就一定选择哪些(当然,也可以比equals少,equals更严格)

即只要equals了他们的hashcode一定相等!!! 反过来不成立

题外话——类的构造函数

快捷键:alt+ins

此时会自动生成一个有参的构造函数,在主函数里面给对象的属性赋值的时候就会自动帮你完成一些初始化操作。

如果没有再定义一个无参构造函数的话上面new对象的代码会报错。

Teacher lisa = new Teacher(111, "lisa");
Teacher bob = new Teacher(111, "bob");

如果没有定义有参构造,这样写即可

Teacher lisa = new Teacher();

但是根据秦老师说的如果写了有参构造,就必须把无参构造也写去!!!

这样new的时候怎么写都不会报错啦~

clone类

浅克隆

首先借助Object.clone()方法

克隆类要实现Cloneable接口,但他是一个标记接口(空的)

重写Object.clone()方法,提高访问权限,把protected改成public

对引用的克隆对象进行转型

抛出CloneNotSupportedException异常或

class Desk implements Cloneable{
    public int id;
    public String name;
​
    public Desk(int id, String name) {
        this.id = id;
        this.name = name;
    }
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
​
    @Override
    public String toString() {
        return "Desk{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Desk desk = (Desk) o;
        return id == desk.id && Objects.equals(name, desk.name);
    }
​
    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

主函数

public static void main(String[] args) throws CloneNotSupportedException{//抛出异常 
    Desk desk1 = new Desk(1,"blues");
    //desk2的引用指向了desk1
    //Desk desk2 = desk1;
    Desk desk2= (Desk) desk1.clone();//转型
​
    System.out.println(desk2==desk1);//虽然是克隆的 副本 但是地址不一样 ==比较地址
    System.out.println(desk2.equals(desk1));//重写后是true
​
}

深克隆

深克隆方法:

浅克隆的他都要有,本质就是对克隆对象的子类对象也进行一遍克隆,实际上也是一样的操作

对子类也implements cloneable

重写clone函数改成public

再修改一下总对象(小汽车)的clone方法

新建一对象(即克隆后的小汽车)将此对象的属性也都克隆

class car implements Cloneable{
    public int id;
    public Engine engine;
    public Tire tire;
​
    public car(int id, Engine engine, Tire tire) {
        this.id = id;
        this.engine = engine;
        this.tire = tire;
    }
    public car(){
​
    }
​
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        //deepc是被克隆对象
        car deepc=(car) super.clone();//super是基类
        //engine的深度克隆
        deepc.engine= (Engine) this.engine.clone();//克隆完返回的是obj,需要强转 this本类
        //tire的深度克隆
        deepc.tire= (Tire) this.tire.clone();
        return deepc;
    }
​
    @Override
    public String toString() {
        return "car{" +
                "id=" + id +
                ", engine=" + engine +
                ", tire=" + tire +
                '}';
    }
​
}
class Engine implements Cloneable{
    public int eid;
    public String ename;
​
    public Engine(int eid, String ename) {
        this.eid = eid;
        this.ename = ename;
    }
​
    public Engine() {
    }
​
    @Override
    public String toString() {
        return "Engine{" +
                "eid=" + eid +
                ", ename='" + ename + '\'' +
                '}';
    }
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
​
​
}
class Tire implements Cloneable{
    public int tid;
    public String tname;
​
    public Tire(int tid, String tname) {
        this.tid = tid;
        this.tname = tname;
    }
​
    public Tire() {
    }
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

主函数

public static void main(String[] args) throws CloneNotSupportedException{
    car car1 = new car(11,new Engine(221,"v8"),new Tire(331,"mql"));
    car car2= (car) car1.clone();
    System.out.println(car1.toString());
    System.out.println(car2.toString());
    System.out.println("===========");
    car1.engine.ename="ved";
    System.out.println(car1.toString());
    System.out.println(car2.toString());
}

包装类

Java不是完全面向对象的语言,因为他有一些基本数据类型。

在设计类的时候为每一个基本数据类型设计了一个对应的类代表

包装类的名字基本和原来类型一致,除了int和char

final修饰的类 太监类 不能被继承 里面的方法也不能重写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值