9_14 前几天复习总结

本文深入探讨了Java中的Boolean赋值、Math方法、COW机制、String hashCode实现、Integer缓存、Thread join方法、Array remove方法、Math round方法、super与this用法及成员变量继承等关键概念。
摘要由CSDN通过智能技术生成
  1. Boolean赋值问题
    1. 下面的程序段是正确的,程序的执行流程是将 flag 赋值为 true 再去看 if 后的括号中的结果是true 还是 false, 在经过赋值之后括号中就是 true 了,所以the flag is true会被打印出来。

              public static void main(String []args){

                     Boolean flag = false;

                     if(flag = true ){

                            System.out.println(“the flag is true”);

                     }

              }

 

  1.  
  2. Math. ceil 和 Math.floor 方法
    1. 在官方文档中,Math.ceil()方法返回的是大于等于当前数字的最小整数,实例如下

                   double i = -0.5;

                   System.out.println(Math.ceil( i ));

                   //输出的是0,因为大于等于 -0.5 的最小整数是 0

                   i = -1;

                   System.out.println(Math.ceil(i));

                   //输出的是 -1 ,因为 -1 满足了 大于等于 -1 的最小整数。

b)  floor方法和ceil 相反,返回的是小于或者等于当前数字的最大整数

 

3、COW(Copy-on-write)写时复制,是指在并发下,线程对容器的对该不应该直接修改容器本身,而是应该赋值一份副本,在修改后将副本重写回容器。,下边这个例子就是没有使用写时赋值带来了并发问题,问题的关键在于,当访问最后一个容器执行到 int lastIndex = list.size() – 1,然后就进入阻塞队列,然后删除最后一个元素的线程在这个时候把最后一个线程删除,那么等到获取最后一个元素的线程重新获得cpu ,它就按刚刚计算得到的 list.size() – 1 得到的值去访问元素,这样的话就会报异常了,因为这个时候后一个元素已经被删除掉了。

public class ProblemOnVisitVector {

    public static void main(String[] args)    {

        // 初始化Vector
        Vector<String>  vector = new Vector();


            vector.add("关注公众号");
            vector.add("Java3y");
            vector.add("买Linux可到我下面的链接,享受最低价");
            vector.add("给3y加鸡腿");

            new Thread(() -> getLast(vector)).start();
            new Thread(() -> deleteLast(vector)).start();
            new Thread(() -> getLast(vector)).start();
            new Thread(() -> deleteLast(vector)).start();

    }

    // 得到Vector最后一个元素
    private  static Object getLast(Vector list)   {
        int lastIndex = list.size() - 1;
        try {
            TimeUnit.MICROSECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return list.get(lastIndex);
    }

    // 删除Vector最后一个元素
    private static void deleteLast(Vector list) {
        int lastIndex = list.size() - 1;
        list.remove(lastIndex);
    }

}

 

4、String.hashCode() 方法的原理是,s 数组就是保存这String 的值的数组,那么就会出现两个不同的String 的hashCode 一样的情况(成为哈希碰撞)

              s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]     ( i * 31 = i * 21 – i;)

下边是示例两个不同的String 的hashCode 相同造成 equals 方法返回 true

String str1 = "通话";
String str2 = new String("重地") ;
System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));

 

5、Integer 分配内存的问题,

       a、问题的根源在于Integer.valueOf(int i); 这个方法会先去看一个叫做 IntegerCache的东西,这里存放这实例化Integer 的时候如果值在 [-128, 127] 的话,就把他们存进去,以后实例化Integer 对象的时候,就先去看 IntegerCache 中是否有这个数,有的话直接返回一个引用,没有的话再去new 一个 Integer对象

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

       b、但是 Integer a = 1000; Integer b = 1000; a == b 返回值就是 false 了,因为 1000 已经无法放在缓冲区里了,在这样会造成在堆中开辟两份内存存放这两个 1000 ,所以返回的就是 false 了

public static void main(String[] args) {
    Integer a = 128;
    Integer b = 128;
    System.out.println(a == b); // 这里返回的是 false

    a = 127;
    b = 127;
    System.out.println(a == b); // 这里返回的是 true
    String aa = "hello"; String bb = "hello";
    System.out.println(aa == bb);
}

 

6、Thread.join() 方法,这个方法的作用是等待当前线程执行完毕后再往下执行。

       a、Thread.join()方法说到底就是下边这几行代码,有三个重点

while (isAlive()) {
    wait(0);
}

  1. join方法会先去判断线程是否是或者的,所以使用join的时候一定要先用start启动线程
  2. join方法会释放锁,因为wait方法会释放锁。
  3. join方法的本质是等待0秒钟,就是说他会释放锁之后马上又获得cpu,又拿到锁。

7、Array.remove 方法,查看源码可以看到这个方法是有重载的,分别是

 

public E remove(int index) {
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
    return oldValue;
}

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

也就是说,当入参是int 类型的时候,是根据下标去删除元素的,所以在下边这个题目中第一次会把元素 1 (是元素为 1, 不是下标为 1)给删除,然后当遍历到元素 4 的时候,就会因为下标越界的问题而报错了。

public static void main(String[] args) {
    List<Integer> NumberList = new ArrayList<>();
    NumberList.add(2);
    NumberList.add(4);
    NumberList.add(1);
    NumberList.add(3);
    NumberList.add(5);
    for (int i = 0; i < NumberList.size(); i++) {
        int v = NumberList.get(i);
        if(v % 2 == 0){
            NumberList.remove(v);
        }
    }
    System.out.println(NumberList);
}

8、Math.round方法,这是四舍五入方法。本质是 floor( x + 0.5)  floor 就是返回小于等于这个数的最大整数(也就是向下取整)

 

9、当类有String类型的成员变量的时候,实例化对象的时候和就会为这个String 赋值,这个赋值和普通的 String a = “ABC”; 是一模一样的,同样回去判断常量池中是否存在值为“ABC”的String 对象,如果有的话就取得它的一个引用,没有的话就实例化一个。下边的这个实例中,test和testB 在实例化的时候都会为name 赋值,在testB 实例化的时候发现常量池已经有了“ABC”这个String 对象了,所以就只是简单返回了一个引用而已,所以test.name == testB.name 得到的是 true

public static void main(String[] args) {
    Test test = new Test();
    Test testB = new Test();
    String result = test.equals(testB) + ",";
    result += test.name == testB.name;
    System.out.println(result);
}

 

10、super() 和 this() ,没有参数也没有点什么什么的,super()表示的是父类的无参构造方法,也可以是指向父类对象的一个引用,因为super().xxx 可以访问具备足够权限的成员变量和方法, this()表示当前类的无参构造器,也可以引用当前的这个对象

       a、在子类的构造方法中,默认会在构造方法的第一行调用父类的无参构造器(意思就是说如果在子类如果没有调用父类的无参构造器的话,那么父类的无参构造器是要存在的,不然子类就调用不到了)

       b、在子类的有参构造器中,如果写this()的话,就是调用了当前类的无参构造器了,注意,这个时候有参构造器是没有直接调用父类的无参构造器的,这个是在子类的无参构造器中调用的。

       c、super()和this()使用的时候都需要放在方法的第一行,否则会报错,这样一来的话这两个就不可以放在同一个方法中了。

       d、在静态方法和静态代码块中不能使用this() 和 super()

       e、在子类的构造方法中可以不用在第一行显式调用super()

 

11、当父类的成员变量生命为private 的时候,子类是可以继承到这个成员变量的,但是在使用的时候会受到private 的约束而不可使用,下边这个例子中,可以通过反射得知子类Test是有name 这个成员变量的,但是name的作用域仅仅在TestFather中,所以在子类中是无法访问到了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值