JDK17 来了,免费!


Oracle今天宣布,从JDK 17开始,以及后续的版本全部免费!! 放大招了 ?
是否有感觉JDK11 和15 的各种特性都没咋研究呢, JDK 17就来了 !此次JDK17是个长期版本哦。

JDK 17 binaries are free to use in production and free to redistribute, at no cost.

https://www.oracle.com/java/technologies/downloads/ 进入官网查看详情

有兴趣的可以下载来耍耍 http://jdk.java.net/, 不过还是那句老话! 在生产环境下!

版本任你发!我用Java8 !

哈哈哈哈 ~Java8 yyds, 因为稳定、安全是最重要的 ,这是新版本可能不具备的,不过相信JDK8 老大哥 近些年迟早会退休的!未来很可能是JDK17+的!

分享几本Java经典书籍

学习一门技术初期,和大部分人一样,我一般都是上课听听、课后B站看看视频、文档学习,因为上手快、学起来更容易懂,但学段时间,掌握到一定程度后,总会发现学的挺肤浅的,有的知识点似懂非懂,写的代码质量就较低;

个人认为想学好、学扎实,静下心看书和多复习是个good idea!帮助你查缺补漏,掌握的更扎实,书上不少知识很枯燥,慢慢看慢慢嚼,或许能发现许多“新大陆”;

走技术这条路,别急着跑吧 ~;

推荐下我目前在看的,PDF版下载

Java编程思想第四版.pdf (2.37MB)

Java程序设计-第4版.pdf (31MB)

深入理解Java虚拟机.pdf (61.4MB)

Java多线程方面,强烈推荐这本,通俗易懂,深入浅出。
点击去看 深入浅出Java多线程

Java 时间间隔推算

计算两个日期之间的间隔时间

LocalDateTime 和 Date 的应用

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;

/**
 * 时间间隔推算 * * @author cst
 */
public class MyDateTest {
    public static void main(String[] args) {
        String begin = "2021-09-01 15:00:00";
        String end = "2021-09-03 16:00:00";
        System.out.println("起始时间: " + begin);
        System.out.println("结束时间: " + end);
        System.out.println("间隔时间A= " + betweenTime(begin, end) + "小时");
        System.out.println("间隔时间B= " + durationTime(begin, end) + "小时");
        System.out.println("距离返校还有 " + betweenTime(end) + "小时");
    }

    /**
     * 计算两个日期的 间隔时间 * LocalDateTime方式 * @param begin 开始时间 * @param end 结束时间 * @return long 小时
     */
    public static long durationTime(String begin, String end) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        Temporal beginTime = LocalDateTime.parse(begin, df);
        Temporal endTime = LocalDateTime.parse(end, df);
        Duration between = Duration.between(beginTime, endTime);
        return between.toHours();
    }

    /**
     * 计算两个日期的 间隔时间 * @param begin 开始时间 * @param end 结束时间 * @return long 小时
     */
    public static long betweenTime(String begin, String end) {
        long result = 0;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            result = (sdf.parse(end).getTime() - sdf.parse(begin).getTime()) / 1000 / 60 / 60;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 计算距离目标时间还有多久 * LocalDateTime方式 * @param targetTime 目标时间 * @return long 小时
     */
    public static long betweenTime(String targetTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        Temporal beginTime = LocalDateTime.now();
        Temporal endTime = LocalDateTime.parse(targetTime, df);
        Duration between = Duration.between(beginTime, endTime);
        System.currentTimeMillis();
        return between.toHours();
    }
}

输出

起始时间: 2021-09-01 15:00:00
结束时间: 2021-09-03 16:00:00
间隔时间A= 49小时
间隔时间B= 49小时
距离返校还有 74小时

将class反编译成java

有时候会碰到只有class文件,看不了源码的情况,那要怎么办呢?需要反编译成java文件,即可正常查看其源码。

一、需要一个jad反编译工具
下载地址 https://varaneckas.com/jad/
如无法访问上方官网,请点击我下载

二、下载好后,解压文件夹。

三、将需要反编译的class文件 放到与jad相同的路径下,然后进入cmd 。

输入命令 jad -o -r -s java -d result example/*.class

四、然后就可以了,结果如下

快去试试吧!

备注:如果嫌弃上面的麻烦,介绍一种便捷的方法在IntelliJ Idea中安装插件 IdeaJad,选中 class文件右键选择 Decompile,完成反编译

近期Java岗笔试面试题(实习 or 秋季校招)

目前有记下来的题目,记录下吧:

笔试-简答题
1.对象初始化顺序
2.servlet的生命周期
3.get post区别
4.简述四种修饰符的作用范围
4.cookie session区别
5.sql注入是啥,如何防止sql注入
6.什么是脏读,事务隔离性哪些可防止脏读
7.forward redirect区别
8.手写代码 你认为最佳的单例模式
9.手写代码 数值反转 "1234" => 4321 ; "0123" =>321
10.手写代码 设计算法从数组中找出最小的数

面试 30分钟:
围绕着笔试题顺序提问和扩展一些框架应用的问题
----------------------------------------------2
笔试
1.Java基础 7题不定项选择题
2.对redis的了解,主要应用场景?
3.事务哪些特性,索引有什么作用?
4.SpringCloud是什么,有什么组件?
5.消息队列是什么?你了解哪些
6.写sql 两个,不给数据库的表,凭空想想,佛了
查询每科成绩前三名的学生名
查询出比平均分高的学生,还有个条件忘了
7.写个二叉树实现算法
8.设计电商系统,需要哪些技术(越多越细越好)

面试 20分钟
主要问项目
比较字符串用什么
讲你项目登录的实现,登录后的后续操作怎么判断是哪个用户
项目用什么模式开发的? mvc
MD5加密,是否可逆,还了解过其他加密吗
接口测试用什么,postMan会用吗,
Json ,给个模型k,v,写出json的格式
Http请求头哪几部分?请求头Header 了解吗
JVM 内存模型
有了解线程池吗说说
项目有用日志吗?日志的格式
事务说说 ,在框架中怎么用
最近有在看什么书?
基础问的少,主要项目实践层面
面试官指出我的不足和重点要学什么

HR 常见问题,聊天
----------------------------------------------3
笔试
1.抽象和接口的区别
2.String,StringBuilder,StringBuffer的区别
3.GC是什么,为什么要有GC
4.Spring IOC是什么,作用?
5.手写快速排序
6.手写单例模式
7.写sql,一个employee表(含有员工和经理),字段: ID,员工名,员工薪资,经理的ID,查询出比经理薪资更高的员工名,这题要用自连接

面试 45分钟
说说你认为最好的项目,介绍下主要功能
项目有涉及精度问题吗,用什么解决
Linux上有搭建过jdk,tomcat啥的吗
对前端掌握的如何
说说常用的集合
说说对锁的理解
说说redis,可以持久化吗?有几种方式?
说说HasMap,说说jdk1.8为什么要用红黑树
平时怎么学习,有什么规划,有什么偶像
闲聊,反问

好像技术总监面
主要问谈入职相关事情,问学习成绩,证书
接受写老项目吗,例如SSH?
接受出差吗?肯定不啊
选公司看重哪些?
大四确定学校能让来吗?ps:无了,突发疫情了...

----------------------------------------------4
这家奇怪,直接打电话过来。
20分钟
1面,技术面,电话面,高冷女面试官
1.介绍你的考试平台项目
2.好家伙,一连串问了十几个Java基础题
例如 ==和equals的区别?
异常有哪几种?常见的运行时异常?
java的基本类型有哪些?
接口可以继承接口吗?可以多继承吗?
强软弱虚引用的区别?
.java和.class的区别?
深拷贝浅拷贝的区别?
Object有哪些方法?
循环语句有哪几种?
就记得这些了,反正都是些简单的基础题。

3.给个数组,找出第二大的数,不能用排序
4.字符串型求运算结果,例如 “1+2*3”
5.sql左连接和右连接区别
6.说说平时学习的方法?
7.期望薪资,为什么选厦门,何时可上班等等一些入职相关问题

----------------------------------------------5
开场国际惯例:自我介绍 -.-
HR电话面,HR面基本都是聊聊天,一些常见的非技术问题
大部分笔试都有的题型:
选择题(单选、判断、不定项),范围广,含有计算机网络、操作系统、Java、数据结构和算法、数据库等

SQL题 给了两个表,成绩表和学生表,要求输出每个班成绩最高的,要考虑重复的

编程题(我记得的)
A.望海楼,给一个数组代表山脉的高度,输出在每座山脉上能够看到的山顶数量(包括自己)
比如输入
[500, 300, 800, 300, 270, 570]
输出
[3,3,5,4,4,4]
ps:经典考时看不懂写不出,考后秒懂

B.五子棋判定,给五个横纵坐标,判定是否连成五子棋。
ac了

视频面40分钟
1.自我介绍
2.项目是部署在哪家的云服务器
3.看代码,说出结果
int a=130;
Interger b = a;
Interger c = a;
System.out.println(b == c);
4.写代码,随机产生100个1到100的随机数,从小到大的顺序输出。

Java的三大特性,为什么Java是单继承?不是单继承会出现什么问题?
说多态。说说理解?
JVM了解吗说说?垃圾回收机制说说?
并发了解吗说说?synchronized和ReentrantLock有什么区别?对锁的了解,并发怎么解救数据的安全?用Eecutors创建线程有什么优点和缺点?RetentLock底层怎么实现的?
说说你近期最熟悉的项目?
并发,线程池说说?用Executors创建的线程池有啥优点缺点?
在学校成绩怎么样?有没挂过科?
Spring 核心 IOC和AOP说说
AOP怎么实现的?
你项目数据库如何设计的?
事务在代码中怎么用?两个方法a方法this调用自己,嵌套里的方法会有事务吗?
事务在哪些情况会失效?为什么失效?


忘了一些,就写这么多了,八股文蛮多的,卷就完事了
总的来说,有挂有过,时间多,哈哈继续面,总不能躺平吧哈哈,会持续更新....

Typora 常用快捷键

标题:Ctrl+1/2/3/4/5
段落:Ctrl+0
增大标题级别:Ctrl+=
减少标题级别:Ctrl+-
表格:Ctrl+T
代码块:Ctrl+Shift+K
公式块:Ctrl+Shift+M
引用:Ctrl+Shift+Q
有序列表:Ctrl+Shift+[
无序列表:Ctrl+Shift+]
增加缩进:Ctrl+]
减少缩进:Ctrl+[
加粗:Ctrl+B
斜体:Ctrl+I
下划线:Ctrl+U
代码:Ctrl+Shift+`
删除线:Alt+Shift+5
超链接:Ctrl+K
图像:Ctrl+Shift+I
清除样式:Ctrl+ 
显示隐藏侧边栏:Ctrl+Shift+L
大纲视图:Ctrl+Shift+1
文档列表视图:Ctrl+Shift+2
文件树视图:Ctrl+Shift+3
源代码模式:Ctrl+/
专注模式:F8
打字机模式:F9
切换全屏:F11
实际大小:Ctrl+Shift+0
放大:Ctrl+Shift+=
缩小:Ctrl+Shift+-
应用内窗口切换:Ctrl+Tab
打开DevTools:Shift+F12

LeetCode刷题

题解

只出现一次的数字

方法1:使用HashMap的getOrDefault

class Solution {
    public int singleNumber(int[] nums) {
       Map<Integer,Integer> map=new HashMap<>();
       for(int i : nums){
           map.put(i,map.getOrDefault(i,0)+1);
       }
       for(Map.Entry<Integer,Integer> entry : map.entrySet() ){
           if(entry.getValue() == 1){
               return entry.getKey();
           }
       }
       return -1;
    }
}

方法2:异或运算 ,根据此性质:a^b^a = b^a^a = b^(a^a) = b^0= b

class Solution {
    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }
}

多数元素

方式1:摩尔投票法

class Solution {
    public int majorityElement(int[] nums) {
        int count = 0;
        int candidate = -1;
        for (int num : nums) {
            if (count == 0) {
                candidate = num;
            }
            count += (num == candidate) ? 1 : -1;
        }
        return candidate;
    }
}

方式2:排序后,取数组中间的那个数

public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
}

搜索二维矩阵 II

根据此有序的二维矩阵,此题要从左下角或右上角开始搜索

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
         // 从左下角开始搜索
        int row = matrix.length-1;
        int col = 0;

        while (row >= 0 && col < matrix[0].length) {
            if (matrix[row][col] > target) {
                row--;
            } else if (matrix[row][col] < target) {
                col++;
            } else { //找到
                return true;
            }
        }

        return false;
    }
}

合并两个有序数组

双指针方法

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int tail = nums1.length - 1;
        int p1 = m - 1;
        int p2 = n - 1;
        while (p2 >= 0) {
            if (p1 < 0 || nums1[p1] <= nums2[p2]) {
                nums1[tail--] = nums2[p2--];
            } else {
                nums1[tail--] = nums1[p1--];
            }
        }
    }
}

合并两个有序链表

//递归方式
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        } else if (l2 == null) {
            return l1;
        } else if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

两个链表的第一个公共节点

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode A = headA, B = headB;
        while (A != B) {
            A = A != null ? A.next : headB;
            B = B != null ? B.next : headA;
        }
        return A;
    }
}

源自https://leetcode-cn.com/

MySQL 查询

MySQL 单表多表查询

select 字段名 from 表名 where 条件

例如:select id from user where name='张三'

​ 查询出 user表中 name为张三 的id

条件查询关键字

= 等于
<> 或 != 不等于
>、 < 、>= 、<=  大于、小于、大于等于、小于等于

between ... and .... 两个值之间,但前值必须小于后值

is null 和 is not null  判断空的

and 并且  , or 或者

in 包含 例如 in('a','b');

not 用于取非,主要用于 is 和 in

like 模糊查询 例如 username like %c% 或 username like _c%
     %匹配任意个字符 、下划线_ 匹配单个字符
其它关键字
distinct 去重 例如,select distinct dep_name from ....

desc 降序
asc  升序(默认)
order by age asc,name desc; 按年龄升序,当年龄一样时,按名字降序
例子:找出工资在1250到3000之间的员工的姓名和薪资,要求按薪资进行降序排序。

select name,sal 
from emp 
where sal between 1250 and 3000 
order by sal desc;

单行处理函数

数据处理函数又被成为单行处理函数,特点是一个输入对应一个输出。 
常见的有
lower 转小写 lower('A')
upper 转大写 lower('a')
substr 截取字符串 substr(字段名,起始位置从1开始,截取的长度)
length 取长度 
trim 去两边的空格
str_to_date 字符串转日期 ('字符串日期','日期格式')%Y %m %d %h %i分 %s秒
            str_to_date('01-10-1999','%d-%m-%Y')
            这种'1999-01-01' 正确格式无需使用函数,mysql会自动转换
date_format ('日期类型数据','日期格式') 日期转字符串 date_format(birth,'%m/%d/Y') 这函数没啥用,存正确格式的日期,mysql会自动转换
rand 生成随机数
round 四舍五入 round(1.23, 2) 保留2位小数
concat 对字符串进行拼接 concat(name1,name2)
ifnull 将null转换成一个具体指值 ifnull(age,0) ,表示如果年龄是空,用0代替

case 字段名 when 条件 then 做什么 else 做什么 end 
例子:当sex为1时,表示为男,否则表示为 女
case sex when '1' then '男' else '女' end 

多行处理函数(分组函数)

分组函数又被称为多行处理函数,特点:多个输入对应一个输出,自动忽略null的记录,不能使用在where后。
使用方式:函数名(字段名),例如 sum(score) ,表示对 分数进行求和。

常见的有 
max 取最大值
min 取最小值
avg 求平均值
sum 求和

count 计数 
    count(*)、count(字段名)和 count(1) 的区别? 

    答:(*)会计算包含null的记录,count(字段名)则忽略null的记录,使用*效率更低
        列名为主键,count(列名) 会比 count(1) 快 ;
        列名不为主键,count(1) 会比 count(列名) 快 ;
        如果表多个列并且没有主键,则 count(1) 的执行效率优于 count() ;
        如果有主键,则 select count(主键)执行效率最优;
        如果表只有一个字段,则 select count(*)最优。

分组查询(重要)

select 字段名 from 表名 where 条件 order by 字段名

SQL语句执行顺序: from → where → group by → select → order by

例子1:按照工作岗位分组,对工资进行求和,查询出岗位和工资总和
     select job,sum(sal) from emp group by job;

例子2:按照部门编号分组,找出每个部门的最高薪资
     select depno,max(sal) from emp group by depno;

例子3: 找出每个部门,不同工作岗位的最高薪资(按照部门编号分组)
     select depno,job,max(sal) from emp group by depno,job;

例子4: 找出每个部门的最高薪资大于3000的信息(按照部门编号分组)
     方式1:select depno,max(sal) from emp where sal>3000 group by depno;
     方式2:select depno,sal from emp group by depno having max(sal)>3000;
     having 可以对分完组后的数据进行再次过滤,不能单独使用,得和group by配合。
     优先使用方式1,where,效率更高

例子5:找出每个部门的平均薪资大于2500的信息(按照部门编号分组) 
     select depno,avg(sal) from emp group by depno having avg(sal)>2500;
     此例子只能用having,无法用where

备注:用了 group by后,select 后面只能跟 参与分组的字段 或 分组函数,否则无意义;

注意:使用分组函数前必须要先分组,所以不能在where 后使用分组函数,例如不能 ...where min(x);

为什么min(x) 不能用在where 的后面,因为使用min(x)的时候,还没有进行分组!请参考SQL的执行顺序。

Mysql 多表查询

内连接

等值连接

查询每个员工所在的部门名称,显示员工名和部门名

select e.ename,d.dname
from emp e
join dept d
on e.deptno = d.deptno;

非等值连接

找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?

select e.ename,e.sal,s.grade
from emp e
join salgrade s
on e.sal between s.losal and s.hisal;

自连接

查询员工的上级领导,要求员工名和对应的领导名(同  张表)

select a.ename,b.ename
from emp a
join emp b
on a.mgr = b.empno

外连接

sql语句中的inner和outer可以省略,带有right或left的是外连接。

左外连接

select e.ename,d.dname
from dept d
 left join emp e
on e.deptno = d.deptno;

右外连接

select e.ename,d.dname
from dept d
right join emp e
on e.deptno = d.deptno;

right 代表什么,表示将join关键字右边的这张表看成主表,主要是为了将右边的这张表的数据全部查询出来,捎带着关联查询左边的表,在外连接当中,两张表连接,产生了主次关系。

三表连接

找出每个员工的部门名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级

select e.ename,d.dname,e.sal,s.grade
from emp e
join dept d
on e.deptno = d.deptno
join salgrade s
on e.sal between s.losal and hisal;
找出每个员工的部门名称以及工资等级,还有上级领导,要求显示员工名、领导名、部门名、薪资、薪资等级

select e.ename,l.ename,d.dname,e.sal,s.grade
from emp e
join dept d
on e.deptno = d.deptno
join salgrade s
on e.sal between s.losal and hisal;
left join emp l //left 保证emp表的数全部查出来
on e.mgr = l.empno

MySQL 子查询

select 中 嵌套 select语句,被嵌套的select 语句成为子查询

可嵌套的位置:select (select) from (select) where (select)

where后出现子查询

找出比最低工资高的员工姓名和工资

select ename,sal from emp where sal > (select min(sal) from emp);

from 后出现子查询

找出每个岗位的平均薪资的薪资等级

select t.*,s.grade
from (select job,avg(sal) as avgsal from emp group by job) t
join salgrade s
on t.avgsal between s.losal and s.highsal; 

select 后出现子查询

找出每个员工的部门名称,要求显示员工名,部门名(此题了解即可)

select e.ename,(select d.dname from dept d where e.deptno=d.deptno) as dname
from emp e;

此情况的子查询只能一次返回1条结果,如果结果是多条会报错,因为和其它字段结果行数不匹配

其它知识

union的例子

第1种:select ename,job from emp where job='Manager' or job='Salesman';

第2种:select ename,job from emp where in('Manager','Salesman');

第3种:
select ename,job from emp where job='Manager';
union
select ename,job from emp where job='Salesman'

第3种使用 union的效率要高一些,对于表连接来说,每连接一次新表则匹配的次数满足笛卡尔积,成倍的翻,但是union可以减少匹配的次数,还可以完成两结果的拼接。
注意,使用union 进行结果合并时,要求两语句的列数和各字段相同
limit

limit startIndex,length;

limit 5; 前5条记录
limit 2,5; 从第3条开始,往后取5条

注意:limit在order by后执行!