练习葵花宝典
1. JavaSE
1.1 概念
1.2Exception
1.3 Thread
1.4 IO
1.5 Security
1.6 Log
1.7 java.exe javac.exe
1.8 内存管理机制
1.8.1 heap(堆)和stack(栈)有什么区别
Java的内存分为两类,一类是栈内存,一类是堆内存。
栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。
堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用new创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用final修饰后,放在堆中,而不是栈中。
1.8.2 GC是什么? 为什么要有GC?
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
1.8.3 垃圾回收的优点和原理。并考虑2种回收机制。
Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
1.8.3 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。
通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
1.8.4 java中会存在内存泄漏吗,请简单描述。
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。
(1)Java中的内存泄露的情况:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是Java中内存泄露的发生场景。通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中可能出现内存泄露的情况,例如,缓存系统,我们加载了一个对象放在缓存中(例如放在一个全局map对象中),然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。
检查java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。
(2)如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
下面内容来自于网上(主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中拿掉,而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让它从数组中消失,将那个元素所在的位置的值设置为null即可):
我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子不是我想到的,是书上看到的,当然如果没有在书上看到,可能过一段时间我自己也想的到,可是那时我说是我自己想到的也没有人相信的。
public class Stack { private Object[] elements = new Object[10]; private int size = 0; public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } }
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果,如果这个堆栈用的比较少,也就浪费了几个K内存而已,反正我们的内存都上G了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。下面看两个例子。
public class Bad { public static Stack s = new Stack(); static { s.push(new Object()); s.pop(); // 这里有一个对象发生内存泄露 s.push(new Object()); // 上面的对象可以被回收了,等于是自愈了 } }
因为是static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的Stack最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很容易理解,Stack内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!
(3)内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
1.9 classpath
1.10 classload
1.10.1 类的初始化顺序
(1)静态变量->静态初始化块->变量->初始化块->构造器
(2)父类静态变量->静态初始化块->子类静态变量->子类静态初始化块->父类变量->父类初始化块->父类构造器->子类变量->子类初始化块->子类构造器
(3)静态变量——静态初始化块,变量——初始化块,出现的顺序取决于在类中出现的顺序
(4)并不是在父类完全初始化后才开始初始化子类
1.10.2 怎样创建一个类的实例
(1)使用new关键字创建一个对象
(2)调用Class类的newInstance方法,利用反射机制创建对象
1.10.3 描述一下JVM加载class文件的原理机制?
JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
(1)ClassLoader基本概念
ClassLoader包括bootstrap classloader(启动类加载器)。
bootstrap classloader: JVM启动时,加载Java核心API(包括ExtClassLoader和AppClassLoader)。
ExtClassLoader:用来加载Java的拓展API,也就是/lib/ext中的类。
AppClassLoader:用来加载用户机器上CLASSPATH设置目录中的Class,通常在没有指定ClassLoader的情况下,自定义的类就由AppClassLoader加载。
(2)ClassLoader加载流程
当运行一个程序,JVM启动,运行bootrap classloader,加载Java核心API(包括ExtClassLoader和AppClassLoader),然后调用ExtClassLoader加载拓展API,调用AppClassLoader加载CLASSPATH设置目录中的Class。
1.11 Collection
1.12 字符串
1.12.1 字符集
Java中字符只以一种形式存在,就是Unicode。
1.13 Java语法
1.13.1 Java有没有goto
Java中的保留字,现在没有在Java中使用。
1.13.2 一个Java源文件中是否可以包含多个类
可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。
1.13.2 & 和 && ,| 和 || 的区别
&和&&都可表示逻辑与,&还可以用作位运算,&&具有短路功能
1.13.3 在Java中如何跳出多重循环
可使用break跳出多重循环,一般在外层使用一个局部变量来获得循环中运算的结果。
1.13.4 switch能否使用short、long、String作为判断条件
switch(expr1)中,expr1只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。
(1)byte、char、short、int四种基本类型以及它们的包装类(需要Java5.0/1.5以上版本支持)都可以用于switch语句。
(2)long、float、double、boolean四种基本类型以及它们的包装类(在Java所有版本中)都不能用于switch语句。
(3)enum类型,即枚举类型可以用于switch语句,但是要在Java5.0(1.5)版本以上才支持。
(4)所有类型的对象(包括String类,但在Java5.0/1.5以上版本中,该项要排除byte、char、short、int四种基本类型对应的包装类)都不能用于switch语句。
1.13.5 "=="和"equals"的区别
(1)"=="用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。
(2)对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
(3)equals方法是用于比较两个独立对象的内容是否相同。
(4)如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。
2. JavaEE
2.1 Spring
2.1.1 Spring有哪些特点?为什么要使用Spring?
Spring有两个特点:
- 控制反转(Inverse of Control,IOC)
- 依赖注入(Dependency Injection, DI
控制反转是对组件对象控制权的转移,从程序代码本身转移到外部容器,通过容器来实现对象组件的装配和管理。
依赖注入是指在运行期间由容器将依赖关系注入到组件之中,即在运行期间,由Spring根据配置文件,将其他对象的引用通过组件提供的setter方法进行设定。
注入类型: 接口注入、设置注入、构造注入。
2.2 MyBatis
2.3 SpringMVC
2.4 SOA
![]() |
作者:沙漏哟 出处:计算机的未来在于连接 本文版权归作者和博客园共有,欢迎转载,请留下原文链接 微信随缘扩列,聊创业聊产品,偶尔搞搞技术 |