标签:
本系列博文主要收录Java中一些常见的但是平常又容易忘记、记错或者记混的知识点的集合。各个知识点之间没有必然的联系,可以随意跳着看,希望能够对各位同学有所帮助。
本博文持续更新、修改,转载请保留原文链接。
堆和栈都是内存的一部分,有着不同的作用,而且一个程序需要在这片区域上分配内存。众所周知,所有的JAVA程序都运行在JVM上,这里所说的自然是JVM中的堆和栈。
最主要的区别就是栈内存用来存储局部变量和方法调用。而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存在。
栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的遍历只能在其所属线程中可见,即栈内存可以理解成线程的私有内存,而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError;如果堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError.
栈的内存要远远小于对内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。你可以通过-Xss选项设置栈内存的大小,-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。
一般入口方法:public static void main(String args[])。即必须有public与static修饰,返回值为void,且方法的参数为字符串数组。
public static没有先后顺序关系,这样static public void main(String args[])也是合理的,或者加入final:public static final void main(String args[])或者加入synchronized:public static synchronized void main(String args[])也可以。不管哪种定义方式,都必须保证main()方法的返回值为void,并有static和public关键字修饰。同时由于mian()方法为程序的入口方法,因此不能用abstract关键字来修饰。
父类静态变量、父类静态代码块、子类静态边框、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数。
在Java中,有些接口内部没有声明任何方法,也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口就是标识接口。标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识的作用,用来表明它的类属于一个特定的类型。Java中的标识接口有:RandomAccess, Cloneable, java.io.Serializable等(欢迎在留言区留言添加)。在使用时经常用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。
构造函数不能被继承,因此,它不能被覆盖,但是构造函数能够被重载,可以使用不同的参数个数或参数类型来定义多个构造函数。子类可以通过super关键字来显示地调用父类的构造函数,当父类没有提供无参数的构造函数时,子类的构造函数必须显示地调用父类父类的构造函数。
当父类和子类都没有定义构造函数时,编译器会为父类生成一个默认的无参数的构造函数,给子类也生成一个默认的无参数的构造函数。此外,默认构造器的修饰符只能当前类的修饰符有关。譬如,如果一个类被定义为public,那么它的构造函数也是public。
封装、继承、多态、抽象
重载:重载是通过不同的方法参数来区分的,例如不同的参数个数、不同的参数类型或不同的参数顺序;不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载;对于继承来说,如果基类方法的访问权限为private,那么就不能再派生类对其重载;如果派生类也定义了一个同名的函数,这只是一个新的方法,不会达到重载的效果。
重写:派生类的覆盖方法必须要和基类中被覆盖方法有相同的函数名和参数;派生类的覆盖方法的返回值必须和基类中被覆盖方法的返回值相同;派生类中的覆盖方法所抛出的异常必须和基类(或其子类)被覆盖的方法所抛出的异常一致;基类中被覆盖的方法不能为private,否则器子类只是定义了一个方法,并没有对其覆盖。
区别:重写是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系;重写只能由一个方法或只能由一对方法产生关系,重载是多个方法之间的关系;重写要求参数列表相同,重载要求参数列表不同;重写关系中,调用方法体是根据对象的类型来决定,而重载关系是根据调用时的实参数与形参表来选择方法体。
抽象类:只要包含一个抽象方法的类就必须被声明为抽象类,抽象类可以声明方法的存在而不去实现它,被声明为抽象的方法不能包含方法体。抽象类的子类为父类中的所有抽象方法提供具体的实现,否则它们也是抽象类。抽象类的成员变量默认为default,当然也可以被定义为private, protected和public,抽象类中的抽象方法不能用private, static, synchronized, native等修饰,同时方法必须以分号结尾,并且不带花括号。
接口: 接口中定义的成员变量默认为public static final,只能够有静态的不能被修改的数据成员,而且必须给其赋值;其所有成员方法都是public, abstract的,而且只能被这两个关键字修饰。
1)调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
2)super()和this()类似,区别是,super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
3)super()和this()均需放在构造方法内第一行。
4)尽管可以用this调用一个构造器,但却不能调用两个。
5)this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
6)this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
7)从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
详细参考《Java中this()和super()的注意点》
只能由字母(a-z, A-Z)、数字(0-9)、下划线(_)和
final:用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖和类不可继承。
finally:作为异常处理的一部分,它只能用在try-catch语句中,并且附带一个语句块表示这段语句最终一定被执行,经常被用在需要释放资源的情况下。
finalize:Object类的一个方法,在垃圾回收器执行时会调用被回收对象的finalize()方法,可以覆盖此方法来实现对其他资源的回收,例如关闭文件等,需要注意的是,一旦垃圾回收器准备好释放对象占用的空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
在Java中,基本数据类型包括:byte(1B), int(4B), char(2B), long(8B), short(2B), float(4B), double(8B), boolean(1B)。默认声明的小数是double类型的,因此对float类型的变量进行初始化时需要进行类型转换。float类型的变量由两种初始化方法:float f=1.0f 或float f=(float)1.0。于此类似的是,直接写的整型数字是int类型的,如果在给数据类型为long的变量直接赋值时,int类型的值无法表示一个非常大的数字,因此,在复制时可以通过这种方法:long l = 2313091390L。
当参与运算的两个变量的数据类型不同时,就需要进行隐式的数据类型转换,转换的规则为:从低精度向高精度转换,即优先级满足byte
short s1=1;
s1=s1+1;
由于在运行时会首先将s1转换成int类型,因此s1+1的结果为int类型,这样编译器会保存,所以正确的写法应该是:shoet s1=1; s1=(short)(s1+1);。
有一种例外情况。“+=”为java规定的运算符,编译器会对其做特殊处理,因此语句:
short s1=1; s1+=1;
能编译通过。
优先级 | 运算符 |
---|---|
1 | . () [] |
2 | +(正) -(负) ++ – ~ ! |
3 | * / % |
4 | +(加) -(减) |
5 | << >> >>> |
6 | < <= > >= instanceof |
7 | == != |
8 | & |
9 | | |
10 | ^ |
11 | && |
12 | || |
13 | ?: |
14 | = += -= *= /= %= &= |= ^= ~= <<= >>= >>>= |
在实际使用时,如果不确定运算符的优先级,最好运用括号运算符来控制运算顺序。
例题(运算结果为0):
byte a=5;
int b=10;
int c=a>>2 + b>>2;
System.out.println(c);
StringBuilder非线程安全,StringBuffer是线程安全的。在执行效率方面,StringBuilder最高,StringBuffer次之,String最低。一般而言,如果要操作的数据量较小,应优先使用String类;如果是在单线程下操作大量数据,应优先使用StringBuilder类,如果是在多线程下操作大量数据,应优先考虑StringBuilder类。StringTokenizer是用来分割字符串的工具类。
问题描述:try{}里有一个return语句,那么紧跟在这个try后的finally{}中的代码是否会被执行?如果会,什么时候执行,在return之前还是return之后?
案例1:
static int method3()
{
try
{
return 1;
}
catch(Exception e)
{
return 0;
}
finally
{
System.out.println("method3 finally");
return 3;
}
}
如果在main()函数中运行System.out.println(method3());的结果为:method3 finally 3
由上可知,当finally块中有return语句时,将会覆盖函数中其他的return语句。
再看案例2:
static int method4()
{
int result = 1;
try{
result=2;
return result;
}
catch(Exception e){
return 0;
}
finally{
result = 3;
System.out.println("method4 finally");
}
}
static String method5()
{
StringBuffer s = new StringBuffer("Hello");
try
{
return s.toString();
}
catch(Exception e){
return null;
}
finally{
s.append(" World");
System.out.println("method5 finally");
}
}
在入口函数中运行:
System.out.println(method4());
System.out.println(method5());
输出:
method4 finally
2
method5 finally
Hello
程序在执行到return时首先将返回值存储在一个指定的位置,其次去执行finally块,最后再返回。
出现在Java程序中的finally块是不是·会被执行?不一定!来看两个例子:
案例3:
static void method6()
{
int i=5/0;
try{
System.out.println("1");
}catch(Exception e){
System.out.println("2");
}finally{
System.out.println("3");
}
}
运行结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at test.TestTest.method6(TestTest.java:80)
at test.TestTest.main(TestTest.java:96)
当程序在进入try语句块之前就出现异常时,会直接借宿,不会执行finally块中的代码。
案例4:
static void method7(){
try{
System.out.println("1");
System.exit(0);
}catch(Exception e){
System.out.println("2");
}finally{
System.out.println("3");
}
}
运行结果:1
当程序在try块中强制退出时也不会去执行finally块中的代码。
检查式异常:我们经常遇到的IO异常及sql异常就属于检查式异常。对于这种异常,java编译器要求我们必须对出现的这些异常进行catch 所以 面对这种异常不管我们是否愿意,只能自己去写一堆catch来捕捉这些异常。
JDK1.7中有(部分):
运行时异常:我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。
详细请参考《JAVA运行时异常及检查式异常》
参考资料:
1. Java中this()和super()的注意点
2. JAVA运行时异常及检查式异常
标签:
原文地址:http://blog.csdn.net/u013256816/article/details/51437272