本文是为了帮助大家进行Java面试时Java基础的复习,希望对大家有所帮助!!!
1.什么是内部类?内部类的分类?
内部类:内部类的官方叫法是嵌套类,在Java中,可以把一个类定义在另一个类里面或者一个方法里面,这样的类成为内部类。
分类:静态内部类;内部类(成员内部类,局部内部类,匿名内部类)
1)静态内部类:静态内部类就是在内部类的前面加了一个static关键字,静态内部类不能直接访问外部类的非静态成员变量和方法(静态内部类可以通过创建外部类的对象访问外部类的非静态的成员变量和方法),内部类可以直接访问外部类的静态变量,与访问权限修饰符无关。
2)成员内部类:成员内部类可以直接使用外部类的所有成员和方法,与访问修饰符的级别无关。外部类要访问内部类的所有成员变量和方法,需要通过内部类的对象来获取。成员内部类不能含有static的变量和方法,因为成员内部类需要先创建外部类才能创建他。
3)局部类内部类:局部内部类是指定义在方法体内的内部类,只能在该方法或条件的作用域内才能使用,退出这个作用域就无法使用。成员内部类的限制条件对局部内部类同样成立,局部内部类可以访问方法体内final修饰的局部变量。
4)匿名内部类:为了避免给内部类命名,或者只是想使用一次,可以选择使用匿名内部类。局部内部类的限制条件对匿名内部类同样成立。
2.内部类的作用?
1)内部类可以有很好的封装,让内部类不对外开放。内部类可以使用private和protected来修饰;
2)内部类可以拥有外部类成员变量和方法的访问权限,即使是private;
3)内部类可用来实现多继承,让多个内部类分别继承一个父类,这样外部类就可以访问多个其他类的属性;
4)如果某个类的接口和父类中存在同名的方法,可以用内部类加以区分。让外部类继承,内部类去实现接口。
3.为什么局部内部类访问局部变量,变量必须加上final?
因为一个方法中的局部变量会随着方法的执行结束而失效,但是方法结束后内部类的实例依然可以存在,但是在外面或者后续调用该局部变量的时候,这个局部变量就失效了。所以Java采取了拷贝本地变量的方法实现,final的变量,会拷贝一份存到局部内部类中,后续使用这个副本,所以可以继续访问。
4.Java采用的是大端还是小端?
大端模式:数据的高字节保存在内存中的低地址中,数据的低字节保存在内存的高地址中;
低端模式:数据的高字节保存在内存中的高地址中,数据的低字节保存在内存的低地址中;
java由于虚拟机的关系,屏蔽了大小端问题,需要知道的话可用 ByteOrder.nativeOrder() 查询。在操作ByteBuffer中,也可以使用 ByteBuffer.order() 进行设置。
5.List、Set、Map的区别?
List和Set接口都继承自Collection接口。
List:
1)可以允许重复的对象;
2)可以插入多个null元素;
3)是一个有序的集合,保持了每个元素的插入顺序,输出的顺序就是插入的顺序;
4)常用的实现类有ArrayList、LinkedList、Vector。
Set:
1)不允许重复的对象;
2)一个无序的集合,无法保证每个元素的顺序,TreeSet可以维护一个排序顺序;
3)可以多次插入null元素,但是只能有一个存在,后插入的覆盖以前的元素;
4)Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。
Map:
1)Map不是collection的子接口或者实现类。Map是一个接口。
2)Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
3)TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
4) Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
5)Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。
6.final、finally、finallize的区别?
final:final修饰的类不能被继承,因此一个类的final和abstract不能同时使用;final修饰的方法不能被重写;final修饰的变量的值不能被修改,并且变量必须在声明的时候就给出初始值。
finally:finally是在异常处理时提供finally块来执行任何的清理工作。无论有没有异常抛出、捕获,finally都会被执行。
finalize:finalize时方法名,Java允许重写finalize方法在GC清理垃圾之前做必要的清理工作,不建议使用。
7.int和Integer的区别?
Java进行和Integer和int的运算时会自动拆箱和装箱。
1)Integer和new Integer不相等。new出来的对象存放在堆中,而非new出来的Integer时存放在常量池中的,内存地址不一样,所以为false;
2)两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。因为java在编译Integer i2 = 128的时候,被翻译成:Integer i2 = Integer.valueOf(128);
3)两个都是new出来的,都为false。还是内存地址不一样;
4)int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比;
8.重载和重写的区别?
重写:
1)重写的方法的标志必须要和被重写的方法的标志完全匹配,才能达到覆盖的效果;
2)重写的方法的返回值必须要和被重写的方法的返回值一致;
3)重写的方法的抛出的异常必须和被覆盖的方法所抛出的异常一致,或者是其子类;
4)被重写的方法不能是private的,否则起子类中只能定义一个新方法,并没有对其重写;
重载:
1)在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序;
2)不能通过访问权限、返回类型、抛出的异常进行重载;
3)方法的异常类型和数目不会对重载造成影响;
4)对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
9.接口和抽象类的区别?
第一点:接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。
第二点:接口可以多继承,抽象类不行
第三点:接口定义方法,不能实现,而抽象类可以实现部分方法。
第四点:接口中变量是常量,而抽类象不是的。
10.自定义注解的使用场景和实现?
跟踪代码的依赖性,实现代替配置文件的功能。比较常见的是Spring等框架中的基于注解配置。
还可以生成文档常见的@See@param@return等。如@override放在方法签名,如果这个方法 并不是覆盖了超类方法,则编译时就能检查出。
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节,在定义注解时,不能继承其他注解或接口。
11.什么是值传递和引用传递?
对象被值传递,意味着传递了一个对象的副本。改变副本的值是不会影响本来对象的值;
对象被引用传递,意味着传递的是对象的引用,改变引用对象的值就是改变原对象的值。
12.Iterator和ListIterator的区别是什么?
Itertor可以用来遍历Set和List集合,只能向前遍历;
ListIterator只能用来遍历List,既可以向前也可以向后遍历,ListIterator实现了Iterator接口,并且包含了:增加元素,替换元素,获取前一个或后一个元素的索引。
13.HashMap和Hashtable有什么区别?
1)HashMap和Hashtable都实现了Map接口,因此大体的功能是相似的;
2)HashMap继承自AbstractMap,Hashtable继承自Dictionary(已经过时);
3)HashMap允许健和值是null,不是线程安全的;
4)Hashtable不允许健和值是null,线程安全的,遗留的类,几乎不会使用了;
如果想用线程安全的HashMap可以使用ConcurrentHashMap,效率会比Hashtable好;
14.Enumeration接口和Iterator接口的区别有哪些?
Java中的集合都提供了返回Iterator的方法,Iterator是Enumeration的替代品;
Enumeration的速度更快,但是Iterator的安全性更好,因为其它线程不能修改正在被Iterator遍历的集合里面的对象;
Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的;
15.HashSet和TreeSet的区别?
HashSet是由Hash表实现,元素是无序的,可以放入null值,但是只能有一个null值,操作的时间复杂度是O(1);
TreeSet是由二叉树实现的,元素是自动排好序的,不允许放入null值,操作的实现复杂度是O(logn);
16.PreparedStatement比Statement有什么优势?
1)PreparedStatement可以参数化查询,比Statement能获得更好的性能;
2)数据可可以使用之前已经编译过和定义好的PrepareStaetment的执行计划,只需要改变参数值,这种预处理语句比普通的语句运行速度要快;
3)PreparedStatement可以阻止常见的SQL注入攻击;
17.System.out.println()里面,System,out,println分别是什么?
System是系统提供的预定义的final类,out是一个PrintStream对象,Println是out对象里面一个重载的方法。
18.Java中的基本数据类型?
byte-1个字节;short-2个字节;int-4个字节;long-8个字节;float-4个字节;double-8个字节;char-2个字节;boolean-1个字节;
19.如果main()方法声明为private?如果把static修饰符去掉?
编译不会报错,运行会报找不到main方法的错误。
20.switch是否能作用在byte上?是否能作用在long上?是否能作用在String上?
JDK1.5以前可以是byte, short, char, int。JDK1.5以后新增加了String(JDK1.7)和Enum。long类型肯定是不可以的。
21.面向对象的特征?
1)封装: 封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是
封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量
定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个
类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则:把对同一事物进行
操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中。
2)抽象: 抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集
中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,
如下: class Person{ String name; int age; } 人本来是很复杂的事物,有很多方面,但因为当前系统只需要了解人的姓名和年龄,所以上面定义的类中只包含姓名和年龄这两个属性
,这就是一种抽像,使用抽象可以避免考虑一些与目标无关的细节。我对抽象的理解就是不要用显微镜去看一个事物的所有方面,这样涉及的内容就太多了,而是要善于划分问题的边界,
当前系统需要什么,就只考虑什么。
3)继承: 在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使
之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
4)多态: 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例
对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑
定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态
性增强了软件的灵活性和扩展性。例如,下面代码中的UserDao是一个接口,它定义引用变量userDao指向的实例对象由daofactory.getDao()在执行的时候返回,有时候指向的是
UserJdbcDao这个实现,有时候指向的是UserHibernateDao这个实现,这样,不用修改源代码,就可以改变userDao指向的具体类实现,从而导致userDao.insertUser()方法调用的具体代
码也随之改变,即有时候调用的是UserJdbcDao的insertUser方法,有时候调用的是UserHibernateDao的insertUser方法: UserDao userDao = daofactory.getDao();
userDao.insertUser(user);
22.反射的用途和实现?
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意一个方法;这种动态获取信息和动态调用方法的功能称为反射。
(动态的判断任意一个对象所属的类;动态构造对象;动态判断某个类的成员变量和方法;动态的调用某个对象的方法)。
反射最主要的用途就是开发各种通用的框架。
23.自定义注解的场景和实现?
使用@interface自定义注解时,自动继承java.lang.annotation.Annotation接口,由编译程序自动完成其它的细节,在自定义注解的时候不能继承其它注解或者接口。
跟踪代码的依赖性,实现代替配置文件的功能。比较常见的实现就是Spring等框架的基于注解的配置和@Override等方法签名。
24.HTTP请求的GET和POST方式的区别?
GET:可以缓存;数据长度有限制,发送数据时,GET方法向URL添加数据,URL的长度是有限制的(URL的最大长度是2048个字符);只允许ASCII字符;GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET;数据在URL中对所有人可见。
POST:不可以缓存;数据长度无限制;数据类型没有限制;POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中;数据不显示在URL中。
25.session和cookie的区别?
1)cookie的数据存放在客户的浏览器上,session的数据保存在服务器上;
2)cookie不是很安全,别人可以分析存放在本地的cookie,并进行cookie欺骗,如果对安全性有要求应该使用session;
3)session会在一定时间内保存在服务器上面,当访问增多的时候,会比较占用服务器的性能,考虑到服务器的性能可以使用cookie;
4)单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie;
5)将登陆信息等重要信息保存在SESSION,其它信息保存在COOKIE;
26.session的分布式处理?
第一种:粘性session
原理:粘性Session是指将用户锁定到某一个服务器上,比如上面说的例子,用户第一次请求时,负载均衡器将用户的请求转发到了A服务器上,如果负载均衡器设置了粘性Session的话
,那么用户以后的每次请求都会转发到A服务器上,相当于把用户和A服务器粘到了一块,这就是粘性Session机制。
优点:简单,不需要对session做任何处理。
缺点:缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的session信息都将失效。
适用场景:发生故障对客户产生的影响较小;服务器发生故障是低概率事件。
实现方式:以Nginx为例,在upstream模块配置ip_hash属性即可实现粘性Session。
第二种:服务器session复制
原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要session,以此来保证
Session同步。
优点:可容错,各个服务器间session能够实时响应。
缺点:会对网络负荷造成一定压力,如果session量大的话可能会造成网络堵塞,拖慢服务器性能。
第三种:session共享机制
使用分布式缓存方案比如memcached、Redis,但是要求Memcached或Redis必须是集群。
第四种:session持久化到数据库
原理:就不用多说了吧,拿出一个数据库,专门用来存储session信息。保证session的持久化。
优点:服务器出现问题,session不会丢失
缺点:如果网站的访问量很大,把session存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。
第五种terracotta实现session复制
原理:Terracotta的基本原理是对于集群间共享的数据,当在一个节点发生变化的时候,Terracotta只把变化的部分发送给Terracotta服务器,然后由服务器把它转发给真正需要这个
数据的节点。可以看成是对第二种方案的优化。
优点:这样对网络的压力就非常小,各个节点也不必浪费CPU时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在session同步上,既避免了对数据库的依赖,又能
达到负载均衡和灾难恢复的效果。
27.JDBC的流程?
1)注册驱动
2)连接数据库
3)创建Statement
4)执行SQL
5)处理结果集
6)关闭连接
28.MVC设计思想(有人也称设计模式)?
1)MVC是一种软件架构的思想,将一个软件的架构按照模型、视图、控制器划分。
2)模型层:业务逻辑包含了业务数据的加工与处理以及相应的基础服务(为了保证业务逻辑能够正常进行的事务、安全、权限、日志等等的功能模块);
视图层:展现模型处理的结果;另外,还要提供相应的操作界面,方便用户使用;
控制层:视图发请求给控制器,由控制器来选择相应的模型来处理;模型返回的结果给控制器,由控制器选择合适的视图;
3)优点:1、使用mvc的思想来设计一个软件,最根本的原因是为了实现模型层的复用,模型层不用关心视图层的展现,不同的视图层可以访问同一个模型;2、代码的具有较好的维护性,封装性好;3、方便测试,不需要把应用部署到容器上才能测试,直接用main方法测试。
29.equals和==的区别?
1)== 比较的是变量内存中存放的对象的内存地址,用来判断两个对象的地址是否相同,即是否指向同一个对象。1、比较的是操作符两端的引用是否是同一个对象;2、两边的引用是否是同一个类型,不是同一个类型不能编译通过;3、如果基本的数据类型,值相等则为true;
2)equals 比较的是两个对象的内容是否相等,由于所有的类都是继承自Objectl类,所以所有的对象都可以调用该方法,如果没有重写该方法,调用的就是Object类的方法,如果重写了该方法,就调用自己本身的方法。equals遵循几个特性1、自反性;2、对称性;3、传递性;4、一致性;5、非空性。
30.Java中直接缓冲区和非直接缓冲区的区别?
直接缓冲区:内核地址空间和用户地址空间之间形成了一个物理内存映射文件,减少了两者之间的copy过程;
非直接缓冲区:通过allocate()分配的缓冲区,将缓冲区建立在JVM的内存之中。
31.垃圾收集算法?
1)标记清除算法:首先标记出所有的需要回收的对象,在标记完成后统一回收被标记的对象。标记清除算法的不足:(1)标记和清除两个过程的效率不高(不清楚);(2)标记清除之后会产生大量的不连续碎片,大量的空间碎片会导致后续分配大对象的时候没有足够的连续空间而提前触发垃圾收集。
2)复制算法:将可用内存按容量分为大小相等的两块,每次只用其中的一块。当这块内存用完了,就将还存活着的对象复制到另一块上面,然后再把已经使用过的内存空间一次清理干净。这个算法不会出现标记清理算法的问题。复制算法的不足之处在于:(1)内存缩小为原来的一半,代价较高。
3)标记整理算法:标记过程仍然与“标记清除”算法一样,但是后续的步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。
4)分代收集算法:根据对象的生存周期将内存划分为几块。一般把Java堆分为新生代和老年代,这样就可以根据各个年代的特点选用最适当的收集算法。在新生代每次都有大量的对象死亡,只有少量的对象存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;而老年代中因为对象的存活率高、没有额外的空间对它进行分配担保,就必须使用“标记清理”或者“标记清除”算法来进行回收。
32.可达性分析算法中不可达的对象是不是非死不可?
不是“非死不可”,还可以进行挽救。宣告一个对象真正死亡,至少要经历两次的标记过程,如果对象在进行可达性分析之后发现不可达,那么它会被第一次标记。标记之后对对象进行筛选,筛选的条件就是此对象是否有必要执行finalize()方法。
当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过(一个对象的finalize()方法只会被系统调用一次),虚拟机将这两种情况都视为“没有必要执行”。
如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后有虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里的“执行”是指由虚拟机触发这个方法,但并不会承诺会等待它运行结束,这么做的原因就是怕finalize()方法执行缓慢或者发生了死循环。
稍后GC会对F-Queue中的对象进行第二次的小规模标记,如果对象要在finallize中拯救自己,只需与引用链中的某个对象建立关联就行,那么在第二次标记的时候会把它移除回收的集合。
33.Java中引用的类型?
1)强引用:“Oject obj = new Object”这类的引用,强引用存在,垃圾收集器就永远不会收集被引用的对象;
2)软引用:软引用用来描述那些还有用但不是必需的对象。软引用关联的对象在发生内存溢出之前,会对这些对象进行二次回收。
3)弱引用:弱引用也是用来描述那些非必需的对象的,当时强度要比软引用弱一些,弱引用关联的对象只能生存到下一次的垃圾收集发生之前;
4)虚引用:虚引用也成为幻影引用和幽灵引用。虚引用的存在不会影响对象的生存时间,更无法通过一个虚引用来获取一个对象的实例。虚引用存在的目的就是能在垃圾收集器回收该对象的时候可以收到通知。
34.JVM自动内存管理中如何确定对象是否“死去”?
1)引用计数法:
给对象添加一个引用计数器,每当有一个地方引用它时,计数器加一;当引用失效的时候,计数器就减一;如果计数器减到了0就代表这个对象不可能再被使用,GC就会清理该对象。
虽然引用计数法很好理解,效率也很高,但是现在主流的JVM都不使用该算法,主要就是因为该算法解决不了循环引用的问题。
2)可达性分析:
把“GC Roots”的对象作为起始点,向下搜索,搜索的路径成为引用链。当一个对象到“GC Roots”没有任何的引用链的时候,说明该对象已不可用。
35.哪些对象可以作为“GC Roots”(JDK1.7)?
虚拟机栈(栈帧中的本地变量表)中的引用对象;
方法区中的类静态属性引用的对象;
方法区中的常量引用的对象;
本地方法栈中JNI引用的对象;
36.ConcurrentHashMap的实现原理?(可以展开去说,此处记录的只是一些重点)
Java1.7的ConcurrentHashMap是由一个个的Segment组成,就是一个Segment的数组;Segment代表“部分”,Segment就是一个HashEntry的数组,Segment通过继承ReentrantLock来进行加锁的操作,每次加锁都是锁住了一个Segment,这样就能保证每个Segment是线程安全的了。
Segment的数组的长度是16,不可以扩容;HashEntry的默认大小是2,负载因子是0.75;
37.CopyOnWriteArrayList?
1)线程安全的ArrayList有两个类,分别是Vector和CopyOnWriteArrayList,CopyOnWriteArrayList的效率更高并且不会有java.util.ConcurrentModificationException错误。
2)CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
3)写的时候:需要加锁
向CopyOnWriteArrayList中add方法的实现(向CopyOnWriteArrayList里添加元素),可以发现在添加的时候是需要加锁的,否则多线程写的时候会Copy出N个副本出来。读的时候:不需要加锁
读的时候:不需要加锁
如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。相对于Arraylist线程安全,相对于vector,第一不会出现迭代器异常,第二提高了效率: 迭代器异常(快速失败):
38.类的实例化顺序?
1)父类的静态变量和静态代码块,子类的静态变量和静态代码块(静态变量和静态代码块按顺序执行)
2)父类的代码块,父类的构造函数,子类的代码块,子类的构造函数(多个代码块是按顺序执行)
39.类加载的过程?
加载 》连接(验证、准备、解析) 》初始化
1)加载:程序运行之前JVM用类加载器把字节码文件加载到内存,作为方法区内这个类的各种数据的入口;
2)验证:验证类加载的正确性,确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求。一般情况下javac编译的是不会出问题的,但是其他方式的文件可能会出问题;
3)准备:为类的静态变量分配内存,将其初始化为默认值。这里只为静态变量分配内存,此时没有对象的实例;例如:private static int c = 80;在准备阶段的初始值是0不是80;
4)解析:把类中的符号引用转化为直接引用。解释一下符号引用和直接引用。比如在方法A中使用方法B,A(){B();},
这里的B()就是符号引用,初学java时我们都是知道这是java的引用,以为B指向B方法的内存地址,但是这是不完整的,这里的B只是一个符号
引用,它对于方法的调用没有太多的实际意义,可以这么认为,他就是给程序员看的一个标志,让程序员知道,这个方法可以这么调用,但是B方
法实际调用时是通过一个指针指向B方法的内存地址,这个指针才是真正负责方法调用,他就是直接引用。
5)初始化:前几个阶段都是以JVM为主导,初始化阶段开始真正执行Java代码。为类的静态变量赋予正确的初始值,准备阶段赋予的是虚拟机的初始值,此处赋予的是编写的这分配的值;
40.符号引用和直接引用?
符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。
41.类加载器的分类?
Bootstrap ClassLoader:根类加载器,负责加载java的核心类(JAVA_HOME/lib下面的类),它不是java.lang.ClassLoader的子类,而是由JVM自身实现,开发者无法直接获取根加载器;
Extension ClassLoader:扩展类加载器,扩展类加载器的加载路径是JDK目录下jre/lib/ext,扩展类的getParent()方法返回null,实际上扩展类加载器的父类加载器是根加载器,只是根加载器并不是Java实现的;
Application ClassLoader:系统(应用程序)类加载器,它负责在JVM启动时加载来自java命令的-classpath选项、java.class.path系统属性或CLASSPATH环境变量所指定的jar包和类路径。程序可以通过getSystemClassLoader()来获取系统类加载器;
42.类加载器和类对的“相同”的判断?
相同的字节码文件,被不同的类加载器加载之后得到的类也是不同的;
如果判断两个Class是否“相同”,这个两个类必须被同一个类加载器加载,否则这个两个类是不同的;
43、Math.round(11.5) 等于多少? Math.round(-11.5)等于多少?
答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。
44、swtich 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?
答:早期的JDK中,switch(expr)中,expr可以是byte、short、char、int。从1.5版开始,Java中引入了枚举类型(enum),expr也可以是枚举,从JDK 1.7版开始,还可以是字符串(String)。长整型(long)是不可以的。
45、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
46.Java的访问权限修饰符?
访问权限 本类 包 子类 其他包
public 是 是 是 是
protected 是 是 是 否
default 是 是 否 否
private 是 否 否 否
47.JVM内存模型?
1)程序计数器:记录正在执行的字节码文件的位置,如果是native方法,程序计数器的值为空,不会发生OOM;
2)java虚拟机栈:每一个线程对应一个虚拟机栈,跟线程的生命周期一致。每个方法的执行都会创建一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存放了java的基本数据类型,对象引用等信息;
3)本地方法栈:执行native方法创建的方法栈;
4)堆:堆是jvm的内存模型中最大的一块内存区域,所有对象的实例和数组都要分配在堆上。它也是垃圾收集的主要区域;
5)方法区:用于存储被加载的类的信息、常量、即时编译后的代码jvm规范把它描述为堆中的一个逻辑部分。jdk8之前成为永久带,jdk1.8取消永久带的概念,用元空间代替。元空间不属于jvm内存的一部分,它直接存在本机内存中,常量池移到堆中;
48.方法区和永久代的区别?
方法区是jvm的规范,永久代是具体的实现,元空间是jdk1.8中的一种实现。
49.程序运行的时候发现CPU过高怎么办?
1)在Linux服务器上,执行top命令,查看占用CPU过高的进程的pid(进程号);
2)查看该进程里面线程的转托管太,查找资源消耗最大的线程,使用top -H -p [进程id]
使用top -H -p [进程id]
3)根据线程号就可以用JVM的命令行工具查看具体的信息,例如jstack命令(使用之前需要将线程ID转换为16进制)
面试题2-操作系统和计算机网络:https://blog.csdn.net/qq_27232757/article/details/83446164
面试题3-Spring和Mybatis:https://blog.csdn.net/qq_27232757/article/details/83446183
面试题4-算法:https://blog.csdn.net/qq_27232757/article/details/83474056