java工具类-包装类使用和源码解析

可能是太久没出去玩了吧,这几天实在是有点懈怠了,做事总提不起精神,正在慢慢调整状态,毕竟现在的吃苦会让未来一切都变得值得
毕竟有足够的钱买各种设备它不香么
猜猜这是北京 哪里
在这里插入图片描述

java的开发者帮用户写好了很多工具类,让用户通过导包就能使用它、
这些包目前只有两个包uitil 和lang ,lang包里面的类使用,不需要在类中导包就能直接使用
有些在开发中经常用,有的是笔试的热点知识
总之工具类是一个java程序员永远绕不开的一个技术栈

Object解析

首先我们很有必要了解一个java最特殊的一个类,万类之祖:Object,所有的类默认继承Object
我们通过Object的原码来学习它//在idea编辑器中按ctrl+单机就能转到源码页面

public final native Class<?> getClass();
//native 修饰符修饰,到了这里这个方法的实现就再也看不到了,它的背后就是用非java语言写的
//返回值是一个Class类型:这里简单说下这是什么这里你可以说成是我之前提到的类模板,它在现实生活中就像是一个金属制品的模具你可以用它在灌入金属液体后形成一个个金属制品,这个东西将会是java反射知识的主角
public native int hashCode();
//获取对象的hash值,底层有相关的hash算法解析这个对象,基本上hash值相同的两个对象引用,他们指向的对象都是同一个,但是仅仅只是基本,有少数情况相同的hash情况hash值,但这种概率非常小,而且hash底层是一些数学运算,相比下面的equals找地址比地址确实是性能快很多。所以在大数据情况下用hashcode辨别是否相同就显得非常给力。
public boolean equals(Object obj) {return (this == obj);}
//eqlues方法很多来工具类或者封装好的类为了业务需求都会去重写这个方法,因为 == 是判断对象的地址是否相同,但有时候我们还想判断对象内部包裹的某些值是否相同这时候重写equals方法就显得很重要
//简单复习的方法重写的定义:1发生在父子类,子类更改完善父类的其中一个方法,方法名和参数列表相同,2修饰符权限子类大于等于父类,3返回值类型小于等于父类,4抛出异常个数和类型都小于父类
protected native Object clone() throws CloneNotSupportedException;
//创建并返回次对象的一个副本
public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}
//用String来表示该字符串,看下方法块也能大概猜出字符串都有些啥 名字+@+hash
//表示方式  对象类名@Hashcode码
//我们在直接输出一个对象时候 如:System.out.println(person)//默认就是调用person.toString 方法

public final native void notify();
//唤醒在该对象监听器上等待的单个线程
public final native void notifyAll();
//唤醒在该对象监听器上等待的所有线程
public final native void wait(long timeout) throws InterruptedException;
//超过指定时间量后让当前线程等待

public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }

        wait(timeout);
    }
    //让当前线程等待
    
protected void finalize() throws Throwable { }
//在对象不再被任何引用指向时候,让垃圾回收器调用此方法

接下来开始介绍包装类
一句话说明包装类的作用:将基本数据类型以对象的形式进行操作:
有八大包装类分别对应八大基本数据类型
byte-Byte short-Short int-Integer long-Long float-Float double-Double boolean-Boolean char-Character
//除了int 和char 都是将类型的首字母大写

一.包装类所在的包 java.lang

二.构造方法

如:
new Integer(int x)
new Integer(String x)
//构造方法原码如下:

private final int value;
 public Integer(int value) {
        this.value = value;
 }
 public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
        //parseInt的源码就比较复杂些,因为是将字符串转成Integer类型,中间会有很多判断机制
        //如果这字符串不是“123”真的就是真字符串“我爱你”这种是转不了的会有些异常处理机制
        //爆出NumberFormatException
        //这个10叫做radix是一个判断字符串是否在允许字符串之间转换的基数之内,会做一些判断
        //如果小于2大于32 ,或者为空,都会爆出NumberForamtException
        //初始判断如下
         if (s == null) {
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {
           throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
  		throw new NumberFormatException("radix " + radix +
                                           " greater than Character.MAX_RADIX");
        }
        //后面就是一个个的遍历字符串里面的元素,如果合法就转成int不合法就爆出异常
       
 }
 		//parseint 本身还有个方法重载这是用户自己经常用的,不过底层还调用了重载的方法,只是判断基数默认赋值了10
 		 public static int parseInt(String s) throws NumberFormatException {
        		return parseInt(s,10);
     	}

    

三.实现接口

除了Character和Boolean继承父类number和实现接口Comparable,而Character 和Boolean 是继承java.io.Serializable和Compare
//下面以Integer 作为举例

public final class Integer extends Number implements Comparable<Integer>

我们来看看Number的源码

public abstract class Number implements java.io.Serializable {
  public abstract int intValue();
  public abstract long longValue();
  public abstract float floatValue();
  public abstract double doubleValue();
  public byte byteValue() {
        return (byte)intValue();
  }
  public short shortValue() {
        return (short)intValue();
  }
  //byte和short都是直接用intValue 后把结果转成自己的类型

六个包装类都会重写他们对应的xxxValue()方法
我们还是从Integer的源码去看看这intValue() 是做什么的

private final int value;
public int intValue() {
        return value;
    }

//Integer类中有个 value 属性, 代表的是Integer包装类包着的数字 ,而intValue 方法就是直接把这个属性return回去
//相当于把包装类引用类型变成 int类型 但是因为是return 你还要用 新的int 变量来接住它才能完成这次类型转换
如:
int c =10
Integer a =new Interger(a);
int b=a.valueof();//这其实挺不方便,一套类型转换涉及到多个变量
在java1.5版本后,提供了一个自动包装类的机制
如:
Integer a= 10//基本类型通过等于直接转换成引用类型,内部自动调用了valueof方法
//valueof原码:

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

int value = new Integer(10)//引用类型在等号赋值时候自动转换成基本类型//内部自动帮你调用intvalue方法

四:常用方法总结

1.parseXXX("")//把String类型转化成基本类型
2.xxxValue(“”)//将引用类型转化基本类型
3、.equlas()//比较两个包装类的值是否相等
//例子
Integer a= 1;
Integer b= 1;
a.equals(b);
这方法很重要,重要的东西我们都得看看源码

//方法重写了Object 的equals方法,原来Object的方法是 == 比较他们在堆内存地址是否一样
  public boolean equals(Object obj) {
        if (obj instanceof Integer) {//判断这个对象是否属于Integer类
            return value == ((Integer)obj).intValue();
            //把对象变成Integer类型后再调用它的intValue方法 变成int
            //在和我们自己对象的 vlaue 进行基本类型比较
        }
        return false;
    }
这里大家可能晕了== 到底比较啥:1.在基本类型时候比较值2.在引用类型时比较地址是否一样

其他方法开发并不怎么常用,要是有其他业务需求可以自行去查api文档

Integer相关笔试题:

很重要,看题:

Integer a1= 10;
Integer a2=10;
Integer a3=new Integer(10);
Integer a4=new Integer(10);
System.out.println(a1==a2);
System.out.println(a1==ia);
System.out.println(a3==a4);
System.out.println(a1.equals(a2));
System.out.println(a1.equals(a3));
System.out.println(a3.equals(a4));

完成这道题首先我们先知道 == 和equals区别
equals比值毫无疑问后面三个返回true
a3 和a4 都是在堆内存中新new 了一个对象,指向的地址肯定不同
那a1和a2呢:我们看下内存结构
在这里插入图片描述
没有new 对象的情况下两个Integer 对象默认都指向 静态元素区 的value 为10 的Intege对象
所以a1和a2 地址一样== 返回true
但是这样的情况是有条件的什么条件我们来看看Integer源码:

//这里有个静态内部类就是我刚刚图中的10 所在的位置它有一个叫做cache的Integer 数组 我们看到在static 块这个最先被执行的部分里我们一个个的将数组从-128 到127 这256个数字里赋值到cache数组里面
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() {}
    }

这就意味这每次我将-128~127以内的数赋值给Integer对象时候
我们将其指向我们数组里面的其中一个对应的 元素
但是如果超过了这个范围我们的Integer就自己新包装一个对象赋值给变量
这就导致了下面的情况
Integer i1=1000;
Integer i2=1000;
i1==i2 返回false;

//–这个部分真的经常考,倒也不是单独出个题,就夹在题目的某行代码里稍微不注意就踩坑

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读