1.Java中堆和栈的区别
每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中拷贝一份缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用了,它要求线程从主存中读取变量的值。
2.volatile关键字
用来保证共享变量的“可见性”,“可见性”的意思就是当一个线程中对volatile关键字修饰的变量进行写入操作时,其他线程能够及时更新这个变量。在JVM的内存模型中,有分为工作内存和主内存,每一个线程都有自己的工作内存,并且共享主内存里面的数据。
对于普通变量,读操作会优先读工作内存中的数据,如果没有的话再到主内存中寻找并且拷贝一份到工作内存。写操作只会改变工作内存中的数据,所以当变量被修改时,其他线程无法及时得知。
对于volatile修饰的变量,读操作时JMM会把工作内存当中的值设为无效,要求线程在主内存中读取数据;写操作时,JMM会把工作内存当中的数据刷新到主存,这样其他线程就能够访问到最新值。
3.ArrayList和LinkedList的区别
1)ArrayList是基于动态数组的数据结构,LinkedList是基于链表的数据结构。
2)对于随机访问,ArrayList优于LinkedList,LinkedList需要遍历链表。
3)对于插入删除,LinkedList优于ArrayList,ArrayList需要移动整个数组。
4.线程安全是什么
线程安全就是多个线程访问时,采用加锁机制。当一个线程访问类的某个数据的时候,其他的线程不能再访问直到该线程访问完毕。
线程不安全就是不采用数据保护机制,可能出现多个线程同时访问同一数据,造成数据污染,出现脏数据(访问的数据跟期待的数据不一样、会影响系统正常行为的数据)
5.SpringMVC的生命周期
1)客户端发送请求(request)到DispatcherServlet
2)DispatcherServlet将请求委托给HandleMapping,寻找能够处理请求的Controller
3)执行Controller对应的业务方法并返回ModelAndView对象给DispatcherServlet
4)DispatcherServlet委托视图解析器(viewResolver)解析返回的内容
5)解析完毕将数据再次返回给DispatcherServlet,通过jsp渲染将页面展示给客户端
6.抽象、继承、封装、多态
抽象:把一类事物的共有属性和行为提取出来,形成物理模型的一种研究方法。
继承:通过扩展一个已有的类,并且继承它的方法和行为,来创建一个新的类。原来的类叫父类,新类叫子类。这就叫继承。
封装:把数据和对数据的操作封装在一起,数据被保存在内部,程序的其它部分只能通过被授权(成员方法)的操作进行对数据的操作。Java实现这种访问控制是通过修饰符来实现的:public(公共访问权限)、protected(继承访问权限)、无修饰符(默认访问权限)、private(私有访问权限)。对应权限是包外&&子类&&包内&&类内、子类&&包内&&类内、包内&&类内、类内。
多态:指一个引用(类型)在不同情况下的多种状态。主要有重载(Overload)(发生在同一类中)和重写(Override)(发生在父类和子类之间)。改变参数个数、顺序、类型的称为重载。与父类同名且参数条件不变并且返回值类型与父类相同或者是父类的子类的称为重写。通过多态,可以使得一个对象能够访问多个子类的方法。
7.Java程序的运行过程,JDK、JRE、JVM是什么?
运行过程:.java源文件会被会被编译器编译为 .class 文件,.class 字节码文件会被虚拟机(JVM)解释为机器码,进而在操作系统上执行。
JDK:包含了编译、运行等开发工具和JRE
JRE:包含了JVM(/bin)和JVM运行时要用到的类库(/lib)
JVM:Java虚拟机,它是一个可以执行 .class字节码文件的虚拟进程。它是Java实现跨平台最核心的部分,它能够将编译器产生的 .class 字节码文件解释给操作系统,也就是 .class文件不是直接在操作系统上执行,而是通过JVM间接的和操作系统进行交互。
8.JVM运行机制
Class Loader(类加载器)、运行时数据区(方法区、堆、栈(虚拟机栈、本地方法栈)、程序计数器)、执行引擎
Class Loader(类加载器):识别、验证、分配内存、帮助解析
方法区:区域内数据所有线程共享。存放静态变量、常量、运行时常量池、类信息这些不变的数据。
栈:存放基本类型变量、对象的引用变量,每个线程都可以有自己的栈,栈内数据与其他线程不共享。
程序计数器:每一个线程都会有一个PC,其实是一个指针,用来指向方法区中下一条执行指令的地址。由执行引擎读取。
堆:一个JVM只有一个堆,且里面的数据时共享的,在类加载器加载类文件后,需要把类、方法、常变量放进堆。堆也是GC回收的主要区域。堆有三个区域
①新生区(伊甸区、幸存者0区、幸存者1区)
伊甸区满则触发GC将伊甸区未被回收的数据移至0区——>0区满则触发GC,0移至1——>1满则触发GC,1移至养老;以此类推。
②养老区。主要保存从新生区筛选出来的对象。
③永久区。存储运行环境必要的类信息,这个区域的数据是不会被GC机制回收的。
9.值传递和引用传递的区别
值传递传递的是副本,它创建了实际的对象,对副本的修改不会影响源对象。而引用传递传递的是对象的应用,而不是实际的对象,因此,外部对引用对象的操作会反映到源对象上。
10.接口和抽象类的区别
1)实现抽象类用extends,实现接口用implements
2)抽象类里面可以有非抽象方法,接口里的不能有方法的实现。
3)一个类只能继承一个抽象类,却可以实现多个接口。(通过此实现多继承)
4)实现接口要实现所有方法,实现抽象类不一定。
5)抽象是对类的抽象,二接口则是对行为的规范。
11.equal() 和 == 的区别
equal()是Object类的方法,默认情况(基本类型)中, equal() 和 == 的返回值是一样的,但是在复合类型(String、Integer、Date......)中,他们的equal()有自己的实现。
1)基本数据类型的比较 equal() 和 == 都是直接比较值
2)复合数据类型的比较 equal()比较的是内存地址, == 比较的是值是否相同
值得注意的是
①String s1 = “hello”;String s2 = “hello”;==>s1==s2,s1.equal(s2)==true
②String s1 = “hello”;String s2 = new String("hello");==>s1!=s2,s1.equal(s2)==true
第①条中,创建s2变量会在字符串池中查找有没有该值,有的话就返回它的引用,地址是不变的。
第②条中是告诉虚拟机我不要引用的,我要一个新的(new)。
此时如果在第②条后面加s2=s2.intern();那么s2又会变成对s1的引用。
12.线程、程序、进程
线程:和进程差不多,不过它是比进程更小的执行单位,一个进程里面可以有多个线程。
程序:指令和数据(静态代码)
进程:程序的执行过程。
13.HashMap和HashTable的区别
1)线程安全不同。HashMap是线程不安全的,HashTable的方法基本都被synchronized过,是线程安全的。
2)效率,HashMap效率高于HashTable。
3)HashMap允许键入空值(key也可以是空的),HashTable键入则会报NullPointerException异常。
14.成员变量与局部变量的区别
1)成语变量是属于类的,所以它会存放在堆内存,而局部变量它是在方法内或是参数,存放在栈内存。
1)成员变量随着类创建而创建,局部变量随着方法的调完毕而消亡。
15.为什么不能用返回值类型来区分重载
1)重载发生在一个类内,如果两个方法除了返回值类型不同,其它相同,在调用的时候我们无法区分是想要调用哪个函数。
2)如果子类重写的函数的返回值类型是父类对应函数返回值类型的子类,也是可以称为重写的。
16.Java为什么药使用 .class 文件,它的优势是什么?
一方面解决了编译型语言执行效率低的问题,另一方面保留了解释型语言的可移植性。
17.比较Java和JavaScript最主要的区别
最主要的区别在于Java是静态语言,类是一等公民;Javascript是动态语言,函数是一等公民,所以它支持函数式编程。
18.什么时候使用断言 assert
断言是一种软件开发中的调试方式,它能够保证程序的正确性。一般在软件开发和测试的时候启用,为了保证程序的执行效率,通常在软件发布的时候要将它关闭。
19.Error和Exception的区别
Error表示的是系统级错误或者是程序无法处理的异常,是恢复不是不可能但困难的一种情况,例如内存溢出,我们没有办法通过修改我们的程序来修复。而Exception代表的是程序执行时需要去捕捉或者处理的异常,它是可以通过修改程序来修复的。
20.列出一些常见的运行时异常
ArithmeticException(算数异常)、IndexOutOfBoundsException (数组下标越界异常)、NullPointerException(空指针异常)、IllegalArgumentException (非法参数异常)
21.下面程序执行的结果
Caught Annoyance
Caught Sneeze
Hello World!
这里可能会有疑问为什么会有第二句 Caught Sneeze,Sneeze不是Annoyance的子类么,子类不是不能捕获父类的异常么?其实很简单,在第一个Catch执行过程中,偷偷执行了Annoyance a = new Sneeze(); 而这句代码带来的结果就是a.getClass() == Sneeze;所以在第二个Catch语句中能够捕捉到异常。
22.构造器Constructor是否可被override
不可以重写(override),但是可以重载(overload)
23.构造方法的特性
名字与类相同、没有返回值但是也不能用void声明、创建对象的时候自动执行