死锁、常用类之数学、日期时间API、数组的算法升华、数组的工具类

一.死锁:

1.当两个或者更多隔线程互相持有对象想要的资源不放手,就会死锁

2.当同步代码快或同步方法中出现了嵌套使用

(1)同步代码快中,出现了另一个同步代码快,或调用了另一个同步方法

(2)同步方法中,出现了同步代码快,或者调用了另一个同步方法,而且两者之间有使用对象要的锁对象等资源时,就有可能出现死锁状态,尽量避免

如果出现了,要么手动停止,或者说我们要制造异常,让线程从死锁状态出来,然后再去抢夺资源。

2.sleep方法和wait方法有什么区别?

(1)sleep方法在Thread类中声明,是静态方法,通过Thread类.sleep()调用

(2)wait方法在Object类中声明,是非静态方法,通过锁对象.wait() 调用

wait方法和notify为什么要在Object中声明“

因为wait方法必须是对象调用,但是锁对象是任意类型的对象

那么意味着任意类型的对象都必须具备wait方法,这样的方法只能放在根父类中声明

(2)sleep方法是必须制定时间,等待时间到了,或中途被interrupt了,就会自动醒来

wait方法,一种是指定时间,一种是无限时等待如果无限时等待必须notify唤醒之后才能继续

(3)当前线程遇到了sleep方法不会释放锁得,一直要等当前线程结束,才会释放锁

public class TestSleepWait {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        MyThread m2 = new MyThread();

        m1.start();
        m2.start();
    }
}
class MyThread extends Thread{
    private int num = 1;
    public void run(){
        synchronized (MyThread.class) {
            System.out.println(num++);
           /* try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
            try {
                MyThread.class.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

二、常用类之数学

1.java.long,math类

(1)public static double sqrt(double a):求x的平方根

(2)public static double random)(): 返回带正号的double 值,大于等于0.0且小于1.0

(3)public static double pow (double a, double b):返回第一个参数的第二个参数次幂,即a的b次方

(4)public static double abs (double a ) 返回绝对值

(5)public static double max(double a, double b):求a和b的最大值

(6)public static double min(double a, double b):求a和b的最小值

(7)public static double floor (double a);向下取整

​ public static double ceil (double a);向上取整

​ public static long round (double a);四舍五入取整(最接近的整数)

​ -x.5比较特殊

2.java.math包

java.math,BigDecimal:定点小数和大的小数,可以精确到小数点后n位,如果可以整除,可以用该方法,如果不能整除,说明保留小数点后多少位

float 和double :浮点数,不精确.

java.math.BigInerger:表示大整数

用法 BigInteger ig1 =new Big Integer(参数);

3.java.util,Random类:产生随机数

可以产生随机的整数、小数、boolean等所有数据类型

Math.random只能产生【0,1】之间的随机小数

Random random = new Random();

三、日期时间API

1.jdk中的日期时间API经历了三代

第一代:java.util.Date等

第二代:java.util.Calendar等

第三代:java.time包及其子包的类型

2.java.util.Date类

(1)Date() 获取当前系统时间

(2)Date(long time),根据指定的毫秒值,获取对应的日期时间

(2)Long getTime()获取当前系统时间距离1970-1-1凌晨的毫秒值

等同于 System.currentTimeMillis()

问题:为什么开始于1970年

Unix操作系统在1970年设计数来,把1970-1-1凌晨作为计算机时间的原始起点

Date类型大部分都是已过时的方法

3.java.util.Calendar类

他是一个抽象类,

如何创建对象:

(1)创建它子类对象

(2)在Calendar类中提供静态方法

Date和Calendar:

(1)使用麻烦

无法获取满足本地人阅读习惯的日期时间对象

需要借助DateFormat,它是抽象类,他有一非常

(2)可变对象:在开发中,日期对象,某个对象某个瞬间的日期时间,是不应该变的

(3)没有考虑闰秒

4.java8引入,java.time包:包含值对象的基础包

(1)本地的日期类型的API

LocalDate:日期、

Localtime:时间

LocalDateTime:日期和时间

LocalDateTime.now()方法指当前时间

LocalDateTime.of()方法可以指定时间

.isLeapYear():判断指定时间是不是闰年

修改日期或时间对象会返回一个新的对象结果,必须接受

5.java.long.System

(1)System.out 对象

(2)System.in 对象

(3)public static long currenTimeMillis():获取距离1970年的时间

(4)public static void arraycopy(Object src,int srcPos,Object,destPos,int length)

src:原数组

srcPos:原数组的起始位置

dest:目标数组

destPos:目标数组的起始位置

length:要挪动的元素的长度

total个元素, arr.length长度 假设length = 10, total = 7, 元素的下标[0,6]
i=2 移动[3],[4],[5],[6]
删除arr数组的[i] 元素: System.arraycopy(arr, i+1, arr, i, total-i-1)
i=2 移动[2],[3],[4],[5],[6]
插入arr数组的[i]元素: System.arraycopy(arr, i, arr, i+1, total-i)

(5)public static void gc():通知GC工作,进行垃圾回收,通知后,不代表GC线程立刻工作。
(6)public static void exit(int status):终止当前运行的Java虚拟机。 该参数作为状态代码; 按照惯例,非零状态码表示异常终止。
(7)public static Properties getProperties():获取所有的系统数属性

6.java.lang.Runtiam类

runtime.getRrntime()代表JVM的运行环境

四、数组的算法升华

1.数组的反转

方案一:

先新建一个数组,然后把元素按照反转之后的正确的顺序放进去,指向新的数组

缺点:浪费空间

方案二:

首尾交换

public class TestArray {
    @Test
    public void test01(){
        int[] arr = {1,2,3,4,5};

        //反转之后:arr中{5,4,3,2,1}
        //方案一:先新建一个数组,然后把元素按照反转之后的正确的顺序放到新数组中,让arr指向新数组
        int[] newArr = new int[arr.length];
        //把arr中的元素逆序放到newArr
        for (int i = 0; i < newArr.length; i++) {
            /*newArr[0] = arr[arr.length-1];
            newArr[1] = arr[arr.length-2];*/
            newArr[i] = arr[arr.length-1-i];
        }
        //让arr指向新的数组
        arr = newArr;

        //遍历
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    @Test
    public void test02(){
        int[] arr = {1,2,3,4,5};

        //首尾交换
        /*
        1  2  3  4   5
        1和5换
        2和4换
        5个元素换2次

        10个元素:5次
        交换的次数 = 数组的长度/2(整数与整数相除只保留整数部分)
         */
        //循环的次数 = 交换的次数
        for (int i = 0; i < arr.length/2; i++) {
            //交换的过程
            int temp = arr[i];
            arr[i] = arr[arr.length-1-i];
            arr[arr.length-1-i] = temp;
        }

        //遍历
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

2.数组的扩容
public class TestArray2 {
    @Test
    public void test01(){
        int[] arr = {1,2,3,4,5};

        //我想要在当前数组的基础上,增加一个元素6,放在最后
        /*
        思路:
        (1)创建新数组
        (2)把原来的元素复制过程
        (3)把新元素放进去
        (4)让arr指向新数组
         */
        int[] newArr = new int[arr.length+1];
        for (int i=0; i <arr.length; i++){
            newArr[i] = arr[i];
        }
//        newArr[newArr.length-1] = 6;
        arr = newArr;
        arr[arr.length-1] = 6;
    }
}
3、数组的插入
ublic class TestArray3 {
    @Test
    public void test01(){
        int[] arr = {1,2,3,4,5};

        //需求:要在arr[1]的位置插入6,结果{1,6,2,3,4,5}
        /*
        (1)先创建一个新数组newArr,新数组的长度 > 旧数组
        (2)把arr中[0,index-1]的元素放到newArr中
        (3)把新元素放到newArr中[index]
        (4)把arr中[index,arr.length-1]放到newArr中
        (5)最后arr指向newArr
         */
        int[] newArr = new int[arr.length+1];
        int index = 1;//插入的位置
        int value = 6;//插入的值
        for (int i=0; i<index; i++){
            newArr[i] = arr[i];
        }
        newArr[index] = value;
        for(int i=index; i<arr.length; i++){
            newArr[i+1] = arr[i];
        }
        arr = newArr;

        //遍历
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    @Test
    public void test02(){
        String[] arr = {"hello","java","world",null,null};

        /*
        要在index=1的位置插入"atguigu",结果{"hello","atguigu","java","world",null};
        思路:
        (1)把index及其后面的元素后移
        (2)然后把新元素放到[index]
         */
        int total = 3;
        int index = 1;//插入的位置
        System.arraycopy(arr, index, arr, index+1, total-index);
        arr[index] = "atguigu";
        total++;

        //遍历
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

    }

    /*
    在arr[index]位置插入value
     */
    public int[] insert(int[] arr,int index, int value){
        /*
        方案一:
        (1)先创建新数组,扩容
        (2)把arr的所有元素,原封不动的赋值到新数组newArr
        (3)再把index位置及其后面的元素后移
        (4)把value放到index位置
        (5)返回新数组
         */
        int[] newArr = new int[arr.length+1];
        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i];
        }
        System.arraycopy(newArr, index, newArr, index+1, arr.length-index);
        newArr[index]=value;
        return newArr;
    }

    @Test
    public void test03(){
        int[] arr = {1,2,3,4,5};
        int index = 1;
        int value = 6;
        arr  = insert(arr, index, value);

        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}
4、数组的元素删除
public class TestArray4 {
    @Test
    public void test01(){
        String[] all = {"hello","java","world",null,null};

        //删除index=1位置的元素
        int index = 1;
        int total = 3;
        //把index+1后面的元素往前移动
        System.arraycopy(all, index+1, all, index, total-index-1);
        all[total-1] = null;

        //遍历
        for (int i = 0; i < all.length; i++) {
            System.out.println(all[i]);
        }
    }
}
5.数组的二分查找

之前:数组的查找,是顺序查找,从[0]开始,挨个比较是否目标对象,如果是,找到了,如果不是,一直找到最后
现在:二分查找,又称为折半查找
二分查找有要求,数组必须是有序的

public class TestArray5 {
    @Test
    public void test01(){
        int[] arr = {2,5,7,8,10,15,18,20,22,25,28};//数组是有序的
        int value = 18;

        //查找value是否在arr中,如果在,打印下标,如果不在,说明不在
        int left = 0;
        int right = arr.length-1;
        int mid = (left +right)/2;
        int index = -1;

        while(left <= right){
            if(arr[mid] == value){
                index = mid;
                break;
            }else if(value > arr[mid]){
                left = mid +1;
            }else{
                right = mid - 1;
            }
            mid = (left + right) / 2;
        }

        if(index==-1){
            System.out.println("没找到");
        }else{
            System.out.println("找到了,下标是:" + index);
        }
    }
}
6.数组的直接排序=冒泡
public class TestArray6 {
    @Test
    public void test01(){
        int[] arr = {49,38,65,97,76,13,27,49};

        /*
        直接选择排序:
           思路:每一轮,找出本轮未排序元素中的最小/最大值,看它是否在正确的位置,如果不在,就与该正确位置的元素交换,这样经过多轮之后,实现排序
           最坏的情况:arr.length-1轮
                    {49,38,65,97,76,13,27,49} 从小到大
            第一轮:在[0,arr.length-1]范围的最小值 arr[5]=13是最小的,它应该在arr[0],所以要arr[0]与arr[5]
                    {13,38,65,97,76,49,27,49}
            第二轮:在[1, arr.length-1]范围找最小值  arr[6]=27是最小的,它应该在arr[1],所以要arr[1]与arr[6]
                    {13,27,65,97,76,49,38,49}
            。。。。
         */
        for (int i=0; i<arr.length-1; i++){
            //第1轮:i=0, j=0到arr.length-1
            //第2轮:i=1, j=1到arr.length-1
            //第3轮:i=2, j=2到arr.length-1
            //...
            //第n轮:i=arr.length-2, j=arr.length-2到arr.length-1
            //j=i
            int min = arr[i];//假设本轮的第一个元素最小
            int index = i;//本轮最小值的下标
            for(int j=i; j<=arr.length-1; j++){
                if(arr[j] < min){
                    min = arr[j];
                    index = j;
                }
            }

            if(index != i){
                //交换 arr[index] 和 arr[i]
                int temp = arr[index];
                arr[index] = arr[i];
                arr[i] = temp;
            }
        }

        //结果
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }


    }

    @Test
    public void test02() {
        int[] arr = {49, 38, 65, 97, 76, 13, 27, 49};

        /*
        第一轮:拿所有元素与arr[0]位置的元素比较,有比它小的,就交换
                第一次:{38, 49, 65, 97, 76, 13, 27, 49};
                第二次:
                第三次:
                第四次:
                第五次:{13, 49, 65, 97, 76, 38, 27, 49};
                第六次:
                第七次:
          第二轮:拿所有元素与arr[1]位置的元素比较,有比它小的,就交换
                。。。
         */
        for(int i=0; i<arr.length-1; i++){
            for(int j=i; j<=arr.length-1; j++){
                if(arr[j] < arr[i]){
                    int temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                }
            }
        }
    }

    @Test
    public void test03(){
        int[] arr = {49,38,65,97,76,13,27,49};

        for (int i=0; i<arr.length-1; i++){
            int index = i;//本轮最小值的下标
            for(int j=i; j<=arr.length-1; j++){
                if(arr[j] < arr[index]){
                    index = j;
                }
            }

            if(index != i){
                //交换 arr[index] 和 arr[i]
                int temp = arr[index];
                arr[index] = arr[i];
                arr[i] = temp;
            }
        }

        //结果
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }


    }

}

五、数组的工具类


java.util.Arrays工具类:此类包含用来操作数组(比如排序和搜索)的各种方法。
开发中:能够用API的方法,肯定是最简洁的,
面试中,需要知道底层是如何实现的,甚至有些算法要手动会实现。

System.arraycopy这个方法和数组关系,为啥在System类中,不在Arrays类?
因为版本的问题。JDK1.0时候,还没有Arrays工具类,但是arraycopy这个方法已经在使用了,
当时没地方放这个方法,只好放在系统类中。后期所有和数组有关的方法都在Arrays类中。

(1)public static int binarySearch(int[] a, int key):二分查找
如果它包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。插入点 被定义为将键插入数组的那一点:
它有很多重载形式,形参的类型不同

(2)public static int[] copyOf(int[] original,int newLength):复制数组
它有很多重载形式,形参的类型不同

(3)public static int[] copyOfRange(int[] original,int from, int to)
它有很多重载形式,形参的类型不同

(4)public static boolean equals(int[] a, int[] a2):比较两个数组是否相同
它有很多重载形式,形参的类型不同

(5)public static void fill(int[] a,int val):用val填充整个数组
它有很多重载形式,形参的类型不同

(6)public static void sort(int[] a) :对指定的 int 型数组按数字升序进行排序。该排序算法是一个经过调优的快速排序法
它有很多重载形式,形参的类型不同

(7)public static void sort(Object[] a):给对象数组排序,按升序排列,要求元素必须是java.lang.Comparable
public static void sort(Object[] a, Comparator c):按升序排列,需要一个Comparator实现类对象

(8)public static String toString(int[] a)
它有很多重载形式,形参的类型不同

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值