近期做牛客网的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
*/