浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象,换而言之,浅拷贝仅仅复制所考虑的对象,而不复制它引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而哪些引用其他对象的变量将指向被复制的新对象。而不是原有的哪些被引用的对象。换而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
(1)被final修饰的类不可以被继承
(2)被final修饰的方法不可以被重写
(3)被final修饰的变量不可以被改变,如果修饰引用,那么表示引用不可变,引用指向的内容可以变。
(4)被final修饰的方法,JVM会尝试将其内联,以提高运行效率。
(5)被final修饰的常量,在编译阶段会存入常量池中。
除此之外,编译器对final域要遵守两个重排序规则:
在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序,初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
所有的人都知道static关键字这两个基本的用法:静态变量和静态方法。也就是被static锁修饰的变量/方法都属于类的静态资源,类实例所共享。
除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作:
public class PreCache{
static{
//执行相关操作
}
}
此外static也多用于修饰内部类,此时称之为静态内部类。
最后一种用法就是静态导包,即import static.import static是在JDK1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需要使用类名,可以直接使用资源名,比如:
fasle,因为有浮点数不能完全精确地表示出来
+=操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换。如:
int a = 127;
byte b = 127;
b = a + b;
b = a + b; //会报编译错误:cannot convert from int ot byte
b += a;
以下代码是否有错,有的话怎么改?
有错误,因为short类型在进行运算时会自动提升为int类型,也就是说s1 + 1的运算结果是int类型,而s1是short类型,此时编译器会报错。
正确写法:
short s1 = 1;
s1 += 1;
+=操作符会对右边的表达式结果强转匹配左边的数据类型,所以没错。
执行,并且finally的执行要早于try里面的return
结论:
1.不管有没有出现异常,finally块中代码库都会执行
2.当try和catch中有return时,finally仍会执行
3.finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前运算的。
Java可抛出(Throwable)的结构分为三种类型:被检查的异常(CheckedException),运行时异常(RuntimeException),错误(Error)。
(1)运行时异常
定义:RuntimeException及其紫烈都被称为运行时异常。
特点:Java编译器不会检查它,已解释说,当程序中可能出现这类异常时,倘若“没有通过throws声明抛出它”,也没有使用try catch捕获它,它还是会编译通过。例如,除数为零时产生的ArithmeticException异常,数组越界时产生的IndexDoutOfBoundsException异常,fail-fast机制产生ConcurrentModificationException异常(java.util包下面的所有集合类都是快速失败的,"快速失败"就是fial-fast,它是java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast,它是java集合的一种错误检测机制。记住这里是有可能,而不是一定。例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出ConcurrentModificationException异常,从而产生fail-fast机制,这个错误叫并发修改异常。
Fail-safe,java.util.concurrent包下面的所有的类都是安全失败的,在遍历过程中,如果已经遍历的数组的内容发生了变化,迭代器就不会抛出ConcurrentModificationException异常。如果未遍历的数组上的内容发生了变化,则有可能反映到迭代过程中,这就是ConcurrentHashMap迭代器弱一致的表现。ConcurrentHashMap的弱一致性主要是为了提升效率,是一致性与效率之间的一种权衡。要称为强一致性,就得到处使用锁,甚至是全局锁,这就与HashTable和同步的HashMap一样了。)等,都属于运行时异常。
常见的五种运行时异常:
ClassCastException(类转换异常)
IndexOutOfBoundsException(数组越界)
NullPointException(空指针异常)
ArrayStoreException(数据存储异常,操作数据是类型不一致)
BufferOverflowException(异常堆栈)
(2)被检查异常
定义:Exception类本身,以及Exception的子类中除了“运行时”异常之外的其他子类都属于被检查异常。
特点:Java编译器会检查它。此类异常,要么通过throws进行声明抛出,要么通过try-catch进行不过处理,否则不能通过编译。例如,CloneNotSupportedException就属于被检查异常,当通过clone()接口去克隆一个对象,而该对象对应的类没有实现Cloneable接口,就会抛出CloneNotSupportedException异常。被检查异常通常都是可以恢复的。如:
IOException
FileNotFoundException
SQLException
被检查异常适用于那是不是因程序引起的错误情况,比如:读取文件时文件不存在引发的FileNotFoundException。然而,不被检查的异常通常都是由于糟糕的编程引起的,比如:在对象引用时没有确保对象非空而引起的NullPointException。
(3)错误
定义:Error类及其子类
特点:和运行时异常一样,编译器也不会对错误进行检查
当资源不足、约束失败、或是其他程序无法继续运行的条件发生时,就会产生错误。程序本身无法修复这些错误。例如,VirtualMachineError就属于错误。出现这种错误会导致程序终止运行。OutOfMemoryError、ThreadDeath。
Java虚拟机规范规定的JVM的内存分为了好几块,比如堆、栈、程序计数器、方法区等。
OOM:
(1)OutOfMemoryError异常
除了程序计数器外,寻觅及内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能。
Java Heap溢出:
一般的异常信息:java.lang.OutOfMemoryError:java heap spacess。
java堆用于存储对象实例,我们只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。
出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄露(Memory Leak)还是内存溢出(Memory Overflow)。
如果是内存泄露,可以进一步通过工具查看泄露对象到GCRoots的引用链。于是就能找到泄露对象是通过怎样的路径于GC Roots相关联并导致垃圾收集器无法自动回收。
如果不存在内存泄露,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。
内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露似乎不会有太大的影响,但内存泄露堆积后的后果就是内存溢出。
内存溢出:指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,你却用来存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
(2)虚拟机和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
这里需要注意当栈的大小越大可分配到的线程数就越小。
(3)运行时常量池溢出
异常信息:java.lang.OutOfMemoryError:PermGenspace
如果要想运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。改方法的作用作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。
(4)方法区溢出
方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。也有可能是方法区中保存的class对象没有被及时回收或者class信息占用的内存超过了我们的配置。
异常信息:
java.lang.OutOfMemoryError:PermGenspace
方法区的溢出也是一种常见的内存溢出异常,一个类如果要被垃圾回收器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。
SOF(堆栈溢出StackOverflow):
StackOverflowError的定义:当应用程序递归太深而发生堆栈溢出时,抛出该错误。
因为栈一般默认为1-2m,一旦出现死循环或者大量的递归调用,在不断地压栈过程中,造成栈容量超过1m而导致溢出。
栈溢出的原因:递归调用,大量循环或者死循环,全局变量是否过多,数组、List、map数据过大。
线程与进程相似,但线程是比进程更小的执行单位。一个进程在执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或者是在各个线程之间切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
程序是含有指令和数据的文件,被存储在磁盘或在其他的数据存储设备中,也就是说程序是静态的代码。