近期做牛客网的Java开发笔试题,发现这类型的题目较多,很容易混淆,特将相关概念和相关示例整理如下,供大家参考^_^
1. 静态代码块在类加载时即运行,而且只运行一次,并且优先于各种代码块以及构造函数运行。如果一个类中有多个静态代码块,会按照书写顺序依次执行。静态代码块不能访问普通变量(普通变量只能通过对象来调用)。
2. 构造代码块在创建对象时被调用,每次创建对象都会调用一次,但是优先于构造函数执行。如果不实例化对象,构造代码块不会执行。如果存在多个构造代码块,则执行顺序按照代码顺序依次执行(多个构造函数情况下,创建对象时传入的参数不同则初始化对应的构造函数)。
格式如下:
public class StaticTest {
static //静态代码块
{
System.out.println("静态代码块");
}
{//构造代码块
System.out.println("构造代码块");
}
}
3.构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用;而一般的方法是在程序执行到它的时候被调用的;当定义一个类的时候,通常情况下都会显示该类的构造函数,并在函数中指定初始化的工作也可省略,不过Java编译器会提供一个默认的构造函数,此默认构造函数是不带参数的。一般的方法则不具有这一特点。
格式如下:
public class test
{
public test()
{
System.out.println("无参构造方法");
}
public test(String a)
{
System.out.println("有参构造方法");
}
.....
}
程序执行顺序:静态代码块>构造代码块>构造函数>普通代码块
对象的初始化顺序:
1)首先执行父类静态的内容;
2)接着执行子类的静态的内容;
3)执行父类构造代码块;
4)执行父类的构造方法;
5)执行子类构造代码块;
6)执行子类的构造方法。
总结:静态代码块内容先执行(先父类,再子类),接着执行父类构造代码块和构造方法,之后执行子类构造代码块和构造方法。
示例如下:
public class StaticTest
{
public static void main(String args[])
{
staticFunction();
}
static StaticTest st = new StaticTest();
static //静态代码块
{
System.out.println("1");
}
StaticTest() //构造函数
{
System.out.println("3");
System.out.println("a="+a+" b="+b);
}
public static void staticFunction()
{
System.out.println("4");
}
{ //构造代码块
System.out.println("2");
}
int a=100;
static int b=112;
}
输出结果:
2
3
a=100 b=0
1
4
解析:类初始化时首先初始化静态内容(静态变量,静态代码块,按顺序执行)。静态引用变量st (static StaticTest st = new StaticTest();)引用的是本类的实例,因此在实例化st变量时,将实例初始化嵌入到静态初始化中。因为这一句放在静态初始化的开头,所以static int b=112没有被调用,输出的b=0,同时,输出1也在2和3后面。在对象实例化时,即为普通成员变量分配内存,再执行构造函数,所以a的值为100。
public class Test {
private int number=0;
static{
System.out.println("静态代码块执行!");
}
{
System.out.println("构造代码块执行!");
number=1;
}
public Test(){
System.out.println("构造方法执行!");
System.out.println(number);
}
public static void main(String[] args) {
System.out.println("---------");
Test test = new Test();
System.out.print("number is: "+test.number);
}
}
运行结果:
静态代码块执行!
---------
构造代码块执行!
构造方法执行!
1
number is: 1
解析:类初始化过程中,首先初始化静态内容(静态变量,静态代码块,并按顺序执行)。静态代码块先执行,输出“静态代码块执行!”。接着执行静态方法main中的内容,所以输出“---------”,对象实例化的时候,首先执行构造代码块,再执行构造函数,依次输出里面的内容。
public class JDTest01 {
public static void main(String[] args)
{
System.out.println(Test2.a);
}
}
class Test2
{
public static final String a = new String("JD");
static
{
System.out.print("OK");
}
}
/*输出结果:
OKJD
*/
public class JDTest02 {
public static void main(String[] args)
{
System.out.println("A");
new JDTest02();
new JDTest02();
}
public JDTest02()
{
System.out.println("B");
}
{
System.out.println("C");
}
static
{
System.out.println("D");
}
}
/*输出结果:
DACBCB
*/
4.static的作用:
一些频繁使用的内容,如果每次使用都重新new一下,这个开销可能会很高,如果使用static,将会一直放在内存中,想用直接调用即可,无需重新new一块空间初始化数据。那么static就是为了实现一个系统的缓存作用,其生命周期直到应用程序退出结束。
这说明,static修饰的类成员,在程序运行过程中,只需要初始化一次即可,不会进行多次的初始化。
主要有四种用法:
1).用来修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享;
2).用来修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类;
3).静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键;
4).静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便。
static可以修饰:方法,属性,代码段,内部类(静态内部类或嵌套内部类)
5.final主要四种用法
1). 用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,我们必须在声明时或者构造方法中对它赋值;
2). 用来修饰方法参数,表示在变量的生存期中它的值不能被改变;
3). 修饰方法,表示该方法无法被重写;
4). 修饰类,表示该类无法被继承。
final可以修饰:属性,方法,类,局部变量(方法中的变量)
Static final:同时使用static和final修饰的成员在内存中只占据一段不能改变的存储空间。
6.成员变量与局部变量的区别
1).在类中位置不同;成员变量:在类中方法外。局部变量:在方法定义中或者方法声明上。
2).在内存中的位置不同;成员变量:在堆内存。 局部变量:在栈内存。
3).生命周期不同;成员变量:随着对象的创建而存在,随着对象的消失而消失。 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失。
4).初始化值不同;成员变量:有默认值初始化。局部变量:没有默认值初始化,必须定义,赋值,然后才能使用。
另外,局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
public class JDTest03 {
public static void main(String[] args)
{
System.out.println(B.c);//直接使用类名调用静态变量
}
}
class A
{
static
{
System.out.print("A");
}
}
class B extends A
{
static
{
System.out.print("B");
}
public final static String c = "C";
}
/*
输出结果:
C
*/