【上海】φ笔试题
Jdk是Java语言软件开发工具包,其中就包含了jre
JRE是运行环境,包含JVM标作实现及Java核心类库
JVM是Java的虚拟机,它是一个虚构出来的一个计算机
基本数据类型:
整数类型:int long short byte
布尔类型:boolean
字符类型:char
单精度型:float
双精度型:double
引用数据类型:
首先知道 String 是引用类型不是基本类型,引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。引用类型包括类、接口、数组等。String 类还是 final 修饰的。
不可以,static环境中的代码在jvm一启动就跟着开始加载 所以 非static变量还没有进行加载完毕,所以非静态变量不能访问。
Overriding:为覆盖,用于继承父类或者接口标记的方法
Overloading:重载,用于在一个类中有同样的方法名,但是方法参数不同。
Interface:接口,当中的方法不能有方法体,只能被实现类实现implement。
Abstract:抽象类,被继承,当中并非所有的方法都是抽象的那些只有被abstract实现的方法才是抽象的子类必须实现,没有就必须定义方法体。
List: 基于数组底层索引进行排序,可添加重复元素。
list接口所有实现类中常用的有 ArrayList ,linkedlist 和 vector。
最受欢迎的是ArrayList(底层是数组结构,元素是按照存储顺序给,0,1,2,3,4,5····下标,查询快,但是当在元素中删除或增加元素时,下标也会随之改变 例如当2元素被删除是,后面的元素会顶替上来元素3下标变为2,以此类推,牵一发二动全身,故而增删慢)。线程不安全,效率高。
linkedlist为双向链表结构,也可当作堆栈、队列、双端队列,更倾向于集合的增加和删除元素,元素的增删不会引起元素索引的改变,索引固定,故而更利于元素的增删。线程不安全,效率高。
vector:底层同样为数组结构,查询快,增删慢。线程安全,效率低。
Set: 无序对象存储,不能添加重复元素,只能有一个null元素
set接口的实现类中常用的有hashset linkedhashset 和 treeset。
hashset其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。
不仅不能保证元素插入的顺序,而且在元素在以后的顺序中也可能变化(这是由于HashSet是按HashCode存储对象(元素)决定的,对象变化则可能导致HashCode变化)
LinkedHashSet是HashSet的一个子类,LinkedHashSet也根据HashCode的值来决定元素的存储位置,但同时它还用一个链表来维护元素的插入顺序,插入的时候即要计算hashCode又要维护链表,而遍历的时候只需要按链表来访问元素。
TreeSet实现了SortedSet接口,顾名思义这是一种排序的Set集合,查看jdk源码发现底层是用TreeMap实现的,本质上是一个红黑树原理。 正因为它是排序了的,所以相对HashSet来说,TreeSet提供了一些额外的按排序位置访问元素的方法,例如first(), last(), lower(), higher(), subSet(), headSet(), tailSet()。存储的类型必须一致,不能一下int ,一下又存String。
TreeSet的排序分两种类型,一种是自然排序(按照a,b,c,···;0,1,2,3···这样的排序),另一种是定制排序。
Map: 是一个键值对存储元素的集合
map集合提供了一种(key,value)映射的存储形式,每一个key对应一个value,key是唯一的,value可以重复。
主要实现类有hashmap ,linkedhashmap ,treemap。
Hashmap:当中可以存储null元素,键不能一样值可以一样, key和value可以为null,但是它线程不安全
hashTable:当中是线程安全的,key和value都不能null
Vector和ArrayList的相同点:
1.都是容量大小动态可变的数组。
2.都可以快速随机的内部元素进行访问。
### 1.Vector是线程安全的,ArrayList不是。
线程安全意味着一个时间点只有一个线程可以对这个对象进行操作,
Vector之所以是线程安全的是因为它所有的方法都加了synchronized关键字。
2.性能。因为Vector的线程安全所以它较之于ArrayList会相对慢,假设我们有两个线程同时访问Vector的对象的某个方法,其中一个要等另外一个处理完释放掉锁,才能进入,而ArrayList则没有这方面的限制,两个线程可以同时对一个方法进行访问。
3.自增长的方式.Vector默认的正常一般数组的长度,而ArrayList默认是50%,ArraryList默认长度是10,当超出它的长度范围,会创建一个新的数组,同时将旧数组的全部内容copy到新的数组上面。
4.在Vector里面有个方法可以对其增长的大小进行设定
5.Vector是唯一一个既有Enumeration,又有Iterator进行遍历的类,而ArrayList只有Iterator.
9.线程的实现方式
四种创建线程方式: Thread创建线程本质上是实现了Runnable
Public class myThread extends Thread {
Public void run (){
// 实现Thread覆盖方法
System.out.println(“myThread.run()”)
}
Psvm:{
myThread m1 = new myThread();
myThread m2 = new myThread();
m1.start();
m2.start();
}
}
概述:如果自己的类已经继承了其它的类,那么可以使用接口来进行创建线程
public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println("MyThread.run()");
}
Psvm:{
// 启动mythread线程需要实例化一个thread并传入自己的mytread实例
MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start();}
}
事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),
public void run() { if (target != null) { target.run(); } }\3. 实现Callable接口通过FutureTask包装器来创建Thread线程 不常用
public interface Callable<V> { // 接口 V call() throws Exception; }// callable类
public class SomeCallable<V> extends OtherClass implements Callable<V> { @Override public V call() throws Exception { // TODO Auto-generated method stub return null; } Psvm:{ // 创建实例 Callable<V> oneCallable = new SomeCallable<V>(); //由Callable<Integer>创建一个FutureTask<Integer>对象: FutureTask<V> oneTask = new FutureTask<V>(oneCallable); //注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。 //由FutureTask<Integer>创建一个Thread对象: Thread oneThread = new Thread(oneTask); oneThread.start(); //至此,一个线程就创建完成了。 } }
GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
Hibernate是全自动化的数据访问,不需要写任何的sql语句。
Mybatis是半自动化的sql与Java代码分离单独提出使用XML进行引用。
final 关键字的修饰特点:
Ø 修饰类,类不能被继承
Ø 修饰方法,那么这个方法不能被重写
Ø 修饰变量,变量就变成了常量,只能被赋值一次
Finally 关键字的特点:
Ø 与try进行搭配用于异常捕获完毕后,都会执行的代码块
Finalize 关键字的特点:
Ø 释放资源(GC进行垃圾回收)
Ø finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的
Public void reversalStr(String s){
If(s.length <= 1 || null == s){
Return s
}
Return reversalStr(s.substring(1)) + s.charAt(0);
}
14.手写冒泡排序
Public String solt (){
Int arr = [1,2,3,5,4,1,2,3,9]
For(int i = 0;i <= arr.length() -1;i++){p
For(int j = 0;j <= arr.length() -i-1;i++){
Int temp = 0;
If(j[j] < j[j+1]){
Temp = j [j];
j[j] = j[j+1];
j[j+1] = temp;
}
}
}
}
restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
spring是一个开源框架 spring为简化企业级应用开发而生,使用spring可以实现简单的Javabean实现,以前只有EJB才能实现这个功能 Spring是一个IOC(DI)和AOP容器框架
答: 10
解答: 参数传递switch进行条件判断,直接跳入为2 的代码块当中 执行出来 第一次 result : 4,
switch机制没有break; 就不会停止循环,那么进入3代码块当中 进行 第二次 result : 6
最终 总记录数 10
@RequestMapper:用于标识http请求与controller之间的映射
@Authowired: 用于IOC当中获取对象,依赖注入
一句话回答:
Spring内部提供了事务,一个是编程式,一个是声明式,
编程式代码和程序代码在一起不好,声明式只需要在类上添加一个注解即可。(基于注解的@Transactional开启声明式事务管理)
标准回答:
(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。 (2)基于 TransactionProxyFactoryBean的声明式事务管理 (3)基于 @Transactional 的声明式事务管理 (4)基于Aspectj AOP配置事务
SpirngBoot的核心配置文件有application和Bootstrap配置文件。
application文件主要用于Springboot自动化配置文件。 bootstarp文件主要有以下几种用途:
使用Spring Cloud Config注册中心时 需要在bootStarp配置文件中添加链接到配置中心的配置属性来加载外部配置中心的配置信息。一些固定的不能被覆盖的属性一些加密/解密的场景.properties 和 .yml .yml采取的是缩进的格式 不支持@PeopertySource注解导入配置
1.内连接,显示两个表中有联系的所有数据; 2.左链接,以左表为参照,显示所有数据,左表没有关联的数据为null; 3.右链接,以右表为参照显示右表数据,左表没有关联的数据为null;
描述:
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击描述:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:
设置热点数据永远不过期。加互斥锁,互斥锁参考代码如下:说明:
1)缓存中有数据,直接走上述代码13行后就返回结果了
2)缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待100ms,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。
3)当然这是简化处理,理论上如果能根据key值加锁就更好了,就是线程A从数据库取key1的数据并不妨碍线程B取key2的数据,上面代码明显做不到这点。
描述:
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。设置热点数据永远不过期。一句话:
shynchroized 主要用于某一时刻锁对象被一个线程占用, 对共享资源限制抢夺。
Lock 主要用于锁定某一个值,保证在程序运行过程中,不给改变。
类别synchronizedLock存在层次Java的关键字,在jvm层面上是一个类锁的释放1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁在finally中必须释放锁,不然容易造成线程死锁锁的获取假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待分情况而定,Lock有多个锁获取的方式,具体下面会说道,大致就是可以尝试获得锁,线程可以不用一直等待锁状态无法判断可以判断锁类型可重入 不可中断 非公平可重入 可判断 可公平(两者皆可)性能少量同步大量同步请求头 、请求行、请求体
GET一般用于请求获取数据的,不适用传递敏感信息。
POST 是安全的数据放在请求报文当中。传递参数是可以限制的。
GET产生一个TCP数据包;POST产生两个TCP数据包
public : 同一模块下可以访问。
private:同一类当中可以访问。
protected:同一包中可以访问。
default:同一包中可以访问。
== :比较对象地址的不同。
equals:比较值的不同。
答:-1
普通类和抽象类的区别
抽象类不能实例化的,普通类可以。
抽象类可以使用final修饰吗
不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。
抽象类必须要用抽象方法吗
不需要,抽象类不一定非要有抽象方法;但是包含一个抽象方法的类一定是抽象类。
select name,sum(score) from stuscore group by name ORDER BY score asc
select subject,count(score >= 80) from stuscore group by subject
avg 平均值
sum 求和
max 最大值
min 最小值
count 计算总量
请查询出比公司名company1公司任何员工工资都高的员工名称
思路:先查询出该公司的最大工资,在进行子查询判断即可
select employee-namefrom works where company-name = 'company1'
and salary = (select max(salary) from works)
查询ID为偶数的所有数据: mod
select * from student where mod(id,2) = 0;