Java SE 024 static与final使用陷阱 续

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

Java SE 024 static与final使用陷阱 续

1.final成员变量赋初值

public class FinalTest4{
    
    
    final int a;
}

(1)对于一个一般的成员变量来说,如果我们没有给它赋初值,那么它的默认值就取0;

(2)但是对于一个final类型的变量来说,我们必须要显示的给它赋初值。

(3)因为对于普通的成员变量来说,如果我们不给它赋初值,我们后面还有机会给它赋

(4)对于final类型,如果不给它赋初值,就没有机会在后面赋值了。所以必须显示的赋初值。

1.1常量赋初值

public class FinalTest4{
    
    
    final int a=0;
}

1.2可以通过构造方法显示的赋初值

public class FinalTest4{
    
    
	final int a;
	public FinalTest4(){
    
    
    	a = 0;
	}
}

1.3 两个构造方法 编译通不过

public class FinalTest4{
    
    
    final int a;
    public FinalTest4(){
    
    
        a = 0;
    }
    public FinalTest4(int a){
    
    

    }
}

(1)当我构造对象的时候,到底是使用第一个构造方法,还是使用第二个构造方法,是由我来指定的,如果使用第一个构造方法,没问题,它已经被赋上初值,如果使用第二个构造方法,a没有赋上初值,因此就会提示“可能尚未初始化变量a”

1.4小结:

(1)对于final类型的成员变量来说,它的赋值方式有两种,第一种是在声明的时候直接给它赋上值。

(2)第二种方式是在声明的时候不给它赋值,并且在这个类的所有的构造方法里面都要给个成员变量赋上初值。

public class FinalTest4{
    
    
    final int a;
    public FinalTest4(){
    
    
        a = 0;
    }
    public FinalTest4(int a){
    
    
        this.a = a;//都会给a赋上值。
    }
}

1.5对于final类型成员变量,一般来说有两种赋初值方式

(1)在声明final类型的成员变量时就赋上初值。

(2)在声明final类型的成员变量时不赋上值,但在类的所有构造方法中都为其赋上初值。

2.static静态代码块

public class StaticTest4{
    
    
	public static void main(String [] args){
    
    
		P p = new P();
	}
}

class P{
    
    
	static {
    
    
		System.out.println("static block");
	}

	public P(){
    
    
		System.out.println("P constructor");
	}
}

解说:
(1)静态代码块是先于构造方法执行的

  • 这个为什么会存在这种情况呢,因为静态代码块的执行时机是,当你定义好一个类之后,这个类会生成一个Class文件放在硬盘上,然后当我们执行的时候,会先加载到java虚拟机上,接着由java虚拟机再去处理它,由它去生成对象。

  • 当从硬盘将class文件加载到java虚拟机上的时候,这个static代码块就已经去执行了

  • 而构造方法是什么时候执行呢?

是在生成对象的时候才去执行的。刚把class文件加载到java虚拟机上,这个时候还没生成对象,所以构造方法后执行。因为它是要生成对象的时候,它才会执行。

  • 而静态代码块加载的时候就会去执行。
public class StaticTest4{
    
    
	public static void main(String [] args){
    
    
		P p = new P();
		P p2 = new P();
	}
}

class P{
    
    
	static {
    
    
		System.out.println("static block");
	}

	public P(){
    
    
		System.out.println("P constructor");
	}
}

执行结果:
在这里插入图片描述

(1)两个P contructor好理解,因为生成了两个对象,而静态代码块儿中的代码为什么只出现一次呢?

因为类加载的时候只需要加载一次就够了。

public class StaticTest4{
    
    
	public static void main(String [] args){
    
    
		new S();
	}
}

class P{
    
    
	static {
    
    
		System.out.println("static block");
	}

	public P(){
    
    
		System.out.println("P constructor");
	}
}

class Q extends P{
    
    
	static {
    
    
		System.out.println("Q static block");
	}

	public Q(){
    
    
		System.out.println("Q Contructor");
	}
}

class S extends Q{
    
    
	static {
    
    
		System.out.println("S static block");
	}

	public S(){
    
    
		System.out.println("S constructor");
	}
}

执行结果:
在这里插入图片描述
先是最上层的静态代码块,即在类进行加载的时候,会先去找父类的静态代码块,父类的有了再去找子类的代码块,依次循环下去。

2.1.小结

(1)静态代码块也是完成一些初始化工作。

  • 首先执行静态代码块,然后执行构造方法。
  • 静态代码块在类被加载的时候执行,而构造方法是在生成对象的时候执行.
  • 要想调用某个类来生成对象,首先需要将类加载到java虚拟机上(JVM),然后由JVM加载这个类来生成对象。

(2)类的静态代码块只会执行一次

  • 是在类被加载的时候执行的,因为每个类只会加载一次,所以静态代码块也只会被执行一次;
  • 而构造方法则不然,每次生成一个对象的时候都会调用类的构造方法,所以new一次就会调用构造方法一次。

(3)如果继承体系中既有构造方法,又有静态代码块,那么首先执行最顶层的类的静态代码块,一直执行到最底层类的静态代码块,然后再去执行最顶层类的构造方法,一直执行到最底层类的构造方法。

注意静态代码块只会执行一次。

3.静态方法访问非静态成员变量

3.1不能在静态方法里面访问非静态的成员变量。

public class StaticTest5{
    
    
	public static void main(String [] args){
    
    
		W.change();
	}	
}

class W{
    
    
	int a = 10;
	public static void change(){
    
    
		a++;
	}
}

3.1.1为什么不能访问:

(1)change()方法是一个静态方法,可以通过类的名字去调用,没有使用任何一个对象的引用去调用。

(2)假如说当前代码是可以的,可以在静态方法里面访问非静态的成员变量,那么一调用change()方法,就将a变成++了。

(3)a是一个非静态的成员变量,每一个对象都会有一个a,那么a++改的是哪一个对象上的a呢?

找到一个理由就能证明这个是矛盾的,是ok的。

(4)所以不能在静态的方法里面去访问非静态的成员变量。

3.2.静态方法可以访问静态的成员变量

public class StaticTest5{
    
    
	public static void main(String [] args){
    
    
		W.change();
	}
}

class W{
    
    
	static int a = 10;
	public static void change(){
    
    
		a++;
	}
}

为什么可以访问?

因为静态成员变量只有一个,即便是通过类来改,改的还是那一个,不管哪一个对象引用都是引用的那一个,这是没问题的。所以静态的方法可以改变静态的成员变量。

public class StaticTest5{
    
    
	public static void main(String [] args){
    
    
		W w = new W();
		w.change();
	}
}

class W{
    
    
	static int a = 10;
	public void change(){
    
    
		a++;
	}
}

此段代码执行成功:为什么?

因为虽然change()是一个非静态的方法,要通过对象去调用,不管通过哪个对象,改的还是唯一的一份儿。

3.3小结

(1)静态的访问静态的,非静态的什么都可以访问。

  • 不能在静态方法中访问非静态成员变量。
  • 可以在静态方法中访问静态的成员变量。
  • 可以在非静态的方法中访问静态的成员变量。
public class StaticTest5{
    
    
	public static void main(String [] args){
    
    
		W w = new W();
		w.change();
	}
}

class W{
    
    
	static int a = 10;
	public static void change(){
    
    
		this.a++;
	}
}

(1)this也是一个非静态的变量。

(2)this表示对当前对象的一个引用,换句话说一定要有一个对象,如果我直接调用这个方法的时候,我可以通过类来去调用,没有对象,那么this是谁呢?判断不出来,所以以上代码也不对。

StaticTest5{
public static void main(String [] args){
W w = new W();
w.change();
}
}

class W{
static int a = 10;
public static void change(){
this.a++;
}
}


(1)this也是一个非静态的变量。

(2)this表示对当前对象的一个引用,换句话说一定要有一个对象,如果我直接调用这个方法的时候,我可以通过类来去调用,没有对象,那么this是谁呢?判断不出来,所以以上代码也不对。

(3)不能在静态方法中使用this关键字。

猜你喜欢

转载自blog.csdn.net/xiogjie_67/article/details/108475690
024