java面试题技术面试问题汇总(陆续补充)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nb7474/article/details/79644805

1.堆,栈,方法区的区别?
堆区
①存放的都是对象,每个对象都包含着一个与之相对应的class的信息,class的目的是得到一些操作指令
②jvm中只有一个堆区,被所有线程共享,堆区不存放基本类型和对象引用,只存放对象本身。
栈区
①每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中。
②每个栈中的数据(原始类型和对象引用)都是私有的,其他栈中不能访问
方法区
①又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
②方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量

2.创建一个类的几种方法? 四种方法.
①使用new关键字
②使用Class类的newInstance方法
③使用clone方法
④使用反序列化

3,序列化和反序列化的概念? 读取和写入一个序列化的类.

① :概念
序列化:指把内存中的java对象数据,通过某种方式吧对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。通俗来说就是将数据结构或者对象转换成二进制串的过程。
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成java对象模型的过程。通俗点说就是讲序列化过程生成的二进制串转换成数据结构或者对象的过程。

② .为什么要使用序列化?
I、 在分布式系统中,对象是在网络上传输,就得把对象数据转换成二进制形式,需要共享的数据的javabean对象,这就需要使用序列化

③ 序列化的过程:
I、 需要序列化的对象的类,必须实现序列化接口:java.lang.Serializable,大多数类都实现了该接口,比如string、integer。
II、 在java中使用对象流来完成序列化和反序列化
ObjectoutputStream 通过writeObject做序列化
ObjectInputStream 通过readObject做反序列化

具体方法在https://blog.csdn.net/nb7474/article/details/79644777 第七题

4.现有employee 表,表中有 员工编号(id) 员工年龄(age) 员工工资(salary) 员工部门(deptid), 按要求用一条SQL语句完成
①查出各个部门高于部门平均工资的员工名单
Select ta.* from employee ta,
(select deptia,avg(salary) avgsal from employee group by deptid) tb
Where ta.deptid=tb.deptid and ta.salary>tb.avgsal

②列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序
Select ta.deptid,count(*) as ‘人数’ from employee ta,
(select deptid,avg(salary) avgsal from employee group by deptid) tb
Where ta.deptid=tb.deptid and ta.salary>tb.avgsal group by ta.deptid order by ta.deptid

③ 求每个部门工资不小于6000的人员的平均值
Select avg(salary) as ‘平均值’,deptid from employee where salary>=6000 GROUP BY dept_id

④ 各部门在各年龄段的平均工资
Select deptid
Sum(case when age<20 then salary else 0 end )/sum (case when age < 20 then 1 else 0 end) as “20岁以下平均工资”,
Sum (case when age >= 20 ande age <40 then salary else 0 end)/sum(case when age >=20 and age<40 then 1 else 0 end) as “20至40岁平均工资”,
From employee
Group by deptid

5.abstract和native方法的区别?

Native本地方法,这种方法和抽象方法类似,只有方法声明没有方法实现,但是与抽象方法不同的是,它吧具体具体实现移交给了本地系统的函数库,没有通过虚拟机,可以说是java与其它语言通讯的一种机制。
Abstract是抽象的,指的是方法只有声明没有实现,他的实现要方式声明该类的子类中实现。
抽象方法都是不可以与private、static、final和native一起使用的,因为抽象方法都是要子类来实现的。

Abstract与接口的区别:https://blog.csdn.net/jackzhouyu/article/details/52699682

6, 类加载的生命周期?
首先我们所说的类加载指的是类的生命周期中加载、连接、初始化三个阶段。
① 加载:查找并加载类的二进制数据。找到要加载的类并把类的信息加载到jvm的方法区中,然后再堆区实例化画一个java.lang.class对象,作为方法区中这个类的信息的入口。
常用的类的加载方式有两种:
I、 根据类的全路径名找到相应的class文件,从class文件中读取文件内容。
II、 另一种是从jar文件中读取。

② 连接:一般会跟加载阶段和初始化阶段交叉进行,主要做一些加载后的验证工作,和一些初始化前的准备工作,分为:

I、验证:保证加载的类能够被jvm所运行

II、准备:为类的静态变量分配内存并设默认的初值。基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0,引用类型的默认值为null,常量的默认值为设定的值,如final static int a=100,则初值就是100。

III、 解析:把常量池中的符号引用转换为直接引用,在这阶段,jvm会将所有的类或接口名、字段名、方法名转换为具体的内存地址。比如我们要在内存中找一个show方法,在解析阶段,jvm会把show这个名字转换为指向方法区的一块内存地址,比如c1716,通过c1716可以找到这show这个方法。Show就是符号引用,c1617就是直接引用。

③ 初始化:如果一个类被直接引用,就会触发类的初始化。在java中,直接引用的情况有:

I、 new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法

II、 通过反射方式执行以上三种行为。

III、 初始化子类的时候,会触发父类的初始化

IV、 作为程序入口直接运行,即直接调用main方法
除了以上四种情况,其他使用类的方式叫被动引用,不会触发类的初始化。

7, arrayList的扩容方式?

首先扩容机制:当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力,ArrayList会增强自身的存储能力,以达到存储新元素的要求。

ArrayList通过内部维护的数组对象进行数据存储。
以jdl1.7举例
① :分析ArrayList的add(e)方法

public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!!
 elementData[size++] = e; return true; }

通过ensureCapacityInternal()方法确保当前ArrayList维护的数组具有存储新元素的能力,经过处理后将元素存储在数组elementData的尾部。elementData是ArrayList真正用于存储元素的数组。

② :分析ensureCapacityInternal方法

private void ensureCapacityInternal(int paramInt)
  {
    if (elementData == EMPTY_ELEMENTDATA) {
      paramInt = Math.max(10, paramInt);
    }
    ensureExplicitCapacity(paramInt);
  }

ensureCapacityInternal判断ArrayList默认的元素存储数据是否为空,为空则设置最小要求的存储能力为10和传递过来需要存储的元素个数之间的最大值,然后调用ensureExplicitCapacity方法实现这种最低要求的存储能力。

③:分析ensureExplicitCapacity方法:

private void ensureExplicitCapacity(int paramInt)
  {
    modCount += 1;
    if (paramInt - elementData.length > 0) {
      grow(paramInt);
    }
  }

④:分析grow方法:

private void grow(int paramInt)
  {
    int i = elementData.length;
    int j = i + (i >> 1);
    if (j - paramInt < 0) {
      j = paramInt;
    }
    if (j - 2147483639 > 0) {
      j = hugeCapacity(paramInt);
    }
    elementData = Arrays.copyOf(elementData, j);
  }

执行扩容操作的时候会设置新的存储能力为原来的1.5倍,如果扩容之后还是不能满足需求,会执行hugeCapacity()方法获取ArrayList能允许的最大值。

⑤:分析hugeCapacity()方法:

private static int hugeCapacity(int paramInt)
  {
    if (paramInt < 0) {
      throw new OutOfMemoryError();
    }
    return paramInt > 2147483639 ? Integer.MAX_VALUE : 2147483639;
  }

在确定ArrayList扩容后最新的可存储元素的个数时,调用elementData = Arrays.copyOf(elementData, j);实现最终的扩容。

8, spring事务的优点?

在以往的jdbcTemplate中事务提交成功,异常处理是通过try/catch实现的。
Hibernate中事务管理是通过sessionFactory创建和维护session来完成。

在spring中集成了transactionTemplate,封装了所有对事物处理的功能,包括异常时事务回滚,操作成功时数据提交等复杂业务功能。对sessionFactory配置也进行了整合,都是有spring容器来管理,大大减少了程序员的代码量。避免了每次对数据操作都要获取session实例来启动事务、提交、回滚事务还有复杂的try/catch。使开发业务逻辑更清晰、降低了程序的耦合性使我们可以在不同的应用中将各个切面结合起来使用提高了代码重用度。

9, getParameter和getAttribute的区别?

① getAttribute表示从request范围取得设置的属性,必须要先setAttribute设置属性。设置与取得的都是Object对象类型getParameter表示接收参数,参数为页面提交的参数,包括:表单提交的参数、URL重写(就是xxx?id=1)传的参数,没有setParameter的方法,接收的参数类型是string

② request.getParameter方法传递的数据,会从web客户端传到web服务器端,代表HTTP请求的数据getAttribute传递的数据只会存在于web容器内部,在具有转发关系的web组件之间共享。返回的是request范围内存在的对象

③ getParameter取得的是通过容器的实现来取得通过类似post,get等方式传入的数据,getAttribute只在web容器内部流转,仅仅是请求处理阶段

10, onload()和ready()的区别?

$(document).ready()和window.onload在表面上看都是页面加载时候我们就去执行一个函数或动作,但是有几个基本的区别:

① 执行时间:window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。$(document).ready()是dom结构绘制完毕后就执行,不必等到加载完毕

② 编写个数不同:window.onload不能同时编写多个,如果有多个window.onload方法,只能执行一个。$(document).ready()可以同时编写多个,并且都能得到执行

③ 简化写法:
window.onload没有简化写法 (document).ready(function()) (function(){})需要注意的一点: 由于在$(document).ready()方法内注册的时间,只要DOM就绪就会被执行,因此可能此时元素的关联文件未下载完。例如与图片有关的html下载完毕,并且已经解析为DOM树了,但很有可能图片还未加载完毕,所以例如图片的高度和宽度这样的属性此时不一定生效。要解决这种问题,可以使用JQuery中另一个关于页面加载的方法-load()。Load方法会在元素的onload时间中绑定一个处理函数,如果处理函数绑定给window对象,则会在所有内容加载完毕后触发,如果绑定在元素上,则会在元素的内加载完毕后触发。

$(window).load(function(){ } ) 等价于js中的window.onload=funciton(){ }

11、 SpringMVC 怎么添加过滤使得避免空指针?
这个最后才知道可以在javabean上设置注解设置这个字段不能为空.

12, 如何通过反射去调用一个类的私有方法?
这个是需要setAccessible()方法来抑制Java访问权限的检查的, 详见:https://blog.csdn.net/nb7474/article/details/79679629

13, 你对Spirng的理解?
Spring相对于ejb来说是一个轻量级的DI和AOP容器框架
在spring中的主要核心有两点:

① 控制反转(IOC)

控制反转意思就是对象的创建不通过手动new,而是把对象的创建权交给Spring来完成。接着便是依赖注入(DI),在容器实例化对象的时候主动将他的依赖对象注入给调用对象。
Spring的IOC有三种注入方式:I、根据属性注入,也叫set方法注入
II、根据构造方法进行注入
III、根据注解进行注入,bean多的情况下,前两种方法会过于臃肿

② 面向切面编程(AOP)

给目标对象的目标方法添加一些额外的功能,将业务中必须的却又与核心业务无关的功能(如权限、日志、事务等功能)独立出去,定义到切面中。好处就是层级清晰便于拓展维护。
比如:每对数据库进行一次操作,都要生成一条体质,如果对数据库的操作有很多类,那么每一类都要写关于日志的方法。如果用aop,那么可以写一个方法,在这个方法中有关于数据库操作的方法,每调用一次这个方法,就加上生成日志的操作。
Spring的优点:解决系统代码耦合度过高的问题,易于维护。

14.List和Array的区别?

①相似之处:
I、都可以表示一组同类型的对象
II、都可以用下标进行索引
②不同之处:
I、数组可以存任何类型的元素,list不可以存基本数据类型的元素,必须要包装。(Java集合如Map、Set、List等所有集合只能存放引用类型数据,实际存放的只是对象的引用,想把基本数据类型存入集合中,直接存就可以了,系统会自动将其装箱成封装类,然后加入到集合当中)
II、数组容量固定不可改变;List 容量可动态增长。
III、数组效率高; List 由于要维护额外内容,效率相对低一些。

容量固定时优先使用数组,容纳类型更多,更高效。
在容量不确定的情景下, List 更有优势。

猜你喜欢

转载自blog.csdn.net/nb7474/article/details/79644805