一、关键字
final
1. 数据
声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
- 对于基本类型,final 使数值不变;
- 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
final int x=1; // x=2;cannot assign a value to final variable 'x' final Inner inner = new Inner(); inner.age=12;
2. 方法
声明方法不能被子类重写。
private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。
3. 类
声明类不允许被继承。
finnaly
catch可以有多个,每个处理不同的异常,finally可以没有也可以有一个,如果没有catch,必须有finally。
try和catch中有return时,finally里面的语句也会执行,而且finally语句在return语句执行之后return返回之前执行的。可以使用编译器的Debug功能查看详细过程。
当在finally块中使用return、throw时,编译器不会再对try、catch块中的非运行时异常进行检查,JVM不会再去捕获try块、catch块中的异常,程序的输出以finally块为准,即finally块的返回值或者finally块中抛出的异常。
当在try块或catch块中遇到return语句时,finally块将在方法返回之前被执行。finally块中的return语句会覆盖try块、catch块中的return语句。合理的做法是在 finally 块之后使用return语句。
public static int test() {
try {
int a = 8 / 0;
return 1;
} catch (Exception e) {
return 2;
} finally {
System.out.println("finally模块被执行");
return 3;
}
}
public static void main(String[] args) {
int test = test();
System.out.println(test);
}
结果为3;
有两种情况finally不会执行
-
在某些情况下,try语句压根就没有执行到,那么finally语句也一定就不会执行到了。
-
还有一种情况就是在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。
finalize()方法
inalize方法是Object提供的的实例方法,使用规则如下:
当对象不再被任何对象引用时,GC会调用该对象的finalize()方法
finalize()是Object的方法,子类可以覆盖这个方法来做一些系统资源的释放或者数据的清理
可以在finalize()让这个对象再次被引用,避免被GC回收;但是最常用的目的还是做cleanup
Java不保证这个finalize()一定被执行;但是保证调用finalize的线程没有持有任何user-visible同步锁。
在finalize里面抛出的异常会被忽略,同时方法终止。
当finalize被调用之后,JVM会再一次检测这个对象是否能被存活的线程访问得到,如果不是,则清除该对象。也就是finalize只能被调用一次;也就是说,覆盖了finalize方法的对象需要经过两个GC周期才能被清除。
static
1. 静态变量
- 静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
- 实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
方法内部不能添加static关键字(静态非静态方法都不可以,编译不通过)
局部变量保存在栈中,为静态变量保存在方法区中,局部变量出了方法就被栈回收了
而静态变量不会,所以在局部变量前不能加static关键字
public class A {
private int x; // 实例变量
private static int y; // 静态变量
public static void main(String[] args) {
// int x = A.x; // Non-static field 'x' cannot be referenced from a static context
A a = new A();
int x = a.x;
int y = A.y;
}
}
2. 静态方法
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
public abstract class A {
public static void func1(){
}
// public abstract static void func2(); // Illegal combination of modifiers: 'abstract' and 'static'
}
只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。
public class A {
private static int x;
private int y;
public static void func1(){
int a = x;
// int b = y; // Non-static field 'y' cannot be referenced from a static context
// int b = this.y; // 'A.this' cannot be referenced from a static context
}
}
3. 静态语句块
静态语句块在类初始化时运行一次。
public class A {
static {
System.out.println("123");
}
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
}
}
123
4. 静态内部类
非静态内部类依赖于外部类的实例,而静态内部类不需要。
public class OuterClass {
class InnerClass {
}
static class StaticInnerClass {
}
public static void main(String[] args) {
// InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
OuterClass outerClass = new OuterClass();
InnerClass innerClass = outerClass.new InnerClass();
StaticInnerClass staticInnerClass = new StaticInnerClass();
}
}
静态内部类不能访问外部类的非静态的变量和方法。
5. 静态导包
在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。
import static com.xxx.ClassName.*
6. 初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
public static String staticField = "静态变量";
static {
System.out.println("静态语句块");
}
public String field = "实例变量";
{
System.out.println("普通语句块");
}
最后才是构造函数的初始化。
public InitialOrderTest() {
System.out.println("构造函数");
}
存在继承的情况下,初始化顺序为:
- 父类(静态变量、静态语句块)
- 子类(静态变量、静态语句块)
- 父类(实例变量、普通语句块)
- 父类(构造函数)
- 子类(实例变量、普通语句块)
- 子类(构造函数)
assert断言
两种用法(需要开启断言检查 开关-enableassertions或-ea来开启。javac -ea 类名.java,或在ide中VM参数添加-ea)
public static void main(String[] args) {
//断言1结果为true,则继续往下执行
assert true;
System.out.println("断言1没有问题,Go!");
System.out.println("\n-----------------\n");
//断言2结果为false,程序终止
assert false : "断言失败,此表达式的信息将会在抛出异常的时候输出!";
System.out.println("断言2没有问题,Go!");
}
Throw和Throws的区别
Throw:
作用在方法内,表示抛出具体异常,由方法体内的语句处理。
具体向外抛出的动作,所以它抛出的是一个异常实体类。若执行了Throw一定是抛出了某种异常。
Throws:
作用在方法的声明上,表示如果抛出异常,则由该方法的调用者来进行异常处理。
主要的声明这个方法会抛出会抛出某种类型的异常,让它的使用者知道捕获异常的类型。
出现异常是一种可能性,但不一定会发生异常。
1. 区别
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型。
2.分别介绍
throws:用于声明异常,例如,如果一个方法里面不想有任何的异常处理,则在没有任何代码进行异常处理的时候,必须对这个方法进行声明有可能产生的所有异常(其实就是,不想自己处理,那就交给别人吧,告诉别人我会出现什么异常,报自己的错,让别人处理去吧)。
格式是:方法名(参数)throws 异常类1,异常类2,.....
throw:就是自己进行异常处理,处理的时候有两种方式,要么自己捕获异常(也就是try catch进行捕捉),要么声明抛出一个异常(就是throws 异常~~)。
注意:
throw一旦进入被执行,程序立即会转入异常处理阶段,后面的语句就不再执行,而且所在的方法不再返回有意义的值!