copyOf()
Arrays的copyOf()方法传回的数组是新的数组对象,改变传回数组中的元素值,不会影响原来的数组。copyOf的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原来数组的长度,则保留数组默认值。
例:
package extracurricular;
import java.util.Arrays;
public class CopyOf {
public static void main(String[] args) {
int[] arr1 ={1,2,3,4,5};
int[] arr2= Arrays.copyOf(arr1, 5);
int[] arr3= Arrays.copyOf(arr1, 10);
for(int i=0;i<arr2.length;i++){
System.out.print(arr2[i]+"");
}
System.out.println();
for(int i=0;i<arr3.length;i++){
System.out.print(arr3[i]+"");
}
}
}
System.arraycopy
System.arraycopy的结构如下:
System.arraycopy(源数组,源数组要复制的起始位置,目标数组(将原数组复制到目标数组),目标数组起始位置(从目标数组的哪个下表开始操作),复制源数组的长度).
注意:目标数组的长度要先加上源数组的长度,不然会越界。
package extracurricular;
import java.util.Arrays;
public class ArrayCopy {
public static void main(String[] args) {
char[] src = new String("hello").toCharArray();
char[] dest = new String("123456").toCharArray();
System.out.print("scr的源数组为:");
for(char c:src){
System.out.print(c);
}
System.out.print("\ntest目标数组为:");
for(char d:dest){
System.out.print(d);
}
int l1=src.length,l2=dest.length,l=l1+l2;
dest=Arrays.copyOf(dest,l);
System.arraycopy(src, 0,dest, l2, l1);
System.out.print("\n复制后数组为:");
for(int i=0;i<dest.length;i++){
System.out.print(dest[i]);
}
}
}
结果为:
scr的源数组为:hello
test目标数组为:123456
复制后数组为:123456hello
存储
栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
堆:存放用new产生的数据
静态域:存放在对象中用static定义的静态成员
常量池:存放常量
非RAM存储:硬盘等永久存储空间
程序命令
Java用来运行一个.class文件;
Javadoc用来生成api文档;
Jar用来生成jar包;
Javac用来把.java文件编译成.class文件。
程序初始化执行顺序
Java程序初始化工作可以在许多不同的代码块中来完成,它们的执行顺序如下:
父类的静态变量、父类的静态代码块、子类的静态变量、子类的静态代码块、父类的非静态变量、父类的非静态代码块、父类的构造函数、子类的非静态变量、子类的非静态代码块、子类的构造函数。
静态内部类不可以直接访问外围类的非静态数据,而非静态内部类可以直接访问外围类的数据,包括私有数据。
JVM堆内存设置
JVM堆内存分为2块:Permanent Space 和 Heap Space。
[if !supportLists]ü[endif]Permanent 即持久代(Permanent Generation),主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大。
[if !supportLists]ü[endif]Heap = { Old + NEW = {Eden,
from, to} },Old 即年老代(Old Generation),New 即年轻代(Young Generation)。年老代和年轻代的划分对垃圾收集影响比较大。
年轻代
所有新生成的对象首先都是放在年轻代。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代一般分3个区,1个Eden区,2个Survivor区(from 和 to)。
大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当一个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当另一个Survivor区也满了的时候,从前一个Survivor区复制过来的并且此时还存活的对象,将可能被复制到年老代。
2个Survivor区是对称的,没有先后关系,所以同一个Survivor区中可能同时存在从Eden区复制过来对象,和从另一个Survivor区复制过来的对象;而复制到年老区的只有从另一个Survivor区过来的对象。而且,因为需要交换的原因,Survivor区至少有一个是空的。特殊的情况下,根据程序需要,Survivor区是可以配置为多个的(多于2个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
针对年轻代的垃圾回收即 Young GC。
年老代
在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
针对年老代的垃圾回收即 Full GC。
持久代
用于存放静态类型数据,如 Java Class, Method 等。持久代对垃圾回收没有显著影响。但是有些应用可能动态生成或调用一些Class,例如 Hibernate CGLib 等,在这种时候往往需要设置一个比较大的持久代空间来存放这些运行过程中动态增加的类型。
结论
所以,当一组对象生成时,内存申请过程如下:
JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域。当Eden区空间足够时,内存申请结束。否则执行下一步。
JVM试图释放在Eden区中所有不活跃的对象(Young GC)。释放后若Eden空间仍然不足以放入新对象,JVM则试图将部分Eden区中活跃对象放入Survivor区。
Survivor区被用来作为Eden区及年老代的中间交换区域。当年老代空间足够时,Survivor区中存活了一定次数的对象会被移到年老代。
当年老代空间不够时,JVM会在年老代进行完全的垃圾回收(Full GC)。
Full GC后,若Survivor区及年老代仍然无法存放从Eden区复制过来的对象,则会导致JVM无法在Eden区为新生成的对象申请内存,即出现“Out of Memory”。
OOM(“Out of Memory”)异常一般主要有如下2种原因:
1. 年老代溢出,表现为:java.lang.OutOfMemoryError:Javaheapspace
这是最常见的情况,产生的原因可能是:设置的内存参数Xmx过小或程序的内存泄露及使用不当问题。
例如循环上万次的字符串处理、创建上千万个对象、在一段代码内申请上百M甚至上G的内存。还有的时候虽然不会报内存溢出,却会使系统不间断的垃圾回收,也无法处理其它请求。这种情况下除了检查程序、打印堆内存等方法排查,还可以借助一些内存分析工具,比如MAT就很不错。
2. 持久代溢出,表现为:java.lang.OutOfMemoryError:PermGenspace
通常由于持久代设置过小,动态加载了大量Java类而导致溢出,解决办法唯有将参数 -XX:MaxPermSize 调大(一般256m能满足绝大多数应用程序需求)。将部分Java类放到容器共享区(例如Tomcat share lib)去加载的办法也是一个思路,但前提是容器里部署了多个应用,且这些应用有大量的共享类库
synchronized、volatile、serialize、static关键字
synchronized关键字:同步代码块关键字,对对象加互斥锁。
volatile关键字:用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。然而,在访问volatile变量时不会执行加锁操作,因此也不会执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制。
serialize关键字:Java 对象序列化为二进制文件。
static关键字: static关键字可以修饰变量,方法,静态代码块。
静态变量:由static修饰的变量称为静态变量;静态变量属于类,而不属于某个对象;静态变量它的副本只有一个(静态变量在类中只加载一)。
静态方法:在静态方法中只能调用静态变量和静态方法;在非静态方法中,可以调用静态方法或者变量。在静态方法中不能使用this和super关键字。
静态代码块:用来给静态成员变量初始化。
jsp中静态include和动态include
动态include用jsp:include动作实现<jsp:include page=”included.jap” flush=”true”/>,它总是会检查所含文件中的变化,适用于包含动态页面,并且可以带参数。各个文件分别先编译,然后组成一个文件。即动态include的结构是两者独立,直到输出时才合并。
静态include用include伪码实现<%@include file=”included.html”%>,定不会检查所含文件的变化,适用于包含静态页面。它是先将文件的代码原封不动地加入到主页面从而合成一个文件,然后再进行翻译,此时不允许有不相同的变量。
动态include和静态include的区别:
1.执行时间上
静态include:<%@include file=”included.html”%>是在翻译阶段执行;
动态include:<jsp:include page=”included.jap” flush=”true”/>在请求处理阶段执行。
2.引入内容不同
静态include:<%@include file=”included.html”%>引入静态文本(html.jsp),在jsp页面