自动装箱与拆箱、equals()和hashCode()、Comparable与Comparator接口、重载与重写

自动装箱与自动拆箱

把基本数据类型赋值给包装类型叫自动装箱,把包装类型赋值给基本类型叫自动拆箱

Integer a=3;//自动装箱
int b=a;//自动拆箱

自动装箱:自动装箱底层调用的是Integer.valueOf()方法,源码如下:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
}

可以看出,当传入的值在 [IntegerCache.low ,IntegerCache.high]之间时,返回的是i+IntegerCache.low,IntegerCache是Integer类内部的一个静态类,源码如下:

   private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

IntegerCache有静态成员变量cache,为一个拥有256个元素的数组:[-128,127]。cache数组对常用的对象进行了缓存,而-128至127是最常用的Integer对象,即当使用的Integer对象大于等于-128并且小于等于127时不用新建一个Integer对象,而是直接使用缓存,这样做一定程度上提高了效率。

Integer aa=100;
Integer bb=100;
System.out.println(aa==bb);//true
int cc=100;
System.out.println(aa==cc);//true,==时自动拆箱,如果+-*/运算,会将基础数据类型装箱

Integer dd=300;
Integer ff=300;
System.out.println(dd==ff);//false

自动拆箱:自动拆箱底层调用的是intValue()方法,源码如下

public int intValue() {
     return value;
}

注意:以下代码编译时不会报错,运行时会报java.lang.NullPointerException

Integer integer100 = null;
int int100=integer100;

equals()与hashCode()

equals()与hashCode()的作用:

  • equals()方法用来判断对象是否相等,通常判断的是值是否相等。
  • hashCode()方法用于返回一个对象的哈希码(散列码),它实际返回一个int整数。哈希码的作用是确定该对象在哈希表中的索引位置。

equals()与hashCode()的关系

  • 在集合类HashMap、HashSet、Hashtable等等这些本质是散列表的数据结构中,hashCode()和equals()是有关系的:
  • 如果两个对象相等(通过equas()方法比较返回true),那么这两个对象的hashCode值一定相同。如果两个对象通过equals()方法比较返回false,那么它们的hashCode()值也应该不同。
  • 如果两个对象hashCode()相等,它们并不一定相等。因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出两个键值对相等。

重写equals()与hashCode()的原则:

  • 同一个对象无论何时调用hashCode()方法得到的返回值必须一样。
  • hashCode()的返回值相等的对象不一定相等,通过hashCode()和equals()必须能唯一确定一个对象。不相等的对象hashCode()可以相等。
  • 一旦重写了equals()函数,就必须重写hashCode()函数。而且hashCode()的生成哈希值的依据应该是equals()中用来比较是否相等的手段。
  • 如果两个对象相等(通过equals()方法比较返回true),但这两个对象的hashCode()方法返回不同的hashCode值,这将导致 HashSet/HashMap 把这两个对象保存在Hash表中的两个位置,从而使两个对象都可以添加成功,这就与Set集合不存在重复元素的规则冲突了。

如果需要把某个类的对象保存在HashSet集合中,重写这个类的equals()方法和hashCode()方法时,应尽量保证两个对象通过equals()方法返回true()时,它们的hashCode()方法返回值也相同。

Comparable与Comparator接口

  • 一个类实现了 Comparable 接口,意味着该类的对象可以直接进行比较(排序),但比较(排序)的方式只有一种,很单一。对象的耦合度高(需要改变对象的内部结构,破坏性大)。实现了Comparable接口的类的对象的列表数组可以通过Collections.sort()Arrays.sort进行自动排序。
  • Comparator比较器,一个类如果想要保持原样,又需要进行不同方式的比较(排序),就可以定制比较器(实现 Comparator接口)。需要比较的对象不需要实现任何接口,只需要在排序的时候传入一个比较器即可,对象本身不用做任何改变。,comparator相当于一通用的比较工具类接口。需要定制一个比较类去实现它,重写里面的compare方法,方法的参数即是需要比较的对象。
  • 如果对象的排序需要基于自然顺序,请选择 Comparable,如果需要按照对象的不同属性进行排序,请选择 Comparator。

比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数

//实现类的对象之间比较大小,那么这个类就要实现Comparable接口,然后重写compareTo()方法
public class people implements Comparable<people>{

    private String name;
    private int age;
    private String sex;

    //省略getter/setter方法、构造器、toString()

    @Override
    public int compareTo(people o) {
        return this.age - o.age;
    }
}
Collections.sort(list,new Comparator<people>(){   
	@Override   
	public int compare(people o1, people o2) {    
		if(o1.age==o2.age&&o1.name==o2.name){     
			return 0;    
		}else if(o1.age>o2.age){     
			return 1;       
		}else{     
			return 0;    
		}   
	}  
}); 

重载(overload)、重写(overwrite)

重载:一个类里定义多个同名方法,只需要参数列表不同。规则:两同一不同

  • 在同一个类中
  • 方法名相同
  • 参数列表不同

重写:子类继承父类时,定义了和父类同名的方法,就叫重写。规则:两同两小一大

  • 方法名相同,参数类型相同
  • 子类方法返回类型小于等于父类方法返回类型
  • 子类方法抛出异常小于等于父类方法抛出的异常
  • 子类方法访问权限大于等于父类方法访问权限

问:为什么方法的返回值不能用于区分重载?
答:Java调用方法时可以忽略返回值

String、StringBuffer、StringBuilder

在Java中,字符串被作为String类型的对象来处理。String类位于java.lang包中,默认情况下被自动全部导入。

  • String类被称为不可变字符序列,原因就是它的底层是由final修饰的字符数组存储的,所以每次重新赋值只是新建了一个对象之后将原来的引用指向它,这样会产生大量的内存垃圾。
  • StringBuffer是线程安全的,同时比String类更高效,特别是对字符串进行连接操作时,使用StringBuffer类可以大大提高程序的执行效率。StringBuffer是线程安全的,因为方法大多数都被synchronized修饰了。
  • StringBuilder类提供了与StringBuffer类兼容的API,被设计用作StringBuffer的一个简易替换,在单线程环境下,它比StringBuffer类要快。但是在多线程环境下StringBuilder是线程不安全的。使用StringBuilder类处理字符串的方法与StringBuffer类基本一样。

抽象类、抽象方法、接口

抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法。

抽象类的作用:抽象类主要用于模板模式中:编写一个抽象父类,父类提供多个子类的通用方法,并把一个或多个方法留给子类实现,这就是一种模板模式。

抽象类与抽象方法的规则如下:

  • 抽象类不能被实例化,只能当做父类被其他子类继承,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例
  • 抽象方法不能有方法体
  • 抽象类的构造器不能用于创建实例,主要用于被其子类调用
  • 含有抽象方法的类只能被定义抽象类
  • 当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(重写)。而final修饰的类不能被继承,final修饰的方法不能被重写,因此final和abstract不能同时使用

接口:接口是从多个相似类中抽象出来的规范,接口不提供任何实现。接口体现的是规范与实现分离的设计哲学。接口定义的是多个类的公共行为规范。对接口有以下规定:

  • 接口中的普通方法都是使用public abstract修饰的,并且方法不能有方法体;但类方法、默认方法都必须有方法体。
  • 接口中的变量都是public访问权限,定义接口成员时,可以省略访问权限控制符,如果指定权限,只能是public。

抽象类和接口的区别

  • 抽象类中可以构造方法 ,接口没有构造函数
  • 类可以实现很多个接口,但是只能继承一个抽象类
  • 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。(Java8 接口可以有实例方法 需要关键字default)
  • Java接口中声明的变量默认是public static final(必须赋初始值)。抽象类可以包含非final的变量。
  • Java接口中的成员函数默认是public abstract的。抽象类的成员函数可以是private,protected或者是public。
  • 接口可继承接口,不能继承类(抽象类和普通类) 抽象类可继承接口也可继承具体类(继承接口时可只实现部分方法)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值