Java面试知识总结三
1.SpringMVC在项目中的应用?
1)service层,项目的业务逻辑层,一般先定义一个接口,在写一个实现类,实现所有的接口方法。service的实现类中要加注解@Service(用于标注业务层组件),@Resource 注入dao组件,方便在业务层中调用对用dao的方法.
@Service
public class ContentServiceImpl implements ContentService{
@Autowired
private ContentDao contentdao;
2)controller层,控制层它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。controller要添加注解@Controller(用于标注控制层组件)),@Resource 注入service组件,方便调用业务层的方法.
@Controller
public class ContentController {
@Autowired
private ContentService contentService;
//用户评论 提交 按钮--insert
@RequestMapping("/ContentController")
@ResponseBody
public Object addByText( @ModelAttribute("content") Content content,HttpServletRequest request){
content.setUsername(((User)(request.getSession().getAttribute("sessionuser"))).getUsername());
contentService.addByText(content);
return new Gson().toJson(contentService.queryOneForJustNow());
}
2.Redis缓存数据存放的时间?
列:在实现积分项目业务中,对不同场景设置了不同的key-value缓存到了redis中。但是因为对不同业务的key需要缓存的时间不尽相同,这里自定义工具类来实现。
设置redis缓存key,截取部分代码:
try{
//cacheManager就相当从redis链接池获取一个连接,具体工厂类获取在后面备注
cacheManager = (RedisCacheManager) CacheManagerFactory.getCacheManager();
totalMonCount = Float.parseFloat(cacheManager.getString(monthKey)) + centCount;
if (centLimitByMonth != -1){
if (totalMonCount > centLimitByMonth) {
// 超出月上限不再累计
logger.error("exceeds the month limit cents! [" + totalMonCount + "] code:[" + code + "]");
return null;
}
} //当未超出月额度,此时要对日额度进行判断;只需判断其是否超出日上限积分
if (dayKey != null){
//累积积分;因为签到其实是没有每日积分的,是按次数规则累积的;但为了统一,直接用centCount代替(都是签一次1分)
totalDayCount = Float.parseFloat(cacheManager.getString(dayKey)) + centCount;
if (centLimitByDay != -1){
if (totalDayCount > centLimitByDay){
logger.info("[ERROR]teacher everyday assign cents > month limit! total: ["+totalDayCount+"]");
return null;
}
}
cacheManager.set(dayKey,totalDayCount.toString(),DateUtil.getSecsToEndOfCurrentDay()); }
//对月限制key进行积分累加
//每月1号凌晨1点启动脚本删除,同时设置了保存到月底缓存时间双重保障
cacheManager.set(monthKey, totalMonCount.toString(), DateUtil.getSecsToEndOfCurrentDay());
logger.info("==monthkey:"+monthKey+"---value:"+totalMonCount);
}
...
}catch(Exception e){
logger.error("===cache redis fail!");
e.printStackTrace(); }finally { if (cacheManager != null){
cacheManager.close();
}
} //工厂类获取redis链接
public class CacheManagerFactory { private static ICacheManager cacheManager; private CacheManagerFactory(){
}; public static ICacheManager getCacheManager(){
if(cacheManager == null){
synchronized (CacheManagerFactory.class) {
if(cacheManager == null){
JedisPooler jedisPooler = RedisPoolerFactory.getJedisPooler();
cacheManager = new RedisCacheManager(jedisPooler);
}
}
}
return cacheManager;
} } //redis链接池工厂类获取链接
public class RedisPoolerFactory { private static JedisPooler jedisPooler; private RedisPoolerFactory(){
}; public static JedisPooler getJedisPooler(){
if(jedisPooler == null){
synchronized (RedisPoolerFactory.class) {
if(jedisPooler == null){
jedisPooler = new JedisPooler();
}
}
}
return jedisPooler;
} } /**
*
* Redis 连接池实例
*
* @author Ethan.Lam
* @createTime 2011-12-3
*
*/
public class JedisPooler { private JedisPool pool;
private String REDIS_HOST;
private String REDIS_PSW;
private int REDIS_PORT;
private int REDIS_MaxActive;
private int REDIS_MaxIdle;
private int REDIS_MaxWait; public JedisPooler(String config) {
__init(config);
} public JedisPooler() {
__init("/jedisPool.properties");
} private void __init(String conf) {
// 完成初始化工作
Properties prop = new Properties();
try {
InputStream _file = loadConfig(conf);
prop.load(_file);
REDIS_HOST = prop.getProperty("REDIS.HOST");
REDIS_PSW = prop.getProperty("REDIS.PSW");
REDIS_PORT = Integer.parseInt(prop.getProperty("REDIS.PORT").trim());
REDIS_MaxActive = Integer.parseInt(prop.getProperty("REDIS.MaxActive").trim());
REDIS_MaxIdle = Integer.parseInt(prop.getProperty("REDIS.MaxIdle").trim());
REDIS_MaxWait = Integer.parseInt(prop.getProperty("REDIS.MaxWait").trim());
} catch (Exception e) {
e.printStackTrace();
REDIS_HOST = "localhost";
throw new NullPointerException(conf + " is not found !");
}
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxActive(REDIS_MaxActive);
config.setMaxIdle(REDIS_MaxIdle);
config.setMaxWait(REDIS_MaxWait);
config.setTestOnBorrow(true);
System.out.println("REDIS Cache服务信息: 当前连接的服务IP为:" + REDIS_HOST + ":" + REDIS_PORT);
if (null == REDIS_PSW || "".equals(REDIS_PSW.trim())){
pool = new JedisPool(config, REDIS_HOST, REDIS_PORT, 5000);
}
else{
pool = new JedisPool(config, REDIS_HOST, REDIS_PORT, 5000, REDIS_PSW);
} } public Jedis getJedis() {
return pool.getResource();
} public void returnResource(Jedis jedis) {
pool.returnResource(jedis);
} public JedisPool getPool() {
return pool;
} InputStream loadConfig(String configPath) throws Exception {
InputStream _file = null;
try {
String file = JedisPooler.class.getResource(configPath).getFile();
file = URLDecoder.decode(file);
_file = new FileInputStream(file);
} catch (Exception e) {
System.out.println("读取jar中的配置文件....");
String currentJarPath = URLDecoder.decode(JedisPooler.class.getProtectionDomain()
.getCodeSource().getLocation().getFile(), "UTF-8"); // 获取当前Jar文件名
System.out.println("currentJarPath:" + currentJarPath);
java.util.jar.JarFile currentJar = new java.util.jar.JarFile(currentJarPath);
java.util.jar.JarEntry dbEntry = currentJar.getJarEntry("jedisPool.properties");
InputStream in = currentJar.getInputStream(dbEntry);
_file = in;
}
return _file;
} }
对于redis这种希望指定缓存有效时间,现在提供3种方案:
1)自定义确切时间:
public static final long LoginCentTimeByDay = 86400;//s 未认证失效时间 1天
public static final long LoginCentTimeByMonth = 86400*30; //s 时效时间 30天
直接指定:
cacheManager.set(monthKey, totalMonCount.toString(),LoginCentTimeByDay)
2)自定义工具类,获取当前时间到第二天的零点、下个月1号零点的时间差(s):
cacheManager.set(monthKey, totalMonCount.toString(), DateUtil.getSecsToEndOfCurrentDay()); public class DateUtil { /**
*获取每月最后一天时间
* @param sDate1
* @return
*/
public static Date getLastDayOfMonth(Date sDate1) {
Calendar cDay1 = Calendar.getInstance();
cDay1.setTime(sDate1);
final int lastDay = cDay1.getActualMaximum(Calendar.DAY_OF_MONTH);
Date lastDate = cDay1.getTime();
lastDate.setDate(lastDay);
return lastDate;
} /*
获取下一个月第一天凌晨1点
*/
public static Date nextMonthFirstDate() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 1); //设置为每月凌晨1点
calendar.set(Calendar.DAY_OF_MONTH, 1); //设置为每月1号
calendar.add(Calendar.MONTH, 1); // 月份加一,得到下个月的一号
// calendar.add(Calendar.DATE, -1); 下一个月减一为本月最后一天
return calendar.getTime();
} /**
* 获取第二天凌晨0点毫秒数
* @return
*/
public static Date nextDayFirstDate() throws ParseException {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DAY_OF_YEAR, 1);
cal.set(Calendar.HOUR_OF_DAY, 00);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
return cal.getTime();
} //********* /**
* 获取当前时间到下个月凌晨1点相差秒数
* @return
*/
public static Long getSecsToEndOfCurrentMonth(){ Long secsOfNextMonth = nextMonthFirstDate().getTime();
//将当前时间转为毫秒数
Long secsOfCurrentTime = new Date().getTime();
//将时间转为秒数
Long distance = (secsOfNextMonth - secsOfCurrentTime)/1000;
if (distance > 0 && distance != null){
return distance;
} return new Long(0); } /**
* 获取当前时间到明天凌晨0点相差秒数
* @return
*/
public static Long getSecsToEndOfCurrentDay() throws ParseException { Long secsOfNextDay = nextDayFirstDate().getTime();
//将当前时间转为毫秒数
Long secsOfCurrentTime = new Date().getTime();
//将时间转为秒数
Long distance = (secsOfNextDay - secsOfCurrentTime)/1000;
if (distance > 0 && distance != null){
return distance;
} return new Long(0); }
}
3)使用定时任务定时清空redis缓存;避免出现定时任务异常,我的业务代码里都保障了两种方案都适用。
定时任务保证,到指定时间直接调用代码进行操作;代码里直接调用shell脚本直接删掉相关redis的缓存数据。
quartz定时任务就需要注意定义相应的cron时间:
我的定时任务的配置文件quartz.xml中定义:
<!--定时任务1-->
<!-- 每天12点将当天用户积分行为缓存清掉 -->
<bean id="deleteRedisCacheDayUsersJob" class="cn.qtone.xxt.cent.quartz.delRedisCacheCentUsers" />
<bean id="deleteRedisCacheDayUsersTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="deleteRedisCacheDayUsersJob" />
<property name="targetMethod" value="delCurrentDayCacheUsersByDay" /><!-- 定时执行 doItem 方法 -->
<property name="concurrent" value="false" />
</bean>
<bean id="deleteRedisCacheDayUsersTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="deleteRedisCacheDayUsersTask" />
<property name="cronExpression" value="59 59 23 * * ?" /><!-- 每天凌晨23:59:59 点执行 -->
<!--<property name="cronExpression" value="0 */1 * * * ?" /><!– 每隔1min执行一次 –>-->
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="deleteRedisCacheDayUsersTrigger" />
<ref bean="deleteRedisCacheMonthUsersTrigger" />
<!--暂时不用-->
<!--<ref bean="centUpdateByMonthTrigger" />-->
</list>
</property>
</bean>
3.数据库中有一张表,表中有主键。现在后台要插入一条数据,但是这条数据会与主键冲突。项目已经开启了事物,要求这条数据不插入进数据库程序能正常运行。问解决的两个办法?
mysql忽略主键冲突、避免重复插入的几种方式
方案一:使用 ignore 关键字
如果是用主键primary或者唯一索引unique区分了记录的唯一性,避免重复插入记录可以使用:这样当有重复记录就会忽略,执行后返回数字0
insert
ignore
into
table_name(email,phone,user_id)
values
(
'test9@163.com'
,
'99999'
,
'9999'
)
还有个应用就是复制表,避免重复记录
insert
ignore
into
table
(
name
)
select
name
from
table2
方案二:使用 replace into
replace的语法格式为:
1.
replace
into
table_name(col_name, ...)
values
(...)
2.
replace
into
table_name(col_name, ...)
select
...
3.
replace
into
table_name
set
col_name=value, ...
replace
into
table_name(email,phone,user_id)
values
(
'test569'
,
'99999'
,
'123'
)
;方案三:ON DUPLICATE KEY UPDATE
INSERT
INTO
table_name1(title,first_name,last_name,email,phone,user_id
,role_id,status,campaign_id)
SELECT
''
,
''
,
''
,table_name2.email,table_name2.phone,
NULL
,
NULL
,
'pending'
,29
FROM
table_name2
WHERE
table_name2.status = 1
ON
DUPLICATE
KEY
UPDATE
table_name1.status =
'pending'
4.数据连接池:数据连接已经占满了,资源释放不掉该怎么处理(注意不是连接池配置问题)?
待解答:
5.编写一个队列,内部是用数组实现。最大长度为2000?
package JavaMianSiTest; public class QueueTest { public static void main(String[] args) {
ArrayQueue queue = new ArrayQueue(100); System.out.println(queue.isEmpty()); for (int i = 0; i < 100; i++) {
queue.insert(i);
}
System.out.println(queue.isFull()); while (!queue.isEmpty()) {
System.out.println(queue.remove());
}
} } class ArrayQueue {
private int[] arrInt;// 内置数组
private int front;// 头指针
private int rear;// 尾指针 public ArrayQueue(int size) {
this.arrInt = new int[size];
front = 0;
rear = -1;
} /**
* 判断队列是否为空
*
* @return
*/
public boolean isEmpty() {
return front == arrInt.length;
} /**
* 判断队列是否已满
*
* @return
*/
public boolean isFull() {
return arrInt.length - 1 == rear;
} /**
* 向队列的队尾插入一个元素
*/
public void insert(int item) {
if (isFull()) {
throw new RuntimeException("队列已满");
}
arrInt[++rear] = item;
} /**
* 获得对头元素
*
* @return
*/
public int peekFront() {
return arrInt[front];
} /**
* 获得队尾元素
*
* @return
*/
public int peekRear() {
return arrInt[rear];
} /**
* 从队列的对头移除一个元素
*
* @return
*/
public int remove() {
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
return arrInt[front++];
}
}
6.Spring中bean的实现原理?
待解答:
7.SpringAOP的原理?
类别 |
机制 |
原理 |
优点 |
缺点 |
静态AOP |
静态织入 |
在编译期,切面直接以字节码的形式编译到目标字节码文件中。 |
对系统无性能影响。 |
灵活性不够。 |
动态AOP |
动态代理 |
在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。 |
相对于静态AOP更加灵活。 |
切入的关注点需要实现接口。对系统有一点性能影响。 |
动态字节码生成 |
在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。 |
没有接口也可以织入。 |
扩展类的实例方法为final时,则无法进行织入。 |
|
自定义类加载器 |
在运行期,目标加载前,将切面逻辑加到目标字节码里。 |
可以对绝大部分类进行织入。 |
代码中如果使用了其他类加载器,则这些类将不会被织入。 |
|
字节码转换 |
在运行期,所有类加载器加载字节码前,前进行拦截。 |
可以对所有类进行织入。 |
Spring AOP动态代理类:
1.使用CGlib动态代理:http://blog.csdn.net/yakoo5/article/details/9099133/
2.使用jdk实现动态代理:http://rejoy.iteye.com/blog/1627405
动态代理和静态代理的区别:
静态代理类优缺点
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
动态代理优缺点:
好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。
这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转
缺点:那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。
参考资料:http://layznet.iteye.com/blog/1182924
8.页面中出现乱码,怎么解决,在那几个地方解决?
1)在jsp 页面中的开头添加<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
2)web.xml中加入
<!--form表单通过post传递的时候解决乱码问题 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3)在controller层中的注解加
@RequestMapping(value = "/ajaxContent", produces = "text/html;charset=UTF-8;")
4)在eclipse中对当前页面右键选择properties的other中选择utf-8(这个是解决Java代码中的注解乱码)
9.Stringbuffer 和stringbudier的区别?
1)在执行速度方面的比较:StringBuilder > StringBuffer > String
2)StringBuilder:线程非安全 StringBuffer:线程安全的
string 、stringbuffer和stringbudier三者使用的总结:
1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
Java面试知识总结三的更多相关文章
- Java面试集合(三)
前言 大家好,给大家带来Java面试集合(三)的概述,希望你们喜欢 三 1.在Java中是否可以含有多个类? 答:可以含有多个类,但只有一个是public类,public类的类名与文件名必须一致. 2 ...
- Java面试集合(三)-30道面试题
前言 大家好,我是 Vic,今天给大家带来Java面试集合(三)的概述,希望你们喜欢 三 1.在Java中是否可以含有多个类?答:可以含有多个类,但只有一个是public类,public类的类名与文件 ...
- Java 面试知识点解析(三)——JVM篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- 中移物联网Java面试-社招-三面(2019/07)
个人情况 2017年毕业,普通本科,计算机科学与技术专业,毕业后在一个二三线小城市从事Java开发,2年Java开发经验.做过分布式开发,没有高并发的处理经验,平时做To G的项目居多.写下面经是希望 ...
- java 基础知识(三)
Arraylist与Vector的区别 清浅池塘 程序员,专栏:Java那些事儿唯一作者,咨询前请先点详细资料 162 人赞同了该文章 这几天工作有点忙,有很多代码需要写,更新文章有点慢,说声抱歉 ...
- Java面试知识1
JAVA面试题集 基础知识: 1.C++或Java中的异常处理机制的简单原理和应用. 当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常.违反语义规则包括2 ...
- java面试宝典第三弹
Http和Https的区别 超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之 ...
- java面试知识迷你版
java基础JUC.AQSJVM类加载过程mybatisSpringspringboot设计模式数据库redis网络问题认证授权Nginxlinux其他lombok消息队列ES缓存分库分表设计高并发系 ...
- Java基础知识(三)
一.hashCode 与 equals (重要) 面试官可能会问你:"你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?" 1 ...
随机推荐
- headers的描述
Cache-Control 作用: 这个是非常重要的规则. 这个用来指定Response-Request遵循的缓存机制.各个指令含义如下 Cache-Control:Public 可以被任何缓存所 ...
- 移动端调试和fiddler移动端抓包使用
这里介绍一款移动端的调试工具以及抓包工具fiddler的使用.也是初次接触,算是初次接触的总结. 1,移动端调试工具.手机截图如下 代码实现 <!DOCTYPE html> <htm ...
- Jenkins系列-Jenkins构建触发器
触发器说明 build whenever a snapshot dependency is built,当job依赖的快照版本被build时,执行本job. 触发远程构建 (例如,使用脚本):这里使用 ...
- Jenkins系列-Jenkins介绍与部署
Jenkins是什么? Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测 ...
- 重要的几个按键Tab Ctrl+c Ctrl+d
1.Tab按键具有命令补齐和档案补齐的功能,重点是可以避免我们打错命令或者文件名,但是Tab按键在不同的地方输入会有不同的结果 试着多按几下,或者连按两次相信你会发现新大陆 a.Tab接在一串指令的第 ...
- parse_str — 将字符串解析成多个变量
$arr2="first=value1&second=value2&third[]=value3&third[]=value4"; parse_str($a ...
- php裁剪图片(支持定点裁剪)
/** * 图片裁剪函数,支持指定定点裁剪和方位裁剪两种裁剪模式 * @param <string> $src_file 原图片路径 * @param <int> $new_w ...
- java-自定义标签&&JSTL标签库详解
自定义标签是Jav aWeb的一部分非常重要的核心功能,我们之前就说过,JSP规范说的很清楚,就是Jsp页面中禁止编写一行Java代码,就是最好不要有Java脚本片段,下面就来看一下自定义标签的简介: ...
- 【C/C++语法外功】类的静态成员理解
例1 孙鑫視頻學習 Oct.27th 2009 Skyseraph 例子1.0 #include "iostream" class Point { public: void ...
- 【bzoj1231】[Usaco2008 Nov]mixup2 混乱的奶牛 状态压缩dp
题目描述 混乱的奶牛[Don Piele, 2007]Farmer John的N(4 <= N <= 16)头奶牛中的每一头都有一个唯一的编号S_i (1 <= S_i <= ...