JAVA开发面试笔记(三)

========================
js中两个变量能直接比较大小吗?
js中var定义的变量是字符串,如果两个变量直接比较大小是会有问题的,应该先转换成int比较,
比如21 和3 比较 如果没有经过转换则会认为3大,
 if(parseInt(num2)>parseInt(num1))  {}//正确
if(num2>num1){}//错误
========================
请简单介绍设计模式
单例模式可以确保一个类只有一个实例,利用getInstance 方法;
工厂模式提供创建对象接口,简单工厂模式由工厂类角色,抽象工厂角色和具体工厂角色。工厂类角色是核心类
========================
介绍synchronized关键字原理
加上synchronized后的方法,当有一个线程访问该方法时,其他的线程则必须等待
========================
你的系统如何分配和管理权限
可以利用数据库查询当前用户的权限,决定当前菜单是否展示
三个表 操作员表 t_cmm_oper 操作员角色表t_cmm_operrole(权限是以角色为单位的,比如风控角色权限,财务角色权限),具体的权限表 t_cmm_funcrole
t_cmm_oper 和 t_cmm_operrole 通过操作员号oper_no关联;
t_cmm_operrole 和 t_cmm_funcrole 通过角色号role_id关联。
如果该用户存在对该菜单的权限则展示,如果没有则不展示
========================
面向对象设计方法
该名词 面向对象设计方法 可拆分成 面向对象设计+方法
面向对象设计的方法就是在需求、概要设计基础上,划分对象-》抽象类-》将类组成为层次化结构
(继承)-》用类与实例进行设计和实现几个阶段。
========================
介绍异常处理机制
关键字 try catch finally throw throws
异常总共有两种 : ERROR 和 Exception 这两个类继承自Throwable
ERROR 一般是虚拟机相关问题
Exception 包含运行时异常RuntimeException 和非运行时异常non-RuntimeException,
比如说数组下标越界,类找不到异常 ClassNotFoundException,强制类型转换错误,空指针异常。
========================
concurrent包 了解吗 -----该题的回答可能有问题,正确的回答可能是 java.util.concurrent包包含能帮助人们管理相互合作的线程集的类。
java.util.concurrent包分成了三个部分,分别是java.util.concurrent、java.util.concurrent.atomic和java.util.concurrent.lock。内容涵盖了并发集合类、线程池机制、同步互斥机制、线程安全的变量更新工具类、锁等等常用工具。
Executors
Lock
多线程编程中常常要锁定某个对象,之前会用synchronized来实现,现在又多了另一种选择,那就是java.util.concurrent.locks。通过Lock能够实现更灵活的锁定机制,它还提供了很多synchronized所没有的功能,例如尝试获得锁(tryLock())。
 使用Lock时需要自己获得锁并在使用后手动释放,这一点与synchronized有所不同,所以通常Lock的使用方式是这样的:
Lock l = ...;
l.lock();
try {
// 执行操作
} finally {
l.unlock();
}
并发集合类
java.util.concurrent包中提供了几个并发结合类,例如ConcurrentHashMap、ConcurrentLinkedQueue和CopyOnWriteArrayList等等,根据不同的使用场景,开发者可以用它们替换java.util包中的相应集合类。
========================
你设计的时候如何实现接口分离
首先定义一个类 ServiceImp实现所有的方法,然后每个类都有专有的接口类ServiceX
采用的是接口分离原则,这个对每个客户类都有一个专用的接口,这个接口中只声明了与这个客户类相关的方法,而ServiceImp类实现了所有的接口。如果ClientA要改变它所使用的接口中的方法,只需改动ServiceA接口和ServiceImp类即可,ClientB和ClientC类不受影响。如果直接实现ServiceImp,修改clientA 则clientB ,clientC 都要跟着修改
第一幅图是接口分离型,第二幅图是接口未分离型






========================
UML 中类之间有哪些关系?
关联 类似于客户和订单的关系
依赖 依赖是指的类之间的调用关系,类似于自行车和打气筒的关系
聚合 聚合是整体和部分之间的关系,类似于计算机和主板的关系
组合 组合也是整体和部分之间的关系,跟聚合类似,但是组合的各部分不可分割,分割了就没有意义,比如人的头和手,头和手从人上分割下来就没有意义了 。
泛化 泛化就是继承。例如人和学生两个类,学生类是人类的泛化
实现 即一个类实现了一个接口
========================
gc太频繁 如何处理
JVM在进行GC时,内存中存在新生代 Young Generation,老年代Old Generation,永久代 PermGen(jdk1.8已经取消)
新生代包括三个区Eden, From(surviver1) ,To(surviver2)
一个对象首先在Eden中生成,然后传入From,然后To, GC在在新生代中非常频繁。
老年代 一般存放几次GC仍然存活的对象,还有比较大的对象,生命周期比较长的对象。
对象生命周期类比人类的年龄,新创建的对象放入新生代的Eden,老的放入老年代 Old Generation
永久代: 永久代存放类的定义,类的字节码 (jdk1.8已经取消)
gc 太频繁可通过如下处理:扩充内存的heap
========================
hashmap 底层如何实现
hashmap 底层是由哈希表进行插入和删除以及遍历。哈希表 是由数组+链表组成
数组 查询方便,插入删除麻烦; 链表 插入删除方便,查询麻烦 。哈希表则可以查询插入删除都方便
HashMap里面实现一个静态内部类 Entry ,其重要的属性有   key , value, next
// 存储时:
int  hash  =  key.hashCode();  //
int  index  =  hash  %  Entry[].length;
Entry[index]  =  value;
相同index的元素用next连接
========================
如何防止SQL注入
最终方案,参数绑定,preparedstatement 其在预处理阶段已经把SQL编译好,
preparedstatement 底层实现就是把传过来的SQL进行替换 不如#{id} 替换成 ? 最后把各个字符串用append拼接起来
=============================
having和group by区别
group by 用于分组,select中非聚合函数的字段都必须出现在group by 后
having 对条件进行过滤,一般是对分组后的数据进行筛选,且条件可以是组函数
SELECT region, SUM(population), SUM(area) FROM bbc GROUP BY region
SELECT region, SUM(population), SUM(area) FROM bbc GROUP BY region HAVING SUM(area)>1000000

==============================

数据库索引类型
建立索引可以加快检索速度
唯一性索引 建索引字段是唯一性非重复的;
主键索引 建索引列是主键
聚集索引 在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。如字典默认按字母顺序排序,读者如知道某个字的读音可根据字母顺序快速定位
创建索引
CREATE INDEX index_name ON table_name (column_list)
删除索引
DROP INDEX index_name ON table_name
================================
session 和cookies
cookie 客户端浏览器中生成
    Cookie c1= new Cookie("USERNAME",logindto.getUsername());
//从客户端读取硬盘中的cookie文件
     Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++){ //从客户端硬盘中读取你当前点击的
//页面的cookie
                 if ("USERNAME".equalsIgnoreCase(cookies[i].getName())){
                   username = cookies[i].getValue();
               }
session 服务器端生成
session机制是一种服务器端的机制
程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否包含了一个session标识-称为session id,如果已经包含一个session id则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,
String sessionId=request.getSession().getId();
首先要获得request对象,然后调用getSession()方法。
================================
mybatis #$ $为什么不能防止SQL注入
mybatis 是个半自动化持久层框架,SQL都要手动编写,所以要防止SQL注入
#{id} 底层会调用 PreparedStatement,PreparedStatement 是预编译,我们在调用该SQL进行查询的时候已经语句编译好了,mybatis会把 #{id} 编译为 一个问号?,后续程序再对该问号进行赋值;
而对于${id},我们在调用该SQL进行查询的时候语句还没有编译好,是在预编译的时候赋值,比如为5,则直接把${id} 转换为5,然后拼成一个完整的SQL,如果#{id} 也可以赋值为表的其他字段的字段名,比如name,然后拼成一个完整的SQL,这样就是SQL注入,程序出现BUG。但是程序涉及到动态表名列名时,只能用$,但是其他情况能尽量用#就不用$
================================
函数闭包
函数内在包含子函数,并return子函数
函数闭包的功能是实现数据缓存,子函数可以直接使用访问闭包函数定义的变量。
闭包函数常见的一种用途就是,我们可以通过此实现计数功能。
实现封装 子函数可以访问的局部变量,其他函数无法访问。
================================
定时服务如何配置
Timer myTimer = new Timer();  
        myTimer.schedule(new Worker(), 1000);//1秒后执行  
Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的
ScheduledThreadExecutor只支持相对时间
每天晚上23:59对系统一天的订单进行批处理
ScheduledThreadExecutor是一个接口,总共有四个方法
/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/
package java.util.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public interface ScheduledExecutorService extends ExecutorService {
ScheduledFuture<?> schedule(Runnable arg0, long arg1, TimeUnit arg3);

<V> ScheduledFuture<V> schedule(Callable<V> arg0, long arg1, TimeUnit arg3);

ScheduledFuture<?> scheduleAtFixedRate(Runnable arg0, long arg1, long arg3, TimeUnit arg5);

ScheduledFuture<?> scheduleWithFixedDelay(Runnable arg0, long arg1, long arg3, TimeUnit arg5);
}

周期定时执行某个任务。

有时候我们希望一个任务被安排在凌晨3点(访问较少时)周期性的执行一个比较耗费资源的任务,可以使用下面方法设定每天在固定时间执行一次任务。

package test;


import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
import com.sun.org.apache.xerces.internal.impl.xpath.regex.ParseException;
/** 
 * 每天晚上8点执行一次 ,输出语句 测试定时 ,而对于该定时程序会一直运行
 * 每天定时安排任务进行执行 
 * @throws java.text.ParseException 
 */  

public class test2  {
	public static void main(String[] args) {
		test2 tt=new test2();
		try {
			tt.executeEightAtNightPerDay();
		} catch (java.text.ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/** 
	 * 每天晚上8点执行一次 
	 * 每天定时安排任务进行执行 
	 * 四个参数分别为 Runnable线程,当天的起始时间,间隔时间,时间单位
	 * initDelay时间可以随时修改来进行测试
	 * @throws java.text.ParseException 
	 */  
	public static void executeEightAtNightPerDay() throws java.text.ParseException {  
	    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);  
	    long oneDay = 24 * 60 * 60 * 1000;  
	    long initDelay  = getTimeMillis("20:00:00") - System.currentTimeMillis();  
	    initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;  
	  
	    executor.scheduleAtFixedRate(  
	            new ThreadTest1(),  
	            initDelay,  
	            oneDay,  
	            TimeUnit.MILLISECONDS);  
	}  
	
	/** 
	 * 获取指定时间对应的毫秒数 
	 * @param time "HH:mm:ss" 
	 * @return 
	 * @throws java.text.ParseException 
	 */  
	private static long getTimeMillis(String time) throws java.text.ParseException {  
	    try {  
	        DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");  
	        DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");  
	        Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time);  
	        return curDate.getTime();  
	    } catch (ParseException e) {  
	        e.printStackTrace();  
	    }  
	    return 0;  
	} 
}
class ThreadTest1 implements Runnable{   
    //定义ThreadTest1的同步方法  
	//定时在规定的时间点,输入语句 测试定时 
    public synchronized void run(){//重写Runnable接口的run(),并声明成synchronized  
    	System.out.println("测试定时");
    }
    
}

========================

单例模式 分为饿汉式和懒汉式
========================
单例多例模式区别
1. 什么是单例多例;
2. 如何产生单例多例;
3. 为什么要用单例多例
4. 什么时候用单例,什么时候用多例;
1. 什么是单例多例:
所谓单例就是所有的请求都用一个对象来处理,比如我们常用的service和dao层的对象通常都是单例的,而多例则指每个请求用一个新的对象来处理,比如action; 
2. 如何产生单例多例:
    在通用的SSH中,单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添加scope="prototype"; 
3. 为什么用单例多例:
    之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;
   之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
    用单例和多例的标准只有一个:
    当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;
4. 何时用单例?何时用多例?
    对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
  而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;
   另外要说一下,并不是说service或dao一定是单例,标准同第3点所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;
5. 多例模式如何创建对象
一个有上限的多例类可以使用静态变量存储所有的实例,特别是在实例数目不多的时候,可以使用一个个静态变量存储一个个的实例  private static Die die1,die2;  
在数目较多的时候,就需要使用静态聚集来存储这些实例
========================
JVM机制
JVM包含 类加载子系统,运行数据区,执行引擎 三部分
类加载器子系统 Java类的加载,链接,初始化。在java类加载时,而非编译时。
加载 是按规定好的文件路径顺序加载jar包,加载类
链接 对前面一步加载生成的字节码文件是否正确
初始化 静态变量赋予原始值,并且执行静态代码块
运行数据区
运行数据区分为5个组件:方法区,堆区域,栈区域,PC寄存器,本地方法堆栈
方法区:类级别的数据存储在这里 。方法区里存的都是类型信息,也就是类的信息,而类的信息 又包括以下内容: 类的全限定名(类的全路径名) 
    类的直接超类的全限定名(如果这个类是Object,则它没有超类) 
    这个类是类型(类)还是接口 
     类的访问修饰符,如public、abstract、final等 
     所有的直接接口全限定名的有序列表(假如它实现了多个接口)
     字段、方法信息、类变量信息(静态变量)   
装载该类的装载器的引用(classLoader)、
类型引用(class)

堆区域: 所有对象及其对应的实例变量和数组将存储在这里
             常量池(常量池在jdk1.7中迁移到了堆中)
栈区域: 对于每个线程都将新创建一个栈,对于每个方法的调用,将在堆栈存储器中产生一个条目,称为堆栈帧。所有局部变量将在栈内存中创建。
JVM中只有一个方法区,一个堆区域,是共享资源。方法区是线程安全的,堆区域是线程非安全的。

类加载的详细过程

类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。

其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。

1、加载

简单的说,类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例(Java虚拟机规范并没有明确要求一定要存储在堆区中,只是hotspot选择将Class对戏那个存储在方法区中),这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。

2、链接
链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,经由验证、准备和解析三个阶段。
1)、验证
验证类数据信息是否符合JVM规范,是否是一个有效的字节码文件,验证内容涵盖了类数据信息的格式验证、语义分析、操作验证等。
格式验证:验证是否符合class文件规范
语义验证:检查一个被标记为final的类型是否包含子类;检查一个类中的final方法视频被子类进行重写;确保父类和子类之间没有不兼容的一些方法声明(比如方法签名相同,但方法的返回值不同)
操作验证:在操作数栈中的数据必须进行正确的操作,对常量池中的各种符号引用执行验证(通常在解析阶段执行,检查是否通过富豪引用中描述的全限定名定位到指定类型上,以及类成员信息的访问修饰符是否允许访问等)
2)、准备
为类中的所有静态变量分配内存空间,并为其设置一个初始值(由于还没有产生对象,实例变量不在此操作范围内)
被final修饰的静态变量,会直接赋予原值;类字段的字段属性表中存在ConstantValue属性,则在准备阶段,其值就是ConstantValue的值
3)、解析
将常量池中的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法),这个可以在初始化之后再执行。
可以认为是一些静态绑定的会被解析,动态绑定则只会在运行是进行解析;静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写)
3、初始化
将一个类中所有被static关键字标识的代码统一执行一遍,如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。
所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是<clinit>方法,即类/接口初始化方法。该方法的作用就是初始化一个中的变量,使用用户指定的值覆盖之前在准备阶段里设定的初始值。任何invoke之类的字节码都无法调用<clinit>方法,因为该方法只能在类加载的过程中由JVM调用。
如果父类还没有被初始化,那么优先对父类初始化,但在<clinit>方法内部不会显示调用父类的<clinit>方法,由JVM负责保证一个类的<clinit>方法执行之前,它的父类<clinit>方法已经被执行。
JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。


https://www.cnblogs.com/xiaoxian1369/p/5498817.html


==============================

用户登录 :服务器把user对象信息放入session,创建完session后,会把session的ID号以cookie的形式回写给客户机。
一般在登录是应用 比如登录输入了用户名和密码
TSecurityUser user = new TSecurityUser();
user.setUserName('hyw');
user.setUserPwd('008');
HttpSession session=request.getSession();
session.setAttribute("user",user);  //把登录的信息存到session里面 这才有了你的那些代码来接受
服务器创建session出来后,会把session的id号,以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session id过来了,就会使用内存中与之对应的session为之服务。
1 //获取session的Id
2 String sessionId = session.getId();
3 //将session的Id存储到名字为JSESSIONID的cookie中
4 Cookie cookie = new Cookie("JSESSIONID", sessionId);
5 //设置cookie的有效路径
6 cookie.setPath(request.getContextPath());
7 response.addCookie(cookie);

后台调用session时
后台java里面是这样调用的
HttpSession session=request.getSession();
TSecurityUser user=(TSecurityUser)session.getAttribute("user");

===================================
左连接如何调优

on与where的执行顺序,在使用Left (right) join的时候,一定要在先给出尽可能多的匹配on满足条件,减少Where的执行。where比on耗时多

===================================
Redis保存的数据格式
String,List,Hash,Set,ZSet

===================================

RESTful到底是什么?

REST并没有一个明确的标准,而更像是一种设计的风格。REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。

RESTful 和 ajax的区别   
 ---restful是一种风格,符合约束条件和原则的应用程序或设计就是RESTful, ajax其实也是RESTful风格的一种实现   






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值