基础知识

重载重写

void invoke(Object obj, Object... args) { ... }
void invoke(String s, Object obj, Object... args) { ... }

invoke(null, 1);    // 调用第二个invoke方法
invoke(null, 1, 2); // 调用第二个invoke方法
invoke(null, new Object[]{1}); // 只有手动绕开可变长参数的语法糖,  // 才能调用第一个invoke方法

重载

  • 在 Java 程序里,如果同一个类中出现多个名字相同,并且参数类型相同的方法,那么它无法通过编译。也就是说,在正常情况下,如果我们想要在同一个类中定义名字相同的方法,那么它们的参数类型必须不同。这些方法之间的关系,我们称之为重载
这个限制可以通过字节码工具绕开。也就是说,在编译完成之后,我们可以再向class文件中添加方法名和参数类型相同,而返回类型不同的方法。当这种包括多个方法名相同、参数类型相同,而返回类型不同的方法的类,出现在Java编译器的用户类路径上时,它是怎么确定需要调用哪个方法的呢?当前版本的Java编译器会直接选取第一个方法名以及参数类型匹配的方法。并且,它会根据所选取方法的返回类型来决定可不可以通过编译,以及需不需要进行值转换等。
  • 除了同一个类中的方法,重载也可以作用于这个类所继承而来的方法。也就是说,如果子类定义了与父类中非私有方法同名的方法,而且这两个方法的参数类型不同,那么在子类中,这两个方法同样构成了重载。
那么,如果子类定义了与父类中非私有方法同名的方法,而且这两个方法的参数类型相同,那么这两个方法之间又是什么关系呢?如果这两个方法都是静态的,那么子类中的方法隐藏了父类中的方法。如果这两个方法都不是静态的,且都不是私有的,那么子类的方法重写了父类中的方法。

返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准

重载方法的选取
  • 重载的方法在编译过程中即可完成识别。具体到每一个方法调用,Java 编译器会根据所传入参数的声明类型(注意与实际类型区分)来选取重载方法。
选取的过程共分为三个阶段
  • 在不考虑对基本类型自动装拆箱(auto-boxing,auto-unboxing),以及可变长参数的情况下选取重载方法;
  • 如果在第 1 个阶段中没有找到适配的方法,那么在允许自动装拆箱,但不允许可变长参数的情况下选取重载方法;
  • 如果在第 2 个阶段中没有找到适配的方法,那么在允许自动装拆箱以及可变长参数的情况下选取重载方法。
多个匹配时候的选取
  • 如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么它会在其中选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系。
  • 在开头的例子中,当传入 null 时,它既可以匹配第一个方法中声明为 Object 的形式参数,也可以匹配第二个方法中声明为 String 的形式参数。由于 String 是 Object 的子类,因此 Java 编译器会认为第二个方法更为贴切。

重写

  • Java 虚拟机中关于方法重写的判定同样基于方法描述符。也就是说,如果子类定义了与父类中非私有、非静态方法同名的方法,那么只有当这两个方法的参数类型以及返回类型一致,Java 虚拟机才会判定为重写。
  • 在子类中可以根据需要对从基类中继承来的方法进行重写。2、重写的方法和被重写的方法必须具有相同方法名称、参数列表和返回类型。3、重写方法不能使用比被重写的方法更严格的访问权限

判断相等

==

  • 当使用 == 比较两个基本数据类型的时候, 就是在比较它们各自在内存中的值
  • == 判断两个引用数据类型是否相等的时候,实际上是在判断两个引用是否指向同一个对象——> 是否是同一个内存地址

equals

  • java中万物皆对象,我们经常要面临的问题是这两个对象是否相等,而不是这两个对象背后的数据是否相等,仅有==是完全不够用的。
  • 由于Java程序员们会创建各种满足它们业务需求的对象,系统无法提前知道两个对象在什么条件下算相等,Java干脆把判断对象是否相等的权力交给编程人员
  • 具体的措施是:所有的类都必须继承 Object 类,而 Object 类中写有equals()方法。编程人员可以通过重写 equals() 方法来实现自己的比较策略,也可以不重写,使用Object类的equals()比较策略。
//Object类中的equals()方法源码
public boolean equals(Object obj) {
    return (this == obj);
}
  • 从 Object 类的equals()源码可以看到,如果编程人员没有显示地重写 equals() 方法,则默认比较两个引用是否指向同一个对象

基本数据类型包装类的比较

public static void main(String[] args) {
    int a = 3;
    Integer b = new Integer(3);
    System.out.println(b.equals(a));	//true, 自动装箱
}

  • 基本类型包装类在重写equals()后,比较的还是基本数据类型的值,但是比较的方式还是装箱后比较
//Integer类中的equals方法
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

equals 和 hascode

  • 在java中,equals和hashcode是有设计要求的,equals相等,则hashcode一定相等,反之则不然。所以要求重写equals 的时候必须重写hashcode

在集合中,比如HashSet中,要求放入的对象不能重复,怎么判定呢?
首先会调用hashcode,如果hashcode相等,则继续调用equals,也相等,则认为重复。
如果重写equals后,如果不重写hashcode,则hashcode就是继承自Object的,返回内存编码,这时候可能出现equals相等,而hashcode不等,你的对象使用集合时,就会等不到正确的结果

final

  • 一般比较基本的类型或防止扩展类无意间破坏原来方法的实现的类型都应该是final的。

修饰变量

  • 凡是对成员变量或者局部变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作final变量。final变量经常和static关键字一起使用,作为常量。
  • final修饰基本数据类型的变量时,必须赋予初始值且不能被改变,修饰引用变量时,该引用变量不能再指向其他对象

修饰方法

  • final也可以声明方法。方法前面加上final关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为final
  • 。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定

修饰类

  • 使用final来修饰的类叫作final类。final类通常功能是完整的,它们不能被继承。Java中有许多类是final的,譬如String,Interger以及其他包装类。

final关键字与static对比

  • static关键字修饰变量时,会使该变量在类加载时就会被初始化,不会因为对象的创建再次被加载,当变量被static修饰时就代表该变量只会被初始化一次

image-20201126171351643

sleep() 和 wait() 有什么区别

  1. 类的不同:sleep() 来自 Thread,wait() 来自 Object。
  2. 释放锁:sleep() 不释放锁;wait() 释放锁。
  3. 用法不同:sleep() 时间到会自动恢复;wait() 可以使用 notify()/notifyAll()直接唤醒。

Comparator 与Comparable 有什么不同

  • Comparable 接口用于定义对象的自然顺序,是排序接口,而 comparator 通常用于定义用户定制的顺序,是比较接口。
  • 我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序

抽象类与接口

  1. 抽象类是指不允许被实例化的类;一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。

  2. abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系

  3. 实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。但在Java8中允许接口中有静态默认的方法。

  4. 接口中定义的变量默认是public static final型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。

  5. 子类中实现父类中的抽象方法时,可见性可以大于等于父类中的;而接口实现类中的接口方法的可见性只能与接口中相同(public)。

&和&&

  • &和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。

  • &&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。

  • &还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位。
    有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。

  • &还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值