一些准备资料
hava中数组左边不能有数值。
wait会陷入等待,但释放锁。sleep不会释放锁。notifyALL唤醒其他类,但不会释放锁。
main方法new的话会先静态代码块(父子类)再构造器(父子类)。但如果类里有new的类,会先这个类的构造器,即类的模板比main方法先。
所谓 volatile的措施,就是
1. 每次从内存中取值,不从缓存中什么的拿值。这就保证了用 volatile修饰的共享变量,每次的更新对于其他线程都是可见的。
2. volatile保证了其他线程的立即可见性,就没有保证原子性。
3.由于有些时候对 volatile的操作,不会被保存,说明不会造成阻塞。
不可用与多线程环境下的计数器!!会迅速被其他线程改。
技术面基本围绕简历上的项目来讲
技术面:Spring mvc的工作流程,介绍一下你的项目,MySQL的分页查询,有没了解Spring boot,挑一个Mybatis里你熟悉的类讲。
1.Spring mvc的工作流程
重点来了,工作流程就是这样的:
网友总结:(能大概记住就好)
- 用户发起请求到前端控制器(DispatcherServlet),该控制器会过滤出哪些请求可以访问Servlet、哪些不能访问。就是url-pattern的作用,并且会加载springmvc.xml配置文件。
- 前端控制器会找到处理器映射器(HandlerMapping),通过HandlerMapping完成url到controller映射的组件,简单来说,就是将在springmvc.xml中配置的或者注解的url与对应的处理类找到并进行存储,用map<url,handler>这样的方式来存储。
- HandlerMapping有了映射关系,并且找到url对应的处理器,HandlerMapping就会将其处理器(Handler)返回,在返回前,会加上很多拦截器。
- DispatcherServlet拿到Handler后,找到HandlerAdapter(处理器适配器),通过它来访问处理器,并执行处理器。
- 执行处理器
- 处理器会返回一个ModelAndView对象给HandlerAdapter
- 通过HandlerAdapter将ModelAndView对象返回给前端控制器(DispatcherServlet)
- 前端控制器请求视图解析器(ViewResolver)去进行视图解析,根据逻辑视图名解析成真正的视图(jsp),其实就是将ModelAndView对象中存放视图的名称进行查找,找到对应的页面形成视图对象
- 返回视图对象到前端控制器。
- 视图渲染,就是将ModelAndView对象中的数据放到request域中,用来让页面加载数据的。
- 通过第8步,通过名称找到了对应的页面,通过第10步,request域中有了所需要的数据,那么就能够进行视图渲染了。最后将其返回即可。
2.MySQL的分页查询
我觉得应该是这个
1)limit语句的查询时间与起始记录的位置成正比(所以查询后面的比如第200000条数据就不合适了)
2)mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用。
2. 对limit分页问题的性能优化方法
利用表的覆盖索引来加速分页查询
我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。
在我们的例子中,我们知道id字段是主键,自然就包含了默认的主键索引。现在让我们看看利用覆盖索引的查询效果如何:
这次我们之间查询最后一页的数据(利用覆盖索引,只包含id列),如下:
select id from product limit 866613, 20 0.2秒
相对于查询了所有列的37.44秒,提升了大概100多倍的速度
那么如果我们也要查询所有列,有两种方法,一种是id>=的形式,另一种就是利用join,看下实际情况:
叫做子查询法
先用主键索引id找出第一条数据,然后大于等于这条数据id的就是要获取的数据
SELECT * FROM product WHERE ID > = (select id from product limit 866613, 1) limit 20
查询时间为0.2秒,简直是一个质的飞跃啊,哈哈
另一种写法 内连接
SELECT * FROM product a JOIN (select id from product limit 866613, 20) b ON a.ID = b.id
查询时间也很短,赞!
3.了解Spring boot
4、测试SpringBoot引入成功与否
App.java中添加@EnableAutoConfiguration注解
main方法中添加SpringApplication.run(App.class,args);通过run方法启动了,tomcat都不需要部署,内嵌了
Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar 命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类。
跨域请求错误,只需要在UserController类上加一个注解@CrossOrigin
即可
4.挑一个Mybatis里你熟悉的类讲
xml写mapper时,一对一时在Mapper里使用 assocation 标签实现查询的立即加载,一对多时使用 Collection 实现延迟加载
用注解的话就是 比如一对一立即加载如下:
@Result(property = "user",column = "uid",one=@One(select="com.xxw.dao.IUserDao.findById",fetchType= FetchType.EAGER))
Mybatis中的一级缓存和二级缓存
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。
当SqlSession对象消失时 sqlsession.close或.cleancache,mybatis的一级缓存也就消失了。数据库有commit也会消失。
不管xml还是注解,一级缓存都是自动开启的。
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
在持久层接口中使用注解配置二级缓存
开二级缓存 这个要写!!!!!!
@CacheNamespace(blocking=true) //mybatis 基于注解方式实现配置二级缓存
则之后同一工厂创建的session查询相同数据时直接从缓存里拿不用再去数据库拿了。
这里还没有service层controller层所以都是在测试类执行操作
执行操作时用到三种模式!!!!
二轮笔试就比较开放式,四道问答题,问了一些web请求的流程(这个就类似前面MVC工作流程答吧),Java容器的一些知识(之前的博客复习过),还有两题记不太清楚了,难度也不是特别难,也能答得上两句话,同样30mim。
过程
第一轮面试是HR面,问了一些简历上的情况(虽说是视频面试,但当时感觉面试官穿的也比较正式,幸亏自己也穿了一件白色衬衫),还问了一些未来的发展方向,感觉问的比较杂吧,所以自己也是放开来讲。
Java中对哪方面比较熟悉?(大概说了一些Java比较重要的点吧,也没有深入去展开,然后就下一个问题了)
关于List的一些特性?(其实也不是很清楚问题是啥,就大概讲了一下ArrayList和LinkedList以及实现原理)
插入元素用什么数据结构比较好?链表吧 头插法,尾插法
关于简历上一些微信小程序项目和Android项目的问题?
5.关于spring框架
5.1介绍一下spring
Spring是分层的java企业级应用 full-stack (全栈)轻量级开源框架,以 IoC(Inverse Of Control: 反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库
spring有七大主要的模块
1. spring core: 核心类库,提供ioc服务
2. spring context: 提供框架式的bean的访问方法,以及企业级的功能
3. spring aop: 提供aop
4. spring dao: 提供jdbc的抽象支持
5. spring orm: 提供对象/映射 api的支持
6. spring web: spring提供了基本web的综合特性,例如多文件的上传
7. spring mvc: spring 提供了model view controller 的实现
5.2 spring IOC、依赖注入、AOP
-
IOC控制反转
1. IOC主要实现对对象的生成、控制和管理生命周期,对象的装配和配置。简单的来说就是对象的控制权由容器来决定
2. 优点:解耦,有利于功能的复用
3. 特点:利用了反射机制
- 依赖注入DI
1. 依赖注入是控制反转的一种体现,通过控制反转,由一个容器将对象的实体和所依赖的对象的引用传递给他(将容器内的引用传递给外部的实体)
2. 注入的方法:(三种)接口注入、setter注入、构造器注入。setter注入和构造器注入的区别,构造器传参强制注入
* 解耦的思路:(根据下面注册驱动1和2对比) * 第一步:使用反射来创建对象,而避免使用new关键字。!!!! * 第二步:通过读取配置文件来获取反射需要的 要创建的对象全限定类名!!!!!!!!
Class.forName(getProperty(key));
就像工厂模式把创建对象的控制权力交给工厂,IOC(Inversion of Control)就是把创建对象的权利交给框架,是框架的重要特征。它包括依赖注入和依赖查找。
作用就是削减计算机程序的耦合(解除耦合)
bean.xml
<!--把对象的创建交给spring来管理-->!!!! 存住全类名,所以应该也是基于反射,给一个id名。 <bean id="accountService" class="com.xxw.service.impl.AccountServiceImpl"></bean>
@Test //如果换成spring整合的junit就可以用注解代替下面两行 直接执行方法 public void testFindAll() { //1.获取容器 spring的核心容器对象 // ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");不能再用了 bena.xml都没了 ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); //2.得到业务层对象 IAccountService as = ac.getBean("accountService",IAccountService.class); //3.执行方法 List<Account> accounts = as.findAllAccount(); for(Account account : accounts){ System.out.println(account); } }
/** * 帐户的业务层实现类 * 曾经XML的配置: * <bean id="accountService" class="com.xxw.service.impl.AccountServiceImpl"> * scope="" init-method="" destroy-method=""> * <property name="" value="" | ref=""></property> * </bean> * 昨天围绕bean的xml配置讲了上面4个功能标签类 所以今天的注解要分为这4类!! * 1.用于创建对象的 * 他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的 * @Component: * 作用:用于把当前类对象存入spring容器中 * 属性: * value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。 * Controller:一般用在表现层 * Service:一般用在业务层 * Repository:一般用在持久层 * 以上三个注解他们的作用和属性与Component是一模一样!!!! * 他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰 * * 2.用于注入数据的!! * 他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的 * @Autowired: * 作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功 * 如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。 * 如果Ioc容器中有多个类型匹配时: * 出现位置: * 可以是变量上,也可以是方法上!!!!!!!(变量上!!!=new了 * 细节: * 在使用注解注入时,set方法就不是必须的了。 * @Qualifier: * 作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲) * 属性: * value:用于指定注入bean的id。 * @Resource * 作用:直接按照bean的id注入。它可以独立使用 * 属性: * name:用于指定bean的id。 * 以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现!!!!!???用@value!!el传数据!! * 另外,集合类型的注入只能通过XML来实现!!!!!! * * @Value!!!! * 作用:用于注入基本类型和String类型的数据!!! * 属性: * value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式) * SpEL的写法:${表达式} * * 3.用于改变作用范围的 * 他们的作用就和在bean标签中使用scope属性实现的功能是一样的 * @Scope * 作用:用于指定bean的作用范围 * 属性: * value:指定范围的取值。常用取值:singleton prototype * * 4.和生命周期相关 了解 * 他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的 * PreDestroy * 作用:用于指定销毁方法 * PostConstruct * 作用:用于指定初始化方法 */ //@Component//或者指定标识 @Component(value="accountService") @Service public class AccountServiceImpl implements IAccountService { // @Autowired // @Qualifier("accountDao1") @Resource(name = "accountDao1") private IAccountDao accountDao;// = new AccountDaoImpl();//??? public void saveAccount() { accountDao.saveAccount(); } }
- aop 面向切面
1. 对一个方法可以进行前置或者后置的操作,主要用于应用服务逻辑和系统服务的隔离
2. 代理模式:静态代理和动态代理。静态代理的代表为AspectJ;动态代理的代表为spring aop
3. AspectJ 为静态代理的增强,所谓静态代理,就是aop框架在编译阶段生成aop代理类,指的是在编译阶段将aspect织入java字节码中,运行时候增强之后的aop对象
4. spring aop为动态代理,aop不修改字节码,每次运行的时候生成一个aop对象,这个aop对象包含了目标对象的所有方法,并且在特定的切点做了增强处理,并调回对象的方法
复习下来感觉都是重点。。。而且居然忘得差不多了。。。(待做:去看看框架面经上的题
原文 博主有答案
排序稳定性
所谓稳定性是指待排序的序列中有两元素相等,排序之后它们的先后顺序不变.假如为A1,A2.它们的索引分别为1,2.则排序之后A1,A2的索引仍然是1和2.
稳定也可以理解为一切皆在掌握中,元素的位置处在你在控制中.而不稳定算法有时就有点碰运气,随机的成分.当两元素相等时它们的位置在排序后可能仍然相同.但也可能不同.是未可知的. 参考详细说明
稳定性算法: 基数排序 , 直接插入排序 , 冒泡排序, 归并排序
不稳定性算法: 桶排序, 二分插入排序,希尔排序, 快速排序, 简单选择排序,堆排序
hr面:大学的一些课程,问了两遍会不会数据库调优,薪资要求,个人兴趣爱好,舍友的评价,平时生活,来这里多久
技术面:主要是问的是下面的我写的技能方面,而不是项目经历。
linux下用户组、文件权限
我没太看懂,没学过
useradd
1、作用
useradd用来创建用户账号和建立用户起始目录
2、格式
useradd [-d home] [-s shell] [-c comment] [-m [-k template]] [-f inactive] [-e expire ] [-p passwd] [-r] name
usermod
usermod可用来修改用户帐号的各项设定。
语法:usermod [-LU][-c <备注>][-d <登入目录>][-e <有效期限>][-f <缓冲天数>][-g <群组>][-G <群组>][-l <帐号名称>][-s ][-u ][用户帐号]
文件权限
ll操作列出文件列表后可见每个文件前面有一串字符串共10位,我们可分为4部分来理解:
- --- --- --- (1 3 3 3)
第一部分:-表示文件,d表示文件夹,l表示链接
第二部分:当前用户所具有的权限
第三部分:当前组内其他用户所具有的权限
第四部分:其他组的用户所具有的权限
介绍一下spring
spring IOC、依赖注入、AOP
讲述一下ssm中的第二个s
SpringMVC是表现层的框架。
1. MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
2. Model:数据模型,JavaBean的类,用来进行数据封装。
3. View:指JSP、HTML用来展示数据给用户
4. Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等
Collection中的实现类和接口
HashMap(map) 和 Hashtable 的区别
讲述一下快速排序的思路
挖坑填数+分治
该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,从后面开始,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
//快速排序 void quick_sort(int s[], int l, int r) { if (l < r) { //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1 int i = l, j = r, x = s[l]; while (i < j) { while(i < j && s[j] >= x) // 从右向左找第一个小于x的数 j--; if(i < j) s[i++] = s[j]; while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数 i++; if(i < j) s[j--] = s[i]; } s[i] = x; quick_sort(s, l, i - 1); // 递归调用 quick_sort(s, i + 1, r); } }
设计模式
一共有23种:
• 创建型模式:
– 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
• 结构型模式:
– 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
• 行为型模式:
– 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
潦草地A了一下博主说的算法题:求1-1000之间的数位质数对的和,输入: 10 输出:(3+7),(5+5)
public class Test6 { public static void main(String[] args) { test(10); } public static void test(int n){ if(n<1||n>1000) return; for(int i=0;i<n;i++){ if(isRight(i)){ for(int j = n;j>=i;j--){ if(isRight(j)){ if(i+j==n){ System.out.println(i+"+"+j); } } } } } } public static boolean isRight(int i){//判单是否为质数 for(int j=2;j<i-1;j++){ if(i%j==0) return false; } return true; } }
原文 没答案 也太多了吧。。。
关于继承:
public static void main(String[] args) { Personn person=new Teacher();//子类父类构造方法都执行了 person.print();//print被重写了 所以只会执行子类覆盖后的方法 如果没有覆盖就还是父类的方法 //person.printtt(3);这个子类自己新加的方法被父类对象无法执行打不出。。。只能Teacher类对象自己执行 System.out.println("-------------"); Teacher teacher = new Teacher();//还是和上面一样 父类和子类构造方法都执行 teacher.printttt(3);//这样才能打出 teacher.print(); }
java多线程可以通过几种方法创建线程?他们有什么区别?在多线程编程中synchronized关键字有什么用途?
1.继承Thread类型重写run 方法
2.实现Runnable接口
3.实现Callable接口
实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值,前者线程执行体run()方法无返回值,因此可以把这两种方式归为一种这种方式与继承Thread类的方法之间的差别如下:
1、线程只是实现Runnable或实现Callable接口,还可以继承其他类。
2、这种方式下,多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
3、但是编程稍微复杂,如果需要访问当前线程,必须调用Thread.currentThread()方法。
4、继承Thread类的线程类不能再继承其他父类(Java单继承决定)。
Java 中关键字 synchronized 表示只有一个线程可以获取作用对象的锁,执行代码,阻塞其他线程。
作用:
- 确保线程互斥地访问同步代码
- 保证共享变量的修改能够及时可见
- 有效解决重排序问题
用法:
- 修饰普通方法
- 修饰静态方法
- 指定对象,修饰代码块
在Web登录界面输入用户名和密码,并点击“登录”完成登录操作。整个过程中从前台页面到后端服务器,再到数据库等环节,都有哪些操作?请写出能想到的相关的流程和处理的内容。
3.一面(70min)
mybatis的一级缓存和二级缓存
sqlSession sqlSessionFactory
mysql的哪些操作会刷新缓存
清除缓存:reset query cache;
或者使用FLUSH命令:FLUSH [LOCAL | NO_WRITE_TO_BINLOG] flush_option [, flush_option] ...
设计模式中的单例模式和抽象工厂模式
(300集复习一下
java的反射机制
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取字节码文件对象的三种方式。
1、Class clazz1 = Class.forName("全限定类名"); //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
2、Class clazz2 = Person.class; //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
3、Class clazz3 = p.getClass(); //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。
(面试官还问到了一些关于java基础的细节,有点模糊记不太清就不在这里列举了!)
4.技术面(60min)
mysql的三大范式
谈谈你对java的final关键字的理解
final可以修饰变量、方法及类:
当定义一个final变量时,jvm会将其分配到常量池中,程序不可改变其值;(值比地址更死板,static值还是可以被改变的,就是除了类加载时那一次,运行时是不会再动态初始化加载的,而final过的就是最终形态)
当修饰一个方法时,该方法在子类中将不能被重写;
当修饰一个类时,该类不能被继承。
平时有用lombok吗,你评价一下这个插件
lombok 提供了简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 java 代码(比如生成javabean写set,get,tostring方法等等)。通过使用对应的注解,可以在编译源码的时候生成对应的方法,所以不会影响任何运行效率。
自定义注解应该如何实现
新建选项里面一个叫Annotation的类,生成public @interface后通常还需要加两个元注解
– @Target 用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
– @Retention 表示需要在什么级别保存该注释信息,用于描述注解的生命周期
表名tb_student 对应类名 SxtStudent.java /** * 表 * @author wanx * */ @Target(value = ElementType.TYPE)//作用在 表示类跟表之间的转化 @Retention(RetentionPolicy.RUNTIME) public @interface SxtTable { //只有一张表即一个类 String value(); } 设置好对应属性和set,get方法 接下来写注解SxtTable 属性对应列名,类型,长度 写注解SxtFiled 然后可以在SxtStudent.java里面写属性了 /** * 属性 * @author wanx * */ @Target(value = ElementType.FIELD)//作用在成员变量上 @Retention(RetentionPolicy.RUNTIME) public @interface SxtFiled { String columnName(); String type(); int length(); } package com.xxw.test.annotation; @SxtTable(value = "tb_student")//用tb_student对应上了对象? public class SxtStudent { @SxtFiled(columnName = "id", length = 10, type = "int") private int id; @SxtFiled(columnName = "sname", length = 10, type = "varchar") private String studentName; @SxtFiled(columnName = "age", length = 3, type = "int") private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 第3我们还需要写注解解析程序 接下来整一个完整的 新建Demo03.java /** * 使用反射读取注解的信息,模拟处理注解信息的流程 * @author wanx * */ public class Demo03 { public static void main(String[] args) { //首先加载类 try { //是这个clz食饭射来的吗? Class clz = Class.forName("com.xxw.test.annotation.SxtStudent"); //通过class对象得到SxtStudent类的注解 Annotation[] annotations = clz.getAnnotations(); for(Annotation a:annotations) { System.out.println(a);//yxjg:@com.xxw.test.annotation.SxtTable(value=tb_student) //因为类上只有一个注解所以读取到value (属性的没有吗? } //也可以通过名字直接获得类的指定的注解 SxtTable st = (SxtTable)clz.getAnnotation(SxtTable.class); System.out.println(st.value());//yxjg:tb_student //获得类的属性的注解 Field f = clz.getDeclaredField("studentName"); SxtFiled sxtFiled = f.getAnnotation(SxtFiled.class); System.out.println(sxtFiled.columnName()+"--"+sxtFiled.type()+"--"+sxtFiled.length()); //运行结果:sname--varchar--10 //现在我们通过类信息,以及注解,以及主程序(第三方程序)Demo03, //我们读出了指定类的相关注解信息,从而拼出了sq语句 //根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Yxjg: @com.xxw.test.annotation.SxtTable(value=tb_student) tb_student sname--varchar--10
关于用户和角色,你会怎么进行设计(包括数据库表的设计以及实体类的设计)
??
了解docker技术吗?
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中。Docker的出现,为后端开发和运维提供了虚拟化技术,优雅地解决了开发环境和生产环境不一致的问题。
谈谈你对maven的理解
Maven 是一个项目管理工具,能帮你构建工程,管理 jar 包,编译代码,还能帮你自动运行单元测试,打包,生成报表,甚至能帮你部署项目,生成 Web 站 点。
两个重要作用:依赖管理,一键构建。
项目一般的打包方式是什么?jar包和war包的区别是什么?
Java项目一般jar包war包ear包 andriod项目apk打包
war包是Sun提出的一种web应用程序格式,与jar类似,是很多文件的压缩包。war是一个可以直接运行的web模块,通常用于网站,打成包部署到容器中。
以Tomcat来说,将war包放置在其\webapps\目录下,然后启动Tomcat,这个包就会自动解压,就相当于发布了。
jar包:通常是开发时要引用通用类,打成包便于存放管理。所以是有根本区别的,war包一般是开发完成产品发布阶段使用。
ear包:企业级应用,通常是EJB打成ear包(不太了解)。
如果你将一个项目打包成jar包,这个jar包很大,你会从哪方面进行排查导致jar包占用内存大的原因所在
1.可能依赖导入了无用的jar包?可以使用 mvn dependency:analyze
命令对项目进行分析,并以此作为参考来剔除无用依赖
2.打包时排除所有 jar 依赖改为运行时外部引用。在 pom 中 spring-boot-maven-plugin 打包插件设置打包时排除所有 jar 包。
你有部署过项目到远程服务器上吗,通过什么方式进行部署的?
① 打包上传:将项目打包成 war 文件,然后利用 FileZilla 传到远程服务器
② 部署:使用 cp 或 mv 命令,将 war 文件移动到 Tomcat 目录下的 webapps 下
③ 重启 Tomcat,访问我们的项目
Linux的常用命令
谈谈你最熟悉的设计模式,它在JDK源码的体现
工厂模式 (可通过创建方法识别返回抽象/接口类型的实现)
- java.util.Calendar#getInstance()//日历类获取对象
- java.lang.reflect.Constructor#newInstance()//反射获取构造器
- java.lang.Proxy#newProxyInstance()//代理类获取代理对象
单例模式(通过创造性方法识别,每次返回相同的实例(通常是自己))
保证一个类只有一个实例(对象),私有构造方法,只提供一个访问该实例的全局访问点。
- java.lang.Runtime#getRuntime()
- java.lang.System#getSecurityManager()
写接口通过什么工具进行调试
RESTer
还有使用过其它公司的SDK吗?
有
谈谈你对前后端分离的理解
是web应用的一种架构模式。
在开发阶段,前后端工程师约定好数据交互接口,实现并运行开发和测试。在前后端框架中,后端只需要负责按照约定的数据格式向前端提供可通用的API服务即可。前后端之间通过HTTP请求进行交互,前端获取到数据后,进行页面的组装和渲染,最终返回给浏览器。
谈谈你对于restful风格的认识
你认为在今后学习微服务的过程中,可能会遇到什么困难
以下是针对我的仿天猫鞋店商城项目提出的问题
①关于订单编号,是怎么实现的
前8位是当前时间,中间六位为自增序列由squence_info辅助记录,后两位为分库分表位,暂时未实现。
②支付这一块的功能怎么实现
③通过什么技术实现用户认证
通过拿到用户输入的手机号和密码,根据该手机号查到密码和用户输入的密码比对,成功则将登陆凭证加入到用户登录成功的session内
this.httpServletRequest.getSession().setAttribute("IS_LOGIN", true); this.httpServletRequest.getSession().setAttribute("LOGIN_USER", userModel);
1.String和StringBuffer的区别?
可变性:
String 类中使用final关键字修饰字符数组来保存字符串,所以String对象是不可变的。而StringBuilder与StringBuffer都继承自AbstractStringBuilder类,AbstractStringBuilder中也是使用字符数组保存字符串char []value但是没有用final关键字修饰,所以这两种对象都是可变的。
线程安全性:
String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、 indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
性能:
每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。
相同情况下使用StringBuilder好,使用StringBuffer仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。
2.jvm的内存管理是怎样的?(详细的介绍了内存的分区以及作用,刚想讲垃圾收集算法和垃圾的收集器的时候,他说讲的很好了,剩下的也没问题,汗 ̄^ ̄゜)
Java虚拟机的内存大致可以分为三个区域:栈stack、堆heap、方法区method area
栈的特点如下:
1. 栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
3. 栈属于线程私有,不能实现线程间的共享!
4. 栈的存储特性是“先进后出,后进先出”(对于方法们)
5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!
堆的特点如下:
1. 堆用于存储创建好的对象和数组(数组也是对象)
2. JVM只有一个堆,被所有线程共享
3. 堆是一个不连续的内存空间,分配灵活,速度慢!
方法区(又叫静态区)特点如下:
1. JVM只有一个方法区,被所有线程共享!
2. 方法区实际也是堆(方法区在堆里面),只是用于存储类、常量相关的信息!
3. 用来存放程序中永远是不变或唯一的内容。(类信息【Class对象】、静态变量、字符串常量等)
程序执行(加载)一个类的内存变化过程:
首先存这个类的类信息在方法区,包括这个类里面所有双引号引起来的字符串常量都是在编译期放在方法区常量池。
然后调用main方法,则在栈中开辟一个栈帧。然后有new对象,又要开辟一个构造器方法的栈帧,建好对象后方法执行完就销毁该方法的栈帧。
执行构造器完毕后,则在堆中以类为模板新建一个对象,堆中存储好对象,且拥有一个地址,等于号把地址赋给main方法中的局部变量(引用对象变量)而关联起来,接收的关联的属性值们和方法区的常量们。若对象引用别的对象的话,对象的引用变量是接收那个对象的地址。
若类被加载过才能给对象分配内存。类加载过程就是上面的过程图。
类加载还有别的知识点,双亲委派什么的。
类加载后创建对象就是这5步。
堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage Collected Heap).从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代:在细致一点有:Eden空间(新生代)、From Survivor、To Survivor空间等。进一步划分的目的是更好地回收内存,或者更快地分配内存。
垃圾回收机制(Garbage Collection) 就像餐厅擦桌子的服务员
任何一种垃圾回收算法一般要做两件基本事情:
1. 发现无用的对象
2. 回收无用对象占用的内存空间。
垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的就是没有任何变量引用该对象(不可达)。Java的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。
1. 引用计数法
堆中每个对象都有一个引用计数。被引用变量(比如=new之前的变量)引用一次,计数加1. 引用变量值变为null,则计数减1,直到计数为0,则表示变成无用对象。优点是算法简单,缺点是“循环引用的无用对象(对象对对象的引用)”无法别识别。
2. 引用可达法(根搜索算法)
程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。
3.你说你熟悉常用的linux命令,那如何查看内存,如何查看日志,如何查看一个线程的详细信息?(有一个没答出来,好久没写忘了)
3这部分有答案
4.快速排序讲一下思路(快排形式很多,认准基准点来说。)
挖坑填数+分治
5.MySQL的select默认是升序还是降序?
6.你对于新生代的理解。
在 Java 中,堆被划分成两个不同的区域:年轻代 ( Young )、老年代 ( Tenured)。年轻代 ( Young ) 又被划分为三个区域:Eden
、From Survivor
、To Survivor
。 这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。
年轻代的特点是产生大量的死亡对象,并且要是产生连续可用的空间, 所以使用复制清除算法和并行收集器进行垃圾回收.对年轻代的垃圾回收称作初级回收 (minor gc
)
垃圾回收过程:
初级回收将年轻代分为三个区域, 一个新生代 , 2个大小相同的复活代, 应用程序只能使用一个新生代和一个复活代, 当eden满了触发初级垃圾回收的时候,gc挂起程序, 当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 ( 即 from 区域 ),这就经过一次初级回收了,并且将这些对象的年龄设置为1。然后再看eden+toSurvivor区域,以此循环类推,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。当Old区满了,则会触发一个一次完整地垃圾回收(FullGC),Full GC 是发生在老年代的垃圾收集动作,所采用的是标记-清除算法。
我发现java方向的超级大几率问题:
jvm必考,java常用容器类(10个左右),简历写的一定会问到,所以该准备的还是要准备,诚实回答过程中交流一定是氛围很好的
DELETE FROM testgroup; INSERT INTO testgroup VALUES ('小明','语文',1), ('小明','数学',2), ('小明','英语',3), ('大花','语文',4), ('大花','数学',5), ('大花','英语',6); SELECT * FROM testgroup;
把列中数据转成列,用CASE 某列 WHEN ‘该列中数据’ THEN 另一列int值类型的,或者直接指定一个int值(因为sum,max这种只能作用int型) END
SELECT NAME AS '姓名', SUM(CASE SUBJECT WHEN '语文' THEN score END) AS '语文', SUM(CASE SUBJECT WHEN '数学' THEN score END) AS '数学', SUM(CASE SUBJECT WHEN '英语' THEN score END) AS '英语' FROM testgroup GROUP BY NAME;
CASE SUBJECT WHEN '语文' 成功把subject列中的语文转成列了。THEN后面是对应的填充数。
SUM只是做连接用,max,min也可以代替SUM,因为这只对应一个数据(转列的那个数据对应的另一int列的数据)而不是sum math这种一列数据。
瞎折腾版本:
SELECT NAME AS '姓名', (CASE SUBJECT WHEN '语文' THEN '哥哥' END) AS '语文', -- 这里第一行可以不写SUM等聚合函数也能连接 MAX(CASE SUBJECT WHEN '数学' THEN 33 END) AS '数学', SUM(CASE SUBJECT WHEN '数学' THEN score END) AS '英语' FROM testgroup GROUP BY NAME;
SQL的case when then else end语句的用法
再来尝试一下
SELECT NAME,GROUP_CONCAT(DISTINCT(SUBJECT) SEPARATOR ",") AS 'yes' FROM testgroup GROUP BY NAME;
所以这是取相同的列数据们为一列
GROUP_CONCAT(DISTINCT(SUBJECT) SEPARATOR ",")