大学四年也即将要结束了,都说毕业即“失业”,但是不能就这样从命吧。所以自己也在努力的找工作中,写一篇JAVA的面试题,可能当中写的不好,或者出现错误,见谅。话不多说,直接开始正题。(敲黑板)
Java中堆(heap)和栈(stack)的区别?
- 栈的存取速度比较快,仅次于位于CPU的寄存器,缺点是栈中数据大小和生存期必须是确定的,缺乏灵活性。另外,栈的数据是共享的(详见b),而栈的优势是可以动态的分配内存且生存期可以不用告诉编译器,缺点是因为在运行时动态的分配内存,所以存取速度会较慢
- 定义: int a = 3; int b = 3;编译器先在栈中创建一个变量为3的引用。然后查找栈中是否存有3这个数值的地址,如果没有,则开辟一个内存来存放,接着将a引用指向3的地址。接着创建变量b,这个时候栈中已经存在有3这个数值的地址,直接将b指向3。这个就是栈的数据共享。
【该种字面值的引用与类对象的引用不同,就是假如接着将a改为4后,b并不会指向4,而类对象引用的情况则是:当两个类对象同时引用一个对象时,其中一个对象改变了引用对象的内部状态,则另一个对象的引用也立马发生改变】
什么是JAVA反射机制?
概念:在运行状态中,对于任意类,都能够获取到其属性和方法,对于任意对象,都能够调用其属性和方法。这种在运行时动态获取信息以及动态调用对象方法的功能叫JAVA的反射机制。
JAVA获取字节码对象有几种方式?
三种:分别是:静态属性.class、Object类中的getClaa()方法、Class.forName(“类的全路径”)【重点,最常用】
静态属性.classàStudeng studet = new Student(); student.class;
Object类中的getClaa()方法à Studeng studet = new Student(); student.getClass();
Class.forName()方式àStudeng studet = Class.forName(“com.cuc.service.student”);
POST和GET的区别?
- 安全性:GET方式会将信息显示在URL中,地址和参数用?连接,参数与参数之间用&连接;而POST请求是将数据放在Http的body中,地址栏不可见
- 大小限制:根据浏览器的不同,对URL的长度有进行限制,最大长度为2k(2048)
- 历史上:服务器的增/删/改/查方法分别是put/delete/post/get
- 速度上:GET的速度会比POST的更快
- 发送方式:GET是将请求头http head和数据data一并发送出去,服务器响应200(返回数据),POST是先将请求头http head发送,服务器响应100(continu,再发送数据data,服务器响应200(返回数据)
Interface和abstract类的区别?
Inteface(接口):
- 包含有常量(不是变量)和抽象方法
- 常量都是public,final,static(可以省略不写)
- 抽象方法的权限都是public(允许省略public,static)
- 接口可以被继承,一个接口可以通过extends来继承另一个接口
Abstract类(抽象类):
- 抽象类中可以没有抽象方法,抽象方法必须在抽象类中
- 抽象类不能进行实例化,及不能使用new关键字来创建对象
- 抽象方法,只能声明,不能添加final和static关键字进行修饰
什么是AOP(面向切面编程)?
扩展功能时,不修改源代码,将功能代码从业务逻辑代码中分离出来。传统的面向对象编程是采用纵向继承体系重复性代码
AOP底层的实现原理(2种):JDK动态代理,该方式要求对象是实现了接口的类;cglib动态代理则是针对类,没有要求实现接口。
Final,finally,finalize()的区别?
- Final关键字:用于修饰变量为常量,常量一般为大写且需要进行初始化,之后不能被修改,用于修饰方法时,表明该方法不能被重写,为最终方法的意思,在修饰类的时候,表示该类不能够被继承。
- Finally:主要用于异常上,和try…catch一起使用,主要用于关闭连接或清除之类的操作。
- Finalize():该方法主要是在垃圾回收机制(GC)之前进行调用。
Throws,throw和try{}catch{}的区别?
- Throws:用于方法名称后,表示该方法可能抛出某种异常。
- Throw:用于代码块中,当代码执行到这里时,一定抛出某种异常。
- Try{}catch{}:当try里面的代码块出现异常时,会被捕捉到并进入catch中,执行catch里面的代码块。
B/S和C/S的区别?
- B/S:即Browser/Service(浏览器/服务器),用户通过浏览器网页的形式进行访问,用户只需要有浏览器即可,添加新功能时,不需要用户更新,更注重于服务端
- C/S:即Client/Service(客户端/服务器),需要用户下载客户端(例如APP),当有新功能增加时,需要用户进行更新,需注重于客户端和服务的两方面
List和set和Map?
- List可以允许重复对象,而set不允许重复对象,前面两者都是collection的子接口或实现类,Map是一个接口
- List可以插入多个null元素,set只允许最多包含一个null元素,Map允许有随意个null值,但是只允许拥有一个null键
- List是有序的,set是无序的,Map的是键值对的形式,允许有相同的值,但是键只能是唯一的。
- List常用的实现类有ArrayList,LinkedList和Vector。Set常用的实现类有Hashset,LinkedHashSet和ThreeSet。Map常用的实现类有HashMap,LinkedHashMap,Hashtable和ThreeMap
List和Set和Map的应用场景?
- 使用索引访问数据时,采用List,ArrayList可以更快的访问,如果经常是添加/删除数据的话,采用LinkedList。
- 如果想要值不重复的话,采用set,可以保证插入的元素是唯一的。
- 如果想要是有序的存储的,则选择List,如果想要无序的存储,则选择set。
- 如果是已键值对的形式存储数据,则选择Map。
转发(forward)和重定向(redirect)的区别?
- 从url来看:转发是由服务器进行请求资源,浏览器发送转发请求,服务器直接访问目标地址的URL来获取资源,然后返回给浏览器,浏览器并不知道资源来自哪里,所以地址栏并没有变化。而重定向,浏览器发送重定向请求到服务器,服务器返回一个状态码(例如301,302),浏览器收到状态码后重新去请求获取资源。
- 从数据共享来看:转发不仅可以进行页面跳转,并且该页面可以共享request中的资源;重定向,只允许页面跳转,不发送数据。
- 从应用场景来看:转发主要用在用户登录时,跳转到指定的页面并返回用户信息等数据;重定向主要应用于用户注销,跳转回平台首页或其他网站不需要登录可访问的页面。
- 从效率来看:转发的效率会更高,重定向的效率会比较慢。
Object中有几种方法?
- Clone()方法:实现对象的浅复制,需要实现cloneable接口,否则抛出CloneNotSupportException异常
- getClaa()方法:final方法,用于获取类对象,与其相同的还有另外两种,静态属性.class和Class.forName(“类全路径”);【常用】
- equals()方法:用于比较两个对象的值是否一样,而”==”是比较两个对象是否指向同一个地址,若是则返回true
- toString()方法:转为字符串类型
- finalize()方法:该方法是在垃圾回收机制前执行,具体执行时间不清楚
- hashCode()方法:获取某个对象的地址
- wait()方法:让线程从执行中转为睡眠状态
- notify()方法:唤醒该对象上的的某个线程
- notifyAll()方法:唤醒该对象上的全部线程
Java常用的六大原则
- 单一职责原则:该原则针对类来说,即一个类只负责一个职责。假如有一个类负责了两项职责,职责T1,职责T2,当修改T1的需求发生变化需要修改T类时,会导致职责T2的故障。
优点:1. 降低类的复杂度,一个类只负责一项职责
2. 提高类的可读性,可维护性
3. 降低变更引起的风险
- 里氏替换原则:子类在继承父类后,需重写父类的方法,虽然没有强制要求子类必须按照父类方法的逻辑进行,但是子类不能够去修改父类的逻辑。
缺点:1. 程序的可移植性降低
2. 增加了对象之间的耦合性
3. 如果父类进行修改后,继承它的所有子类也需要进行修改,增加成本
- 依赖倒置原则:高层模块不依赖低层模块,二者都应该依赖其抽象;抽象不依赖细节,细节依赖于抽象。通俗的讲就是,在高层模块和低层模块之间加入一个抽象(接口),通过抽象来将高层模块和低层模块进行依赖,降低耦合性。
- 接口隔离原则:类A通过接口I依赖类B,类C通过接口I依赖类D,若对于类A和类C来说不是最小接口,则类B和类D都需要去实现他们不需要的方法,这样会使程序变得很臃肿,采用接口隔离后,类A通过接口I依赖B,类C通过接口J依赖类D,这样就可以减轻程序的臃肿。
- 迪米特法则:对象之间应该减少关联,从而降低对象之间的耦合性
- 开闭原则:一个软件实体类,应该对外扩展开放,对修改关闭,该原则时前面五个原则的基石。
Spring有哪些组件?
Bean组件,Context组件,Core组件
SpringMVC执行流程
- 用户发送请求,请求被SpringMVC的前端控制器DispatcherServlet截获
- DispatcherServlet得到请求的URL(统一资源定位符)并对其进行解析,得到一个URI(资源标识符),然后根据解析到的URI来调用HandlerMapping进行获取所有相关的对象。
- DispatcherServlet调用相关的HandlerAdapter进行处理。
- Handler处理完成后,返回一个ModelAndView给DispatcherServlet,该ModelAndView中需要包含有视图名和视图模型
- DispatcherServlet调用对应的视图解析器ViewResolver并返回给DispatcherServlet
- ViewResolver结合Model和view渲染视图
- 将视图返回给浏览器
Spring IOC和AOP的区别?
- IOC(控制反转Inverse of Control):假如有一个A类和一个B类,当A类需要B类时,按照我们传统的是 B b = new B();这样来获取B的对象。这样有一个缺点就是耦合性太强,假如B类的类名改成了C,那么我们就要修改源代码成C c = new C();Spring为了降低耦合性,出现了IOC控制反转,若A类需要B类的对象,则不直接通过new关键字,而是交给Spring容器来完成,在Spring的配置文件中可以这样写到 <bean id=”b” class=”com.cuc.B”/> <bean id=”a” class=”com.cuc.A”> <property name=”b” ref=”b” /></bean>,这样就A类中直接通过定义一个变量的形式private B b;就可以动态的获取到B类的实例化对象。
- AOP(面向切面编程):AOP主要使用在事务方面上,当你需要完成一件事情,但是在完成这件事情之前,还需要完成其他事情,比如你现在需要吃早饭,但是吃早饭的前提是你需要先刷牙和洗脸,然后吃完早饭后还需要将碗筷收拾干净,类似这样的行为就是AOP,从这样例子我们迁移到JAVA上来,AOP在事务的使用上主要是这样的,当你需要访问数据库时,Sping会把在你访问数据库之前帮你开启事务,在你访问结束之后,Spring会自动的帮你提交或者回滚事务。而你并不用去理会它当中的事务处理是怎样进行的。各自分工明确,符合单一原则的设计原则。
脏读,不可重复读和幻读
- 脏读:对于数据X,有一个事务A对数据X进行的修改,但是没有修改成功,在事务回滚之前,事务B来读取了这个事务A没有修改成功的数据,这就是脏读,通俗的说就是一个事务读取到了另一个事务没有修改成功的数据。
- 不可重复读:对于数据X,事务A先读取了数据X,然后进行事务操作,这个时候事务B对数据X进行了成功修改,然后事务A回来再次读取数据X发现和前一次读取到的数据不一样,这个就是脏读,通俗的说就是一个事务第一次读取了数据,然后另一个事务进行了数据的修改后,最开始的那个事务再次回来读取时发现和前面读取的数据不一致。
- 幻读:对于N条数据,事务A读取到了这N条数据之后,事务B这时候进来添加了M条数据,这个时候事务A在读取时发现第一次读取的是N条数据,而第二次则是N+M条数据。通俗的说就是一个事务第一次读取到的数据比第二次读取到的数据少。
Volatitle和sychronized的区别
- Volatitle只能作用于变量上,而sychronized则可以作用于变量,方法和类。
- Volatitle相当于告诉JVM,CPU缓存上的数据是不确定的,需要从主存上进行获取,sychronized是则是锁定当前的变量,除当前线程外,不允许其他线程进行访问
- Volatitle不能造成线程阻塞,sychronized会造成线程阻塞
- Volatitle只能保证变量修改的可见性,不能保证原子性,sychronized可以保证变量修改的可见性和原子性
- Volatitle变量不会被编译器进行优化,sychronized变量会被编译器优化
如何保证线程安全?
- 原子性(Atomic):我们的JAVA程序会被操作系统编译成汇编语言,程序若不是单指令,那么在执行一半的时候,很容易去执行了其他的代码,导致该线程暂停,这样很容易导致数据的错误出现。
- 同步(synchronized):同步关键字synchronize可以使用在变量,方法和类上,该关键字会给程序加一个锁,当锁是处于锁住的状态时,除了当前线程能够进行操作,其他线程都需处于就绪状态,等该线程结束后,锁会打开,这时根据调度算法调度下一个线程进入CPU操作,同步可保证数据的可见性以及原子性。
- 过度优化(volatitle):有了同步可以对线程安全有了一定的保证性,但是在很多情况下,这样还是不够,所以我们还可以使用volatitle关键字,告诉JVM在CPU缓存上的数据是不确定的,直接从主存上进行获取。
HashMap和HashTble的区别?
- 时间上:HashTable产生于JDK1.1,HashMap产生于JDK1.2,所以HashTable要比HashMap早一些
- 公开的方法:两者都有相同的方法(Map接口:sieze()/isEmpty()/containKey()/containValue()/get()/put()/remove()/putAllMap()/clear()/keyset()/values()/entrySet()/equals()/hashCode()/toString();Cloneable接口:clone()),但是在HashTable上,还有另外两个方法(Dictionary抽象类:elements(),其他:contains()),因为HashTable是继承了抽象类Directionary,而HashMap是继承了抽象类AbstractMap,但是抽象类Directionary已经被弃用了,所以element()方法也就没啥用,而contains()方法跟前面Map接口的containValue()方式是一样的。
- Null key和Null value:HashTable是不允许null值存在的,会报空指针NullPointerException异常,而HashMap则对null进行了特殊的处理,会将null的哈希码值定为0,也就放在了哈希表的第一个位置。
- 容量:HashTable初始容量是11,每次扩大是容量是2N+1;HashMap的初始容量是16,每次扩大2N
- 线程安全:HashTable是线程安全的,在其get(Object key)和Keyset()方法中都使用了sychronized关键字,HashMap是线程不安全的
什么是死锁?
- 死锁的概念:产生死锁,至少需要两个及以上的线程才可以产生,线程对资源的使用,我在等你的执行,而你在等我,相互等待,互不相让,则会产生死锁的情况