发表于: 2021-03-21 21:49:12

6 1046


一,今天完成的事情

任务一深度思考

1.JVM运行以及内存分配

1首先我们必须要知道的是 Java 是跨平台的。而它之所以跨平台就是因为 JVM 是跨平台的。JVM 建立了 Java 程序和操作系统之间的桥梁,JVM 是用 C 语言编写,而 C 语言不具备跨平台的特性。所以对于 Windows 平台,Java 有基于 Windows 平台的 JVM;对于 Linux 平台,Java 也有基于 Linux 平台的 JVM等等。不同的操作系统有不同的 JVM,所以我们编写的 Java 代码能在各个平台上运行,是因为有各个平台的 JVM

 

  而 Java 的内存分配也是在 JVM 中进行的。JVM Java 内存分配的原理和前提。

 

Java 程序为了提高程序的效率,对数据进行了不同空间的分配,具体划分为如下 5 个内存空间。

 

1程序计数器(Program Counter Register

  它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器。每一条JVM线程都有自己的PC寄存器,各条线程之间互不影响,独立存储,这类内存区域被称为线程私有内存在任意时刻,一条JVM线程只会执行一个方法的代码。该方法称为该线程的当前方法(Current Method);如果该方法是java方法,那PC寄存器保存JVM正在执行的字节码指令的地址;如果该方法是native,那PC寄存器的值是undefined。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

 

2Java虚拟机栈(Java Virtual Machine Stack

  与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。JVM stack 可以被实现成固定大小,也可以根据计算动态扩展。如果采用固定大小的JVM stack设计,那么每一条线程的JVM Stack容量应该在线程创建时独立地选定。JVM实现应该提供调节JVM Stack初始容量的手段;如果采用动态扩展和收缩的JVM Stack方式,应该提供调节最大、最小容量的手段。如果线程请求的栈深度大于虚拟机所允许的深度将抛出StackOverflowError;如果JVM Stack可以动态扩展,但是在尝试扩展时无法申请到足够的内存时抛出OutOfMemoryError

 

通常来说栈存放的是局部变量,包括:

  ①、保存基本数据类型的值

  ②、保存对象的引用

 

3本地方法栈(Native Method Stack

  本地方法栈与虚拟机栈作用相似,后者为虚拟机执行Java方法服务,而前者为虚拟机用到的Native方法服务。虚拟机规范对于本地方法栈中方法使用的语言,使用方式和数据结构没有强制规定,甚至有的虚拟机(比如HotSpot)直接把二者合二为一。本地方法栈抛出的异常跟上面的虚拟机栈一样。

 

4Java堆(Java Heap

  虚拟机管理的内存中最大的一块,同时也是被所有线程所共享的,它在虚拟机启动时创建,这货存在的意义就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。这里面的对象被自动管理,也就是俗称的GCGarbage Collector)所管理。用就是了,有GC扛着呢,不用操心销毁回收的事儿。Java堆的容量可以是固定大小,也可以随着需求动态扩展(-Xms-Xmx),并在不需要过多空间时自动收缩。Java堆所使用的内存不需要保证是物理连续的,只要逻辑上是连续的即可。JVM实现应当提供给程序员调节Java 堆初始容量的手段,对于可动态扩展和收缩的堆来说,则应当提供调节其最大和最小容量的手段。如果堆中没有内存完成实例分配并且堆也无法扩展,就会抛OutOfMemoryError

  堆存放的是所有 new 出来的东西,注意:这里创建出来的对象只包括属于各自的 成员变量,不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员变量复制一遍。

 

5方法区(Method Area

  跟堆一样是被各个线程共享的内存区域,用于存储以被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然这个区域被虚拟机规范把方法区描述为堆的一个逻辑部分,但是它的别名叫非堆,用来与堆做一下区别。方法区在虚拟机启动的时候创建。方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。方法区在实际内存空间中可以是不连续的。Java虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段,对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段。当方法区无法满足内存分配需求时就会抛OutOfMemoryError

 

  5.1 运行时常量池(Runtime Constant Pool

  它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。Java虚拟机对Class文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。但对于运行时常量池,Java虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。不过,一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

 

2.jdbc连接池原理及分析

1,连接池原理

在服务器端一次性创建多个连接,将多个连接保存在一个连接池对象中,当应用程序的请求需要操作数据库时,不会为请求创建新的连接,而是直接从连接池中获得一个连接,操作数据库结束之后,并不需要真正关闭连接,而是将连接放回到连接池中。

节省创建连接、释放连接 资源

2,分析

1)并发问题

为了使连接管理服务具有最大的通用性,必须考虑多线程环境

2)多数据库服务器和多用户 对于大型的企业级应用,常常需要同时连接不同的数据库(如连接oraclesybase)。设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址等信息。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。

3)连接池的分配与释放

连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。

4)连接池的配置与维护

连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minconn)和最大连接数(maxconn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快

 

3.Mybatis有哪些常用标签?怎么使用标签来完成动态查询?

1,定义SQL语句

insert

delete

update

select

配置关联关系

collection

association

配置java对象属性与查询结果集中列名的对应关系

resultMap

控制动态SQL拼接

foreach

if

choose

格式化输出

where

set

trim

定义常量

sql

其他

include

2if

动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。比如:

<select id="findActiveBlogWithTitleLike"

     resultType="Blog">

  SELECT * FROM BLOG

  WHERE state = ‘ACTIVE’

  <if test="title != null">

    AND title like #{title}

  </if>

</select>

这条语句提供了一个可选的文本查找类型的功能。如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回;反之若传入了“title”,那么就会把模糊查找“title”内容的BLOG结果返回(就这个例子而言,细心的读者会发现其中的参数值是可以包含一些掩码或通配符的)。

如果想可选地通过“title”“author”两个条件搜索该怎么办呢?首先,改变语句的名称让它更具实际意义;然后只要加入另一个条件即可。

<select id="findActiveBlogLike"

     resultType="Blog">

  SELECT * FROM BLOG WHERE state = ‘ACTIVE’

  <if test="title != null">

    AND title like #{title}

  </if>

  <if test="author != null and author.name != null">

    AND author_name like #{author.name}

  </if>

</select>

choose, when, otherwise

有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找,若两者都没有提供,就返回所有符合条件的BLOG(实际情况可能是由管理员按一定策略选出BLOG列表,而不是返回大量无意义的随机结果)。

<select id="findActiveBlogLike"

     resultType="Blog">

  SELECT * FROM BLOG WHERE state = ‘ACTIVE’

  <choose>

    <when test="title != null">

      AND title like #{title}

    </when>

    <when test="author != null and author.name != null">

      AND author_name like #{author.name}

    </when>

    <otherwise>

      AND featured = 1

    </otherwise>

  </choose>

</select>

trim, where, set

前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在考虑回到“if”示例,这次我们将“ACTIVE = 1”也设置成动态的条件,看看会发生什么。

<select id="findActiveBlogLike"

     resultType="Blog">

  SELECT * FROM BLOG

  WHERE

  <if test="state != null">

    state = #{state}

  </if>

  <if test="title != null">

    AND title like #{title}

  </if>

  <if test="author != null and author.name != null">

    AND author_name like #{author.name}

  </if>

</select>

如果这些条件没有一个能匹配上将会怎样?最终这条 SQL 会变成这样:

SELECT * FROM BLOG

WHERE

这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:

SELECT * FROM BLOG

WHERE

AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单的用条件句式来解决,如果你也曾经被迫这样写过,那么你很可能从此以后都不想再这样去写了。

MyBatis 有一个简单的处理,这在90%的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能得到想要的效果:

<select id="findActiveBlogLike"

     resultType="Blog">

  SELECT * FROM BLOG

  <where>

    <if test="state != null">

         state = #{state}

    </if>

    <if test="title != null">

        AND title like #{title}

    </if>

    <if test="author != null and author.name != null">

        AND author_name like #{author.name}

    </if>

  </where>

</select>

where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。而且,若最后的内容是“AND”“OR”开头的,where 元素也知道如何将他们去除。

如果 where 元素没有按正常套路出牌,我们还是可以通过自定义 trim 元素来定制我们想要的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">

  ...

</trim>

prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它带来的结果就是所有在 prefixOverrides 属性中指定的内容将被移除,并且插入 prefix 属性中指定的内容。

类似的用于动态更新语句的解决方案叫做 setset 元素可以被用于动态包含需要更新的列,而舍去其他的。比如:

<update id="updateAuthorIfNecessary">

  update Author

    <set>

      <if test="username != null">username=#{username},</if>

      <if test="password != null">password=#{password},</if>

      <if test="email != null">email=#{email},</if>

      <if test="bio != null">bio=#{bio}</if>

    </set>

  where id=#{id}

</update>

这里,set 元素会动态前置 SET 关键字,同时也会消除无关的逗号,因为用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号。

若你对等价的自定义 trim 元素的样子感兴趣,那这就应该是它的真面目:

注意这里我们忽略的是后缀中的值,而又一次附加了前缀中的值。

<trim prefix="SET" suffixOverrides=",">

  ...

</trim>
foreach

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

<select id="selectPostIn" resultType="domain.blog.Post">

  SELECT *

  FROM POST P

  WHERE ID in

  <foreach item="item" index="index" collection="list"

      open="(" separator="," close=")">

        #{item}

  </foreach>

</select>

foreach 元素的功能是非常强大的,它允许你指定一个集合,声明可以用在元素体内的集合项和索引变量。它也允许你指定开闭匹配的字符串以及在迭代中间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

注意 你可以将任何可迭代对象(如列表、集合等)和任何的字典或者数组对象传递给foreach作为集合参数。当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。当使用字典(或者Map.Entry对象的集合)时,index是键,item是值。

 

4.什么叫反射?反射的坏处是什么?有哪些反射的应用场景?

1Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。

2,坏处:

1使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。

2反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程序中使用反射。

3)使用反射会模糊程序内部逻辑。

4)安全限制。

5)内部暴露。代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

3,反射应用场景:

1提高程序的灵活性。改代码的风险要比改配置大,即便不知道代码的实现都能通过改配置来完成要做的事。这种就能通过可配的,其内部很可能就是通过反射来做的。

2屏蔽掉实现的细节,让使用者更加方便好用

 

5.什么是SVN,小乌龟是什么,SVN的文件版本号是怎么来的,哪些文件应该上传到SVN,哪些不该上传?GitSVN的区别又是什么?

1SVNsubversion的缩写,是一个开放源代码的版本控制系统,通过采用分支管理系统的高效管理,简而言之就是用于多个人共同开发同一个项目,实现共享资源,实现最终集中式的管理。

2svn又叫小乌龟。

3svn中的版本号revision是全局版本号,svn commit 操作可以作为一个原子事务操作发布任意数量文件和目录的修改。在你的工作副本中,你可以改变文件内容,创建、删除、改名和复制文件和目录,然后作为一个整体提交。在版本库中,每次提交被当作一次原子事务操作: 要么所有的改变发生,要么都不发生,Subversion 努力保持原子性以应对程序错误、系统错误、网络问题和其他用户行为。

每当版本库接受了一个提交,文件系统进入了一个新的状态,叫做版本,每个版本被赋予一个独一无二的自然数,一个比一个大,初始修订号是 0,只创建了一个空目录,没有任何内容。

可以形象的把版本库看作一系列树,想象有一组版本号,从 0 开始,从左到右,每一个修订号有一个目录树挂在它下面,每一个树好像是一次提交后的版本库“快照”。

4,为了减小整个svn目录的体积、以及防止过多的冲突,凡是自动生成的代码,都不应该上传到svn中,即千万不要使用svnadd命令或者菜单添加任何自动生成的目录和文件。另外,如果项目中使用了比较大的视频文件,如某个avi文件,则也建议不要上传,而是通过其他方式(如ftp或者共享)供组员下载到本机目录。

5,一般需要上传到svn的文件:

1)  所有自己写的 .h .cpp .c 文件,以及第三方库的 .h 文件

2)  项目工程相关文件 .sln 文件和  .vcproj文件,QT工程的 .qrc 文件

3)  项目资源文件,MFC工程为res目录和.rc文件,QT工程为 Resources 目录和 .ui文件,以及做界面所添加的 .ico图标文件、.img等图像文件。

4)   第三方库文件 .lib或者.dll ,自己工程生成的libdll不用上传。而使用的第三方库则不一样,如果程序链接需要第三方的lib,或者运行时需要当前运行目录下有这个第三方的dll,则需要上传。

 

6,区别

1GIT是分布式的,而SVN是集中式的

2GIT把内容按元数据方式存储,而SVN是按文件:因为git目录是处于个人机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签,分支,版本记录等。

3GIT分支和SVN的分支不同:svn会发生分支遗漏的情况,而git可以同一个工作目录下快速的在几个分支间切换,很容易发现未被合并的分支,简单而快捷的合并这些文件。

4GIT没有一个全局的版本号,而SVN

5GIT的内容完整性要优于SVNGIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

 

6.什么是AOP,适用于哪些场景,AOP的实现方案有哪些?

1AOPAspect Oriented Programming),即面向切面编程。利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

2,使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

3,使用AOP的几种方式:

1经典的基于代理的AOP

2@AspectJ注解驱动的切面

3POJO切面(纯粹通过<aop:fonfig>标签配置)

4注入式AspectJ切面

 

7.MapListArraySet之间的关系是什么,分别适用于哪些场景,集合大家族还有哪些常见的类?

1,数组:array

集合:

collection:set(集),list(列表)

map(映射):Hashmap ,Hashtable

2,最基础的是array,所有的集合都是通过array实现的。

在代码中进行随机访问和存储,array的效率是最高的,但是array是固定的,不能动态改变,且一个array只能存放同一种数据类型。针对以上缺点,就出现了集合就是list,set,map

java集合可以存储和操作不固定的一组数据,但是只能存放引用类型的数据,不能放基本数据类型。

java集合位于java.util中。

3

1List(有序、可重复):需要自动扩展的数组,所以有了List

List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。

2Set(无序、不能重复):需要没有重复的数组,所以有了set

Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。

3Map(键值对、键唯一、值不唯一):从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。适用于快速查找。

Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值

4,集合大家族的类和继承关系都写在下面了。

Collection<–List<–Vector

Collection<–List<–ArrayList

Collection<–List<–LinkedList

Collection<–Set<–HashSet

Collection<–Set<–HashSet<–LinkedHashSet

Collection<–Set<–SortedSet<–TreeSet

 

8.SpringIOC有几种方式?它们之间的差别是什么,应该选择Annonation还是应该选择XML

1,若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架。

但是我觉得这题问的是SpringIOC有几种使用方法。

a.接口注入

b.setter方法注入

c.构造方法注入

d.注解方式注入

2

1)在处理大的业务量的时候,用XML配置应该更加好一些。因为XML更加清晰的表明了各个对象之间的关系,各个业务类之间的调用。同时spring的相关配置也能一目了然。

2annotation配置在class文件中,可以降低维护成本,annotation的配置机制很明显简单。能够比XML的开发效率高,更灵活。不需要第三方的解析工具,利用java反射技术就可以完成任务。编辑期可以验证正确性,差错变得容易。

 

9.JDBCTemplateJDBC

1JDBCJava DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API, 可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。

2JDBCTemplate Spring JDBC 的封装,通俗点说就是 Spring jdbc 的封装的模板, Spring 对数据库的操作在 jdbc 上面做了深层次的封装,使用 spring 的注入功能,可以把DataSource 注入到 JdbcTemplate 之中。

 

10.为什么要使用Interface,而不是直接使用一个实体类来完成任务?InterfaceImpl这种方式的好处是什么?

1,为什么使用 interface

1)定义了一个统一的接口,方便开发人员并行合作。

2)代码简洁,便于查看

3)需要修改的时候只需要修改其实现,对外暴露的接口不用变

2,InterfaceImpl写法优点:接口+实现最常见的优势就是实现类和接口分离,在更换实现类的时候,不用更换接口功能。

 

11.为什么要处理异常,Try/Catch应该在什么样的场景下使用,在真实的系统中,会出现网络中断,DB连接不上的错误吗?多久会发 生一次?

1为什么要处理异常:在实际的运行环境中,总有开发者无法预料甚至无关管控的情况发生,为了不让这些意外情况产生不可预测的后果,我们需要主动处理异常。

2Try/Catch应该在什么样的场景下使用:捕捉异常,自己处理。程序块中语句可能的异常不能引起其他逻辑中断;例如:缓存逻辑不能影响正常的逻辑运行,故缓存逻辑应该放在try/catch块中。或者,必须对异常进行处理,否则会降低用户使用体验。例如:异常到了Controller层,若不处理则会返回404500错误页面,因此,必须使用try/catch处理各种异常。

3在真实系统中,会出现网络中断导致DB无法连接的情况。发生的频率和系统设计有关。希望设计能让用户感知不到。

 

12.日志应该怎么打,在什么位置,需要打印出来什么样的关键参数?

1打印日志应该使用框架,而不是 System.out.print``` ,否则日志不会保存下来,不利于排错。

2,根据要求,判断打印的位置。如果记录系统或者机器的状态,查看的位置有比:网络请求、系统CPU、内存、IO使用情况等等。这种日志主要是给运维人员使用,生成各种更直观的展现形式,在系统出问题的时候报警。

3,一条信息完整的日志,应该包含 whenwherelevelwhatwhocontext

 

13.为什么需要单步调试?Debug的时候IDE是怎么找到源码的?

1单步调试可以随意的暂停,查看上下文变量的值来分析具体错误产生的原因。

2IDE无论什么时候,找到源码的方式和编译原理有关。提示和跳转就是不断的对你的代码做语法分析。有的做法是用AST抽象语法树。intellij在打开一个编辑器的时候,会扫描文件里所有的【可以引用到一个外部定义】的AST节点,比如变量名。对于每个AST节点(类名叫PsiElement),它有个方法叫getReferences会被调用,如果没有返回null而是返回了一个PsiReference的实例,那么intellij就知道你这个AST节点是可以【引用其他节点的】。对于每个变量名,intellij会调用它的getReferences返回的PsiReference的一个叫resolve的方法。这个方法会返回它所引用的那个AST节点。

 

14.可否远程连接到线上直接调试?真实的项目中,遇到问题的排查方案是什么?

1,可以,并且很多时候需要远程连接到线上直接调试。本地环境与远程环境为不一致,线上线下数据的不一致,导致有些问题没办法在本地复现。仅靠本地调试无法直接定位问题。

2,首先定位问题,定位系统异常,还有业务应用。然后一般会用各种性能分析工具,查看CPU,内存,磁盘,网络等情况。对于java,常用命令有:jps: 查询当前机器所有 JAVA 进程信息;jmap: 输出某个 java 进程内存情况 (:产生那些对象及数量等)jstack: 打印某个 Java 线程的线程栈信息;jinfo: 用于查看 jvm 的配置参数。

也应该考虑分析日志:GC 日志,业务日志等。

 

15.Spring中的IOC是什么意思,为什么要用IOC而不是New来创建实例?

1IOC—Inversion of Control,即控制反转,不是什么技术,而是一种设计思想。传统JavaSE程序设计,我们在对象内部直接通过new进行创建对象,是程序主动去创建依赖对象,而IoC有一个专门的容器来创建这些对象,即由IoC容器来创建这些对象的创建。

理解好IoC的关键是:谁控制谁,控制了什么,为何是反转,在哪些方面反转了。

2使用 new 来创建实例有以下弊端:使用起来非常繁琐,而且需要了解整个依赖链条并全部实例化。

当之前的依赖发生改变的时候之后所有的实例都需要修改。这导致了耦合非常紧密,不利于业务的开发。这是一种硬编码,违反了面向接口编程的原则。频繁创建对象,浪费了资源。

使用 IOC 之后,向容器索取 bean 即可:bean 之间解耦,在运行期间会动态的进行依赖设置。需要更改 dao 的时候只需要修改 daoImpl,不会破坏其他的代码。不需要手动整理其依赖关系

 

16.什么是贫血模型,什么是充血模型?为什么我们会强制要求使用贫血模型?

1,首先介绍贫血模型和充血模型 

贫血模型:是指领域对象里只有getset方法,或者包含少量的CRUD方法,所有的业务逻辑都不包含在内而是放在Business Logic层。

优点是系统的层次结构清楚,各层之间单向依赖,Client->(Business Facade)->Business Logic->Data Access

充血模型: 层次结构和上面的差不多,不过大多业务逻辑和持久化放在Domain Object里面,Business Logic只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成Client->Business Facade)->Business Logic->Domain Object->Data Access

 2,接下来对比

贫血模型只负责存储数据,剥离了业务代码,整个代码结构更加清晰,并且抽象出各种结构,方便开发人员协同工作。

 

17.clean,install,package,deploy分别代表什么含义?

1clean:我们在使用maven的构建项目会产生一个target文件,但我们修改了代码后就需要使用clean清楚target,重新生成target

2package:打包到本项目,一般是在项目target目录下。如果a项目依赖于b项目,打包b项目时,只会打包到b项目下target下,编译a项目时就会报错,因为找不到所依赖的b项目,说明a项目在本地仓库是没有找到它所依赖的b项目。

3install:打包会安装到本地的maven仓库中,如果没有设置过maven本地仓库,一般在用户/.m2目录下。如果a项目依赖于b项目,那么install b项目时,会在本地仓库同时生成pom文件和jar文件

4maven deploy:项目打包上传至远程仓库,将最终版本的包拷贝到远程

5,总结。package命令完成了项目编译、单元测试、打包功能,但没有把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库

install命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库,但没有布署到远程maven私服仓库

deploy命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库

 

18.怎么样能让Maven跳过JUnit?

1跳过测试代码的编译

mvn package -Dmaven.test.skip=ture

2编译,但是跳过单元测试

mvn package -DskipTest

 

 19.为什么要用Log4j来替代System.out.println

1println 只能输出到控制台,不能保存

2println 需要手动指定输出的信息,完成后需要手动注释

3log4j 可以分级输出日志,并且可以输出调试信息

总之,记录日志可以作为日后处理问题的一个追溯,方便开发者根据日志来统计查询处理问题。此外,查阅日志内容可以了解项目的运行状况,发现项目存在的一些隐藏的bug

 

20.为什么DB的设计中要使用Long来替换掉Date类型?

1mysql 中的 date 分很多种,使用long 统一处理比较方便

2使用 long 保存的开销比字符串小




二,今天问题:

正在考虑任务二代码如何呈现较好。


三,今天的收获:

复习了反射等。基本数据结构比较,基本数据库知识。


四,明天的计划:

继续任务一深度思考。任务一总结。



返回列表 返回列表
评论

    分享到