小码农的十万个为什么!!!(一)

《小码农的十万个为什么!!!(一)》
《小码农的十万个为什么!!!(二)》

1.使用父类保存子类对象能使程序执行性能更好?

Collection list = new ArrayList(); // 指向list的方法 可重复 有序
Collection set = new HashSet(); // 指向set 不可重复 没有顺序
目的是解耦。
将对细节的依赖转为对抽象的依赖。
通俗点就是从前通过父类的引用实现了某功能,现在由于业务发展,需要对功能进行拓展或修改,实际表现就是要跟换改功能具问体的实现类。
换到这里父类引用指向子类对象可以拆分为两层:答父类对象专与实际子类相关联,调用父类对象实现功能。
当发生业务变更的时候,只需要修改父类对象与实际子类相关联的业务逻辑层,而不需要更改调用父类对象实现的接属口调用层。
解除耦合的好处是,避免了牵一发而动全身的现象,极大简化了业务更新迭代过程中,所需要修改的代码量。

2.su和su -的区别?

su只是切换了root身份,但Shell环境仍然是普通用户的Shell;
而su -连用户和Shell环境一起切换成root身份了。只有切换了Shell环境才不会出现PATH环境变量错误,报command not found的错误。
su切换成root用户以后,pwd一下,发现工作目录仍然是普通用户的工作目录;
而用su -命令切换以后,工作目录变成root的工作目录了。
用echo $PATH命令看一下su和su - 后的环境变量已经变了。

3.为什么要同时覆盖hashcode方法和equals方法?

这是一种通用的约定,而不是必须的。
  用HashMap来阐述原因,首先假设key1和key2的值在业务逻辑领域是相等的,即它们应该是同一个对象,HashMap已经存储了key1,现在要查找key2是否存在,正确的结果应该是存在:。
  Java中的HashMap实际上是一个链表数组,即首先HashMap是一个数组,然后数组中的每一个元素是一个链表(更通用的概念可以称为bucket,Java中的HashMap用Entry类描述链表的结点结构),HashMap在执行Put,Contains之类的操作时,会首先根据你提供的Key计算hashCode值,然后根据这个hashCode值在数组中找到某一个链表或桶(通常是找到链表的起始结点),这一步操作利用了hashCode()方法,如果你覆盖了就会用你提供的方法,在找到某一个链表的起始结点后,就会遍历链表,然后通过equals方法来寻找是否存在与Key的值相等的结点,如果执行equals方法后的结果相等,HashMap就认为已经存在这个元素,这一步如果你覆盖了equals方法就会用到你提供的equals方法。
  通过上面的描述,我们发现equals方法和hashCode方法如果不同时按你自己逻辑覆盖的话,HashMap就会出问题。比如你只覆盖了equals方法而没有覆盖hashCode方法,那么HashMap在第一步寻找链表的时候会出错,有同样值的两个对象Key1和Key2并不会指向同一个链表或桶,因为你没有提供自己的hashCode方法,那么就会使用Object的hashCode方法,该方法是根据内存地址来比较两个对象是否一致,由于Key1和Key2有不桶的内存地址,所以会指向不同的链表,这样HashMap会认为key2不存在,虽然我们期望Key1和Key2是同一个对象;反之如果只覆盖了hashCode方法而没有覆盖equals方法,那么虽然第一步操作会使Key1和Key2找到同一个链表,但是由于equals没有覆盖,那么在遍历链表的元素时,key1.equals(key2)也会失败(事实上Object的equals方法也是比较内存地址),从而HashMap认为不存在Key2对象,这同样也是不正确的。

4.LinkedList多连问

(1)为什么LinkedList用的是双向链表而不是单向链表?
  因为双链表本身就具有了单链表的功能,只是在存储上会多一个前向指针。所以在不考虑空间浪费的情况下,双链表更通用,覆盖面更广。
(2)LinkedList是双向链表还是双向循环链表?
  从JDK1.7开始,LinkedList 由双向循环链表改为双向链表在JDK 1.7之前(此处使用JDK1.6来举例),LinkedList是通过headerEntry实现的一个循环链表的。先初始化一个空的Entry,用来做header,然后首尾相连,形成一个循环链表。
  最后添加的数据就将next改成header,而header的prev就改成新添加的数据,这样形成的双向循环链表。
  在JDK 1.7,1.6的headerEntry循环链表被替换成了first和last组成的非循环链表。
(3)为什么要换成双向链表?
  猜测:这也就是为了考虑节省一些操作?不用header节点,不管是在链表头部还是链表尾部增删数据,改动的都少一些,不用专门弄个header节点,这样还每次都要操作这个节点。
(4)LinkedList默认增删数据是从头部还是尾部操作?
源码中:
增加数据是默认从尾部开始添加;
删除数据是默认从头部开始增加。
(5)为什么LinkedList增删数据比ArrayList快?查询慢?
  因为增删数据时LinkedList只涉及到指向节点的指针的改变,不需要像ArrayList那样需要对数组位置的变动。查询的时候LinkedList是根据二分法遍历链表查询,而ArrayList只用根据下表就能定位数据。

5.为什么StringBuilder线程不安全,StringBuffer线程安全?

源码分析就是StringBuilder没有加synchronized锁,而StringBuffer加了。

6.java 的 Class.forName 和 ClassLoader.loadClass 方法的区别?

一个 Java 类加载到 JVM 中会经过三个步骤,装载(查找和导入类或接口的二进制数据)、链接(校验:检查导入类或接口的二进制数据的正确性;准备:给类的静态变量分配并初始化存储空间;解析:将符号引用转成直接引用;)、初始化(激活类的静态变量的初始化
Java 代码和静态 Java 代码块)。
对于 Class.forName 方法来说:
//Class.forName(className) 方法内部实际调用的方法是 Class.forName(className, true, classloader);
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
/*
三个参数的含义分别为:
name:要加载 Class 的名字
initialize:是否要初始化
loader:指定的 classLoader
/
对于 ClassLoader.loadClass 方法来说:
//ClassLoader.loadClass(className) 方法内部实际调用的方法是 ClassLoader.loadClass(className, false);
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
/

两个参数的含义分别为:
name:class 的名字
resolve:是否要进行链接
*/
所以通过传入的参数可以知道 Class.forName 方法执行之后已经对被加载类的静态变量分配完了存储空间,而 ClassLoader.loadClass 方法并没有一定执行完链接这一步;当想动态加载一个类且这个类又存在静态代码块或者静态变量而你在加载时就想同时初始化这些静态代码块则应偏向于使用 Class.forName 方法。

7.Class.forName()、Class.class、getClass() 区别?

Class.class 的形式会使 JVM 将使用类装载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回 Class 对象。
Class.forName() 的形式会装入类并做类的静态初始化,返回 Class 对象。
.getClass() 的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的 Class 对象。
静态属性初始化是在加载类的时候初始化,而非静态属性初始化是 new 类实例对象的时候初始化。他们三种情况在生成 Class 对象的时候都会先判断内存中是否已经加载此类。

8.如何在ArrayList中添加String类型数据?

方式一:用Integer.valueOf(String)就获取到了Integer类型的对象了
方式二:用反射机制,先获取ArrayList类对象,再调用getMethod()调用ArrayList中的add方法获取Method方法对象,
再是通过方法对象获取invoke(list,“XXX”)方法执行操作,这样操作就完成了。
ArrayList list=new ArrayList();
Method method = list.getClass().getMethod(“add”, Object.class);
method.invoke(list, “i am a String”);
System.out.println(list);

9.隐式类型转换和显式类型转换?

隐式类型转换也叫做自动类型转换,
规则:从存储范围小的类型到存储范围大的类型。
转换方向:byte→short(char)→int→long→float→double(这里指的是只有前面的数据类型能随便转换成后面的)
—实际开发中这样的类型转换很多,但没有为这种转换提供专门的语法,都是由虚拟机自动完成。
—例子:byte b = 10;short sh = b;这里在赋值时,JVM首先将b的值转换为short类型,然后再赋值给sh。
显式类型转换也叫做强制类型转换,
规则:从存储范围大的类型到存储范围小的类型。
转换方向:double→float→long→int→short(char)→byte
强制类型转换通常都会存储精度的损失,所以使用时需要谨慎。
—需要在被转换值的前面添加个括号,括号里面写的是希望得到的数据类型。
—例子:int m = 1234;byte b = (byte)m;//-46
------解析:整数强制转换为整数时取数字的低位,例如int类型的变量转换为byte类型时,则只去int类型的低8位(也就是最后一个字节)的值。
则m的值还是12345,而b的值为-10。b1的计算方法如下:m的值转换为二进制是10011010010,取该数字低8位的值作为b的值,则b
的二进制值是11010010,按照机器数的规定,最高位是符号位,1代表负数,在计算机中负数存储的是补码,则该负数的原码是10101110,
该值就是十进制的-46。
(附:补码算得原码:—百度百科
算法1: 补码=原码取反再加1的逆运算
10010110是补码,应先减去1变为反码,得10010101;
由反码取得源码即除符号位外其他为按位取反,得11101010,即十进制数的-106
算法2:负数补码速算法,由最低位(右)向高位(左)查找到第一个1与符号位之间的所有数字按位取反的逆运算
10010110是补码,符号位与最后一个1之间的所有数字按位取反,得11101010)
注意:+=具有强转效果(short s = 1;s = s + 1;s += 1;前面的s=s+1会报错,因为s+1会先转换成int类型,然后再赋值给short类型,这样可能数据丢失;s+=1具有强转效果,相当于s = (short)(s+1),所以正确)

10.JDK+JRE+JVM???

JDK(Java Development Kit—java开发工具包)
bin:最主要的是编译器(javac.exe)
include:java和JVM交互用的头文件
lib:类库jre:java运行环境
jre:java运行环境
JRE(Java Runtime Environment—java运行环境)
光有JVM还不能让class文件执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。在JDK的安装目录里你可以找到jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和lib和起来就称为jre。
JVM(Java Virtual Machine—java虚拟机)
是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。

11.为什么项目中直接调用的是接口或者说项目中为什么上面的层中注入的是下面层的接口而不是直接调用实现类?

多态的体现—接口可以有多个实现类,可以拓展功能—这也就是用接口形成多实现体系(如集合框架)
解耦操作—调用接口也就避免了直接跟具体的功能实现类进行耦合关联,这样后期如果有功能修改,就只用在接口下的实现类中修改,对调用接口来实现功能影响不大。
封装(信息隐藏)—本来是调用者和类直接耦合了,现在是interface和interfaceImpl建立联系,interface和调用者建立联系,这样做旨在减少调用者和类的直接联系
项目协作,是项目模块化的利器。

12.一个进程中的多个线程可以共享哪些资源?

线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。
同一个进程的多个线程有自己独立的堆栈和局部变量

13.JAVA虚拟机启动程序步骤:

(1) Main是启动时候的主线程,即程序入口
(2) 在main函数结束后,虚拟机会自动启动一个DestroyJavaVM线程,该线程会等待所有user thread 线程结束后退出(即,只剩下daemon 线程和DestroyJavaVM线程自己,整个虚拟机就退出,此时daemon线程被终止),因此,如果不希望程序退出,只要创建一个非daemon的子线程,让线程不停的sleep即可。

14.提交一个任务到线程池中,线程池的处理流程如下:

1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

15.线程池分类:

(1) FixedThreadPool 固定核心线程的线程池。
特点:它的核心线程数量就是最大线程数,所以线程池内的线程永远不会消亡,它采用了无参数的链表阻塞队列,最大的任务数可达232-1个。因此存在任务积压导致内存溢出的风险。
(2)CachedThreadPool 缓存线程池
特点:没有核心线程,线程池不能满足任务运行时会创建新的线程,线程数量没有上限。默认的消亡时间为60秒。值得注意的是:它的阻塞队列是SynchronousQueue,这是一个没有存储性质的阻塞队列,它的取值操作和放入操作必须是互斥的。根据源码文档的解释,可以理解为每当有任务放入时会立即有线程将它取出执行。
(3)ScheduledThreadPool 固定调度线程池
特点:有固定的核心线程,线程的数量没有限制,默认存活时间为60秒。同时支持定时及周期性任务执行。
(4)SingleThreadExecutor 单核心线程池
特点:只有一个核心线程,所以能保证任务的串行化执行。
(5)WorkStealingPool 并行执行线程池
特点:在jdk8中实现 线程池。它内部的线程池实现是ForkJoinPool,这是一个可以同时利用多个线程来执行任务的线程池。无参默认使用CPU数量的线程数执行任务

16.SQL存储过程,视图,触发器,数据库表之间的关系是怎么样的?

数据库表是数据的载体,数据内容及数据关系的存储空间。
视图是利用数据库表生成的“伪表”,袭本身仅为一条查询数据库表的语句(物化视图除外)。
sql存储过程是处理、筛选数据的。作用是将数据库表中的数据读取出来,处理后将最终结果插入到某张表中,或者展现在页面上。
触发器是连带功能的开关,我们通过这个开关控制一些与正在处理的数据或动作具有连带性质的数据库表内的数据。
触发器是开关,sql存储过程是处理数据的,也就是说可以通过触发器控制sql存储过程处理连带数据。

17.Mybatis中的sql与include标签??

用来封装SQL语句, 来调用。
实例:

<sql id="Base_Column_List">
id, name,sex,${someCol}
</sql>  
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select 
	<include refid="Base_Column_List">
		<property name="someCol" value="age"/>
	</include>
from user
where id = #{id,jdbcType=INTEGER}
</select>

则与selectByPrimaryKey方法映射的语句是:

select 
id, name,sex,age
from user
where id = #{id,jdbcType=INTEGER}

18.Mybatis中的trim标签??

<trim prefix="(" prefixOverrides="AND|OR" suffixOverrides="," suffix=")">子句</trim>

prefixOverrides:子句首的命中词列表,以|分隔,忽略大小写。如果命中(轮询命中词,最多只命中一次),会删除子句首命中的词;没命中就算了。
prefix:删除子句句首后,在子句最前边加上单个空格+prefix。
suffixOverrides:子句尾的命中词列表,以|分隔,忽略大小写。如果命中(轮询命中词,最多只命中一次),会删除子句尾命中的词;没命中就算了。
suffix:删除子句句尾后,在子句最后边加上单个空格+suffix。

where和set标签都可以用trim替换:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
                          <if test="username!=null and password!=null">
                             and username=#{username} and password=#{password}
                         </if>
                </trim>
                 <!-- 效果同上
          <where>
                         <if test="username!=null and password!=null">
                             and username=#{username} and password=#{password}
                         </if>
                 </where> -->
<update id="updateUser" parameterType="com.scme.pojo.User">
                 update user 
                 <set>
                     <if test="username!=null">
                             username=#{username}
                     </if>
                 </set>
                 <where> 
                     <if test="id!=null">
                             id=#{id}
                     </if>
                 </where>
         </update>
         <update id="updateUser" parameterType="com.scme.pojo.User">
                 update user 
         <trim prefix="set" prefixOverrides=",">
              <if test="username!=null"> username=#{username} </if>         </trim>           <where>                 <if test="id!=null"> id=#{id} </if>                   </where> </update>

19.Mybatis中的choose标签??

choose(when,otherwise)标签相当于switch(case,default) ,如下例,若title 为空,when标签里的代码,将不会执行,默认执行otherwise标签里面的代码。

<select id="queryBy"
     resultType="Blog">
  SELECT * FROM BLOG WHERE 1=1
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <otherwise>
      AND id= 1
    </otherwise>
  </choose>
</select>

20.Mybatis中的bind标签?

bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中。
例证:

<if test=” userNarne != null and userNarne ! = ””>
and user name like concat ( ’ 毛 ’, #{ userNarne },’ 毡 ’ )
</if>

使用 con cat 函数连接字符串,在 MySQL 中,这个函数支持多个参数,但在 Oracle 中只支持两个参数。由于不 同数据库之间的语法差异 ,如果更换数据库,有些 SQL 语句可能就需要重写。针对这种情况,可 以使用 bind 标签来避免由于更换数据库带来的一些麻烦。
可以写成下面这样:

<if test=” userNarne != null and userNarne !=””>
<bind narne= " userNarneLike ” value = ”’ 草 ’+ userNarne + ’ 每 ’” / 〉
and user name like #{userNarneLike}
</if>

bind标签的两个属性都是必选项, name为绑定到上下文的变量名,value为OGNL表达式。创建一个 bind 标签的变量后 , 就可以在下面直接使用,使用 bind 拼接字符串不仅可
以避免因更换数据库而修改 SQL,也能预防 SQL 注入。

21.SQL中的case…when…then…end???

--简单case函数
case sex
when '1' then '男'
when '2' then '女’
else '其他' end
解析:当sex值为1时,结果为男;当值为2时,结果为女,否则为其他。

--case搜索函数
case
when sex = '1' then ''
when sex = '2' then ''
else '其他' end
解析:当sex值为1时,结果为男;当值为2时,结果为女,否则为其他。

这两种方式,可以实现相同的功能。简单case函数的写法相对比较简洁,但是和case搜索函数相比,功能方面会有些限制,比如写判定式。
还有一个需要注重的问题,case函数只返回第一个符合条件的值,剩下的case部分将会被自动忽略。
通常可以与一些聚合函数结合使用。

22.select 1 from table???select count(1) from table???select sum(1) from table???

第一种的写法是增加临时列,每行的列值是写在select后的数;
第二种是不管count(a)的a值如何变化,得出的值总是table表的行数;
第三种是计算临时列的值乘以表的行数。

23.Mybatis中的<![CDATA[ sql 语句 ]]>???

术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。
在 XML 元素中,"<" 和 “&” 是非法的。
"<" 会产生错误,因为解析器会把该字符解释为新元素的开始
"&" 也会产生错误,因为解析器会把该字符解释为字符实体的开始
某些文本,比如 JavaScript 代码,包含大量 “<” 或 “&” 字符。为了避免错误,可以将脚本代码定义为 CDATA。
CDATA 部分中的所有内容都会被解析器忽略。
CDATA 部分由 “<![CDATA[" 开始,由 "]]>” 结束:
在mapper文件中写sql语句时,遇到特殊字符时,如:< 等,建议使用**<![CDATA[ sql 语句 ]]>**标记,将sql语句包裹住,不被解析器解析

24.MySQL的ROUND函数???

ROUND(X)
ROUND(X,D)
返回参数X, 其值接近于最近似的整数。在有两个参数的情况下,返回 X ,其值保留到小数点后D位,而第D位的保留方式为四舍五入。若要接保留X值小数点左边的D 位,可将 D 设为负值。
mysql> SELECT ROUND(-1.23);

    -> -1

mysql> SELECT ROUND(-1.58);

    -> -2

mysql> SELECT ROUND(1.58);

    -> 2

mysql> SELECT ROUND(1.298, 1);

    -> 1.3

mysql> SELECT ROUND(1.298, 0);

    -> 1

mysql> SELECT ROUND(23.298, -1);

    -> 20
    返回值的类型同 第一个自变量相同(假设它是一个整数、双精度数或小数)。这意味着对于一个整数参数,结果也是一个整数(无小数部分)。

当第一个参数是十进制常数时,对于准确值参数,ROUND() 使用精密数学题库:

对于准确值数字, ROUND() 使用“四舍五入” 或“舍入成最接近的数” 的规则:对于一个分数部分为 .5或大于 .5的值,正数则上舍入到邻近的整数值, 负数则下舍入临近的整数值。(换言之, 其舍入的方向是数轴上远离零的方向)。对于一个分数部分小于.5 的值,正数则下舍入下一个整数值,负数则下舍入邻近的整数值,而正数则上舍入邻近的整数值。
对于近似值数字,其结果根据C 库而定。在很多系统中,这意味着 ROUND()的使用遵循“舍入成最接近的偶数”的规则: 一个带有任何小数部分的值会被舍入成最接近的偶数整数。
以下举例说明舍入法对于精确值和近似值的不同之处:

mysql> SELECT ROUND(2.5), ROUND(25E-1);

±-----------±-------------+

| ROUND(2.5) | ROUND(25E-1) |

±-----------±-------------+

| 3 | 2 |

±-----------±-------------+

25.MySQL IFNULL() 函数???

IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。
IFNULL() 函数语法格式为:
IFNULL(expression, alt_value)
如果第一个参数的表达式 expression 为 NULL,则返回第二个参数的备用值。
参数说明:
expression 必须,要测试的值
alt_value 必须,expression 表达式为 NULL 时返回的值

26.为什么sql中时间值尽量不要用between…and…,通常建议用>=和<=?

select count(1) from user where regist_date between ‘2017-07-25 00:00:00’ and ‘2017-07-25 24:00:00’;
这条sql语句查询出结果为0。实际上数据库有一条符合该查询条件的数据。
错误原因:2017-07-25 24:00:00 晚上24点即为下一天00点 2017-07-26 00:00:00,数据库识别不出24点的信息;
换成下一天00点即可以查询出正确结果,如下:
select count(1) from user where regist_date between ‘2017-07-25 00:00:00’ and ‘2017-07-26 24:00:00’;
Java代码中可以识别24点的信息,但就算你写成24点,打印出的结果却是下一天00点。
上述情况把between…and…换成>= <=能识别出来。
总结:涉及到时间24点的时候,用下一天00点代替。

27.sql语句中两表使用join 和 不使用join 有什么区别?性能哪个好?

两张表a和b:
SELECT * FROM a INNER JOIN b ON a.id = b.id

SELECT * FROM a,b WHERE a.id = b.id
有什么区别?性能哪个好?
相同点:两者都是关联查询,其实效率相似,数据量大的时候建议还是用官方推荐的join吧。
不同点:前者是称为内连接,后者是称为等值查询。加上筛选条件后,使用前者是先将表与表先关联查询,在结果中使用条件筛选;使用后者是先通过筛选条件筛选后再进行关联。

28.Integer.valueOf()和Integer.parseInt()???

(1)Integer.valueOf()
是Integer中的静态方法,返回指定int值的Integer实例(对象)

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

(2)Integer.parseInt()
是Integer中的静态方法,返回指定字符串对应的十进制int整数

public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
}

注意:
基本数据类型不能和Object类型进行互相转换。

29.Java中的字符串转时间或者时间转字符串???

Date now = new Date();
  SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String str = simple.format(now);
  System.out.println(str);//2020-06-21 22:22:20

 
  SimpleDateFormat simple1 = new SimpleDateFormat("yyyy-MM-dd");
  String str1 = "2020-06-21 21:12:56";
  try {
   Date date = simple1.parse(str1);
   System.out.println(date);//Sun Jun 21 00:00:00 CST 2020
  } catch (ParseException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

30.Java中处理常量时为什么switch-case性能比if-else强???

(1)if-else走逻辑判断时,每条if语句都独立需要加载,都要走一遍判断。这就是耗时的机制问题了。
(2)switch-case 根据一个值进行多路分支,只做一次计算,然后将表达式的值与每个case的值比较,进而选择哪一个case语句块。

31.Mysql中按某一字段去重,并查询去重后的所有字段??

SELECT pnum, name
FROM products AA
WHERE id =
(SELECT MIN(id) FROM products BB WHERE BB.pnum = AA.pnum GROUP BY BB.pnum);

distict+多个字段----所有字段都相同时才会去重

32.MySQL中为什么往往第一次查询比第二次查询慢???

1、mysql默认的query_cache是打开的,第一次查询走的是数据文件,第二次就是query_cache,查询方式:show variables like ‘%query_cache%’,如果数据更新会重新缓存。
2、如果mysql使用的数据引擎是innodb那么第一次查询走数据文件,第二次buffer_pool也比查询数据文件要快。

33.bash和sh有什么区别呢?

两者都是shell,都是解析工具。
1.bash(Bourne Again SHell) 是linux标准的默认shell ,它基于Bourne shell,吸收了C shell和Korn shell的一些特性。
2.sh(Bourne shell )是UNIX标准的默认shell,它简洁(concise)、紧凑(compact) 、高效(fast) ,是由AT&T编写,属于系统管理shell。
bash完全兼容Bourne shell,也就是说用Bourne shell的脚本不加修改可以在bash中执行

34.服务器宕机了怎么办?

启动机器,看能否登陆,如果能登陆,请检查:
a、是否是应用程序导致内存溢出或者泄露导致
b、是否是进程过多或者不断创建,耗尽资源导致
c、是否是数据库程序死锁,连接数过多导致
d、是否是应用程序异常导致
e、是否是流量负载过大导致
f、 是否是遭受黑客入侵攻击导致
g、是否是误操作导致
如果无法查看故障现场,则可以查询系统日志查看是否有异常记录。

35.Linux经常死机、卡住

linux操作系统服务器在出现死机或卡顿情况,可以参考以下项目进行整体排查:
a、检查服务器进程与服务否占用了太多的内存或是没有释放内存,当服务器内存用完后,然后就会很快宕机;
b、看看/var/spool/cron 里面是不是有cron(计划任务、自动任务)在对应时间段内执行;
c、检查web服务器的参数是否超过了服务器的性能,如允许最大连接数过高等;
d、进程数很高,服务瘫痪,机器假死(例如zombie进程是否过多,一直占用资源);
e、cat /var/log/message查看系统日志是否有异常
f、检查磁盘是否有坏块。(可使用badblocks命令配合参数)
g、内核消耗过大,查看是否有瞬间资源占用过大的进程或服务;
h、ps -ef 查看进程异常否,是否存在攻击

36.Java中如何@Autowire写在变量上和构造方法上的区别??

public class Test1{
    @Autowired
    private A a;
    private final String prefix = a.getExcelPrefix();
}
//空指针异常
public class Test2{  
    final String prefix;
    @Autowired
    public Test(A a) {
        this.prefix= a.getExcelPrefix();
    }
}
//正常

区别主要在于加载顺序上,@autowired写在变量上的注入要等到类完全加载完,才会将相应的bean注入,而变量是在加载类的时候按照相应顺序加载的,所以变量的加载要早于@autowired变量的加载,那么给变量prefix 赋值的时候所使用的a,其实还没有被注入,所以报空指针,而使用构造器就在加载类的时候将a加载了,这样在内部使用a给prefix 赋值就完全没有问题。

Java变量的初始化顺序为:
静态变量或静态语句块–>实例变量或初始化语句块–>构造方法中的变量–>@Autowired下的变量

37.Java中类的各部分加载顺序简述

(1)类未加载
1.先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。
2.执行子类的静态代码块和静态变量初始化。
3.执行父类的实例变量初始化
4.执行父类的构造函数
5.执行子类的实例变量初始化
6.执行子类的构造函数
(2)类已加载
静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法
静态块(静态变量)→成员变量→构造方法

38.程序、进程和守护进程的区别??

程序是软件代码的集合
进程是运行着的程序
守护进程是一直运行着的程序

39.Java中的守护线程和用户线程的区别??

java中的线程分为两种:
守护线程(Daemon)用户线程(User)
  任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon(boolean);true则把该线程设置为守护线程,false则为用户线程。Thread.setDaemon()必须在Thread.start()之前调用,否则运行时会抛出异常。
在java中守护线程和本地线程有什么区别呢?
  唯一的区别是判断虚拟机(JVM)何时离开,Daemon是为其他线程提供服务,如果全部的User Thread已经撤离,Daemon 没有可服务的线程,JVM撤离。也可以理解为守护线程是JVM自动创建的线程(但不一定),用户线程是程序创建的线程;比如JVM的垃圾回收线程是一个守护线程,当所有线程已经撤离,不再产生垃圾,守护线程自然就没事可干了,当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。

40.Java如何将从库中取出的“字符串类型的json数据”转换成map??

JSONObject可以解决!!

//一般我们取到的是Object类型,如下处理:
String extra = String.valueOf(obj);
JSONObject jsonObject = JSONObject.parseObject(extra);
Map<String,Object> mapExtra = jsonObject;
//mapExtra就是转换后的map

41.Object转换成Map??

//方法一:自创版
    private static Map<String,Object> objToMap(Object object) throws IllegalAccessException {
        try{
            Class cls = object.getClass();
            Map<String,Object> map = new HashMap<>();
            while( cls.getSuperclass() != null){
                Field[] fields = cls.getDeclaredFields();//获取该类所有的属性值
                for(Field field : fields){
                    String name = field.getName();//获取属性名
                    boolean flag = field.isAccessible();//获取原来的访问控制权限
                    field.setAccessible(true);//修改访问控制权限
                    Object value = field.get(object);//获取属性值
                    field.setAccessible(flag);//恢复访问控制权限

                    //上面为什么频繁修改访问控制权限???
                    //isAccessible()值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
                    //实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问
                    //由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的

                    //value处理
                    if(value != null && StringUtils.isNotBlank(value.toString())){
                        //如果是List,将List转换为json字符串
                        if(value instanceof List){
                            value = JSON.toJSONString(value);
                        }
                        map.put(name,value);
                    }
                }
            }
            return map;
        }catch (Exception e) {
            log.info("Object To Map Failed,{}",e.getMessage());
        }
        return null;
    }

//方法二:com.fasterxml.jackson.databind.ObjectMapper版
ObjectMapper
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))//设置时间数据的格式
.convertValue(obj, JacksonType.MAP_OF_OBJECT)//转换

//方法三:io.terminus.common.utils.BeanMapper版
public static Map<String, Object> convertObjectToMap(Object obj) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        Map<String, Object> objectAsMap = new HashMap();
        BeanInfo info = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] var3 = info.getPropertyDescriptors();
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            PropertyDescriptor pd = var3[var5];
            Method reader = pd.getReadMethod();
            if (reader != null && !reader.isAccessible()) {
                reader.setAccessible(Boolean.TRUE);
            }

            objectAsMap.put(pd.getName(), reader.invoke(obj));
        }

        return objectAsMap;
    }

42.Java8中foreach()遍历时break和continue关键字不能用了??

最近优化代码时将之前的各种遍历换成并行流遍历方式,结果发现遍历方法中的continue和break关键字是无法使用的。
实际上,Java8的foreach()中我们无法直接终止方法,我们可以使用return关键字实现终止当前遍历执行下一次的作用。

List<String> list = Arrays.asList("1", "2", "3", "a", "b", "c");
list.stream().forEach(e ->{
	if(e == "1" || e == "a"){
		return;
	}
	System.out.println(e);
});
结果:
2
3
b
c

这是为什么?
在Stack Overflow中主要是说foreach()不是一个循环,不是设计为可以用break以及continue来中止的操作。

43.Java接口中的方法都是抽象方法???

以前,这句话是对的。因为接口是纯抽象类,里面的方法都是抽象方法。
JDK8出现后,看着源码,又会想到这个疑问:Java接口中的方法都是抽象方法吗?为什么JDK8后面的接口中都会出现default修饰的方法,这些方法还有方法体,即方法的实现?还有静态方法?这都是怎么回事呢。
(1)为什么接口要支持静态方法?
接口中的静态方法和类中定义的静态方法一样,不属于特定对象,所以它们不是实现接口的api的一部分,必须使用InterfaceName.staticMethod来调用它们。
接口中的静态方法背后的思想是提供一种简单的机制,允许通过将相关的方法内聚在接口中,而不必创建新的对象。
抽象类也可以做同样的事情。主要的区别在于抽象类可以有构造函数、成员变量和方法。
推荐把和只和接口相关的静态utility方法放在接口中(提高内聚性),而不需要额外创建一些utility类专门去放置这些方法。
(2)为什么接口要支持default方法?
简单理解就是,在接口中增加方法体(方法实现),就是为了让实现类中省去写实现该方法的操作从而简化操作。
(3)实例说明

//Comparator接口中的一个defalut
default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
}
//经过编译 ,反编译
public java.util.Comparator<T> reversed();
//并没有abstract关键字修饰,所以认为这种就不再是抽象方法了,所以JDK8后接口中的方法都是抽象方法这句话是不对的。

44.函数式接口@FunctionalInterface??

JDK8中我们常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。
(1)特点
1.该注解只能标记在"有且仅有一个抽象方法"的接口上。
2.JDK8接口中的静态方法和默认方法,都不算是抽象方法。
3.接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
4.该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
(2)实例说明

实例一:玩法介绍
出自https://www.zhihu.com/question/324013646/answer/1744506336

public class FunctionalInterfaceTest {

    // 1.写了一个方法,参数是函数式接口,你可以传递Runnable的实现,也可以使用Lambda或方法引用
    public static void execute(Runnable runnable) {
        try {
            runnable.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // 2.传入匿名对象
        execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名对象");
            }
        });

        // 3.使用Lambda,()表示Runnable#run()的参数,println()是Runnable#run()的方法体
        execute(() -> System.out.println("使用lambda"));

        // 5.因为wrapPrintln和上面的println做的是同样的事,可以替换
        UserService userService = new UserService();
        execute(() -> userService.wrapPrintln());
        
        // 6.IDEA提示上面的代码可以优化成 方法引用
        execute(userService::wrapPrintln);
        
        // 8.你会发现上面的写法仍是对的,因为“仅有一个抽象方法”是对Runnable的约束,不要搞混
    }

    // 4.我们试着把println()移到wrapPrintln中
    static class UserService {
        public void wrapPrintln() {
            System.out.println("包装后的println");
        }

        // 7.给UserService新增一个方法
        public void anotherMethod() {
            System.out.println("另一个方法,不影响execute使用wrapPrintln");
        }
    }
}

实例二:特点介绍

// 正确的函数式接口
@FunctionalInterface
public interface TestInterface {
 
    
    // 抽象方法
    public void sub();
 
    // java.lang.Object中的方法不是抽象方法
    public boolean equals(Object var1);
 
    // default不是抽象方法
    public default void defaultMethod(){
 
    }
 
    // static不是抽象方法
    public static void staticMethod(){
 
    }
}

注意:
java.lang.Object中的方法不是抽象方法
default不是抽象方法
static不是抽象方法
(3)总结
  函数式接口不同于以往的普通接口,它最大的作用其实是为了支持行为参数传递,比如传递Lambda、方法引用、函数式接口对应的实例对象等。
  @FunctionalInterface标记在接口上,“函数式接口”是指仅仅只包含一个抽象方法的接口。如果一个接口中包含不止一个抽象方法,那么不能使用@FunctionalInterface,编译会报错。
  函数式接口是为了lambda表达式服务,函数式接口的存在是 lambda 表达式出现的前提,lambda表达式相当于重写了函数式接口中的唯一方法。

45.Mybatis中的foreach标签??

1.属性介绍
(1)collection:
需做foreach(遍历)的对象,作为入参时,list、array对象时,collection属性值分别默认用"list"、“array"代替,Map对象没有默认的属性值。但是,在作为入参时可以使用@Param(“keyName”)注解来设置自定义collection属性值,设置keyName后,list、array会失效;
(2)item:
集合元素迭代时的别名称,该参数为必选项;
(3)index:
在list、array中,index为元素的序号索引。但是在Map中,index为遍历元素的key值,该参数为可选项;
(4)open:
遍历集合时的开始符号,通常与close=”)“搭配使用。使用场景IN(),values()时,该参数为可选项;
(5)separator:
元素之间的分隔符,类比在IN()的时候,separator=”,",最终所有遍历的元素将会以设定的(,)逗号符号隔开,该参数为可选项;
(6)close:
遍历集合时的结束符号,通常与open="("搭配使用,该参数为可选项;
2.实例

...
<if test="farmIds != null">
                AND a.farm_id IN
                <foreach item="item1" collection="farmIds" open="(" separator="," close=")">
                    #{item1}
                </foreach>
</if>
<if test="pigTypes != null &amp;&amp; pigTypes.size() > 0">
                AND a.pig_type IN
                <foreach item="item2" collection="pigTypes" open="(" separator="," close=")">
                    #{item2}
                </foreach>
</if>
...

上面的实例是从我SQL中截取的一段有关foreach的部分,这里参数是map形式,map里面有两个键值对的value是集合形式,所以我两次用到了foreach,这里就不能两次collection=“list”默认形式,我才用的是两个集合对应的key值作为collection,另外if里面用的是“pigTypes != null && pigTypes.size() > 0”这也是为了保险,我这里pigTypes集合对应的数据集合可能为空,若只用“!=null”会报错。

46.为什么匿名内部类用的变量必须final呢??

这里推荐一片非常好的文章《你知道匿名内部类、Lambda表达式为嘛只能使用外部final的变量吗?》
  从Java设计的角度来说,单纯的就为了保护数据安全和代码稳定。因为Java通过类的封装规范了类与类之间的访问权限,而内部类却打破了这种规范,它可以直接访问自身所在的外部类里私有成员,而且自身还可以创建相同的成员,从作用域角度看,内部类的新成员修改了什么值,外部方法也是不知道,因为程序的运行由外而内的,所以外部根本无法确定内部这时到底有没有这个东西。综上所述,选择final来修饰外部方法的成员,让其引用地址保持不变、值也不能被改变保证了外部类的稳定性。

47.Java内部类与外部类之间的参数传递??

直接看这里吧,写的很好《Java匿名内部类的传值》

48.ValueOperations和HashOperations的区别?

ValueOperations和HashOperations和都是操作对redis进行数据操作的工具类。
ValueOperations是操作简单的value例如String工具类,通过redisTemplate.opsForValue()获取。
HashOperations是操作value为Map的工具类,通过redisTemplate.opsForHash()获取。

49.系统快照是什么意思?

系统快照就是把系统某个状态下的各种数据记录在一个文件里,就如同人照相一样,相片显内示的是你那个时容shu间的一个状态。系统快照就是系统的“照片”,虚拟机制作了系统快照后就不用启动虚拟系统了,直接恢复快照就行了,你制作快照的时候,系统什么状态,回复后就是什么状态,包括你打开的软件的状态。
补充:
  快照的作用主要是能够进行在线数据备份与恢复。当存储设备发生应用故障或者文件损坏时可以进行快速的数据恢复,将数据恢复某个可用的时间点的状态。
  快照的另一个作用是为存储用户提供了另外一个数据访问通道,当原数据进行在线应用处理时,用户可以访问快照数据,还可以利用快照进行测试等工作。所有存储系统,不论高中低端,只要应用于在线系统,那么快照就成为一个不可或缺的功能。

50.Java中数组的声明方式??

注意:String str[]和String[] str这两种方式是一样的,都可以表示数组。

public class WhatEver {
    public static void main(String[] args) {
        //第一种   例:
        String[] test1 = new String[6];
        test1[0] = "数组0";
        test1[1] = "数组1";


        //第二种 例:
        String[] test2 = {"数组0","数组1","数组2","...."};

        //第三种 例:
        String[] test3 = new String[]{"数组0","数组1","数组2","...."};
    }
}

以梦为马,以汗为泉,不忘初心,不负韶华
梧高凤必至,花香蝶自来

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值