初学JAVA-12-static关键字和final关键字

        回顾一下我们程序的主方法mian方法public staitc void main(String[] args) ,我们说过这个方法的写法是固定的,现在我们再来看这个方法有什么要求:必须是公开的(public)、静态的(static)、没有返回值的(void)、带一个String类型的数组为入参的、名字叫main的(必须每个字母都小写)的方法。public、void、String[]我们都了解过了,main的拼写不用多说,我们现在专门来说说static关键字。

        static方法

                static可以用于修饰方法,这个从main方法我们已经很清楚了。那么static的方法有什么特点?
            1.static方法可以以类名加方法名的方式调用
            2.static方法中不能使用this关键字和super关键字。
package com.dyz.test;
public class StaticTest{
	public static void print1(){
		System.out.println("this is a static method");
	}	
	public void print2(){
		System.out.println("this is a dynamic method");
	}	
	public static void main(String[] args){
		StaticTest.print1();
		StaticTest st = new StaticTest();
		st.print1();
		st.print2();
	}
}
            上面的例子中,我们在没有创建任何对象的情况下,使用类名直接引用了静态方法,在创建对象之后,我们使用对象又引用了这个静态方法。可见我们可以在没有对象的情况下就直接使用静态方法,但是我们不能在静态方法里使用非静态方法,因为非静态方法必须要通过对象调用,而有此时对象都还没有产生,所以无法调用。这也是this和super为什么不能再静态方法中使用的原因,因为this代表对象本身,super代表父类对象,此时他们都未产生,所以要调用就会出错
package com.dyz.test;
public class StaticSonTest extends StaticTest{	
	public static void print3(){
		super.print2();
		super.print1();
	}
}

package com.dyz.test;
public class StaticSonTest extends StaticTest{	
	public static void print3(){
		print2();
		print1();
	}
}
            例子中当我们不使用super关键字时,报错变成了一个,因为print2()并不是一个静态方法,所以引用会出错,但是print1()是一个静态方法,所以可以正常引用。


            static变量

            static可以用来修饰变量,用static修饰的变量被称为静态变量。静态变量用于标识类共有的属性,它的值是所有类对象共有的。比如我们假定人类的平均寿命是80岁,那么Person类的avg_life应该是一个值80,而每一个具体的对象寿命是具体对象的寿命,并不会因为谁谁谁特别长寿或者某某某刚出生就夭折而影响这个值。再比如全国平均工资2W,不会因为我工资低或者你工资高就导致这个值出现变化。当然,我们这里并不是说是类共有的就不能修改了,而是你做修改的时候,所有同类的对象也同时做了改动。
package com.dyz.test;
public class StaticTest{
	private static int score ;	
	public static void main(String[] args){
		System.out.println(StaticTest.score);
		StaticTest.score = 100;
		StaticTest st1 = new StaticTest();
		StaticTest st2 = new StaticTest();
		System.out.println(st1.score);
		System.out.println(st1.score);
		st1.score =200;
		System.out.println(st1.score);
		System.out.println(st1.score);		
	}
}
        在我们没有创建对象的时候,我们就可以通过类名来为静态变量赋值了,当我们创建对象以后,静态变量的值并没有初始化,而我们在一个对象中修改了这个静态变量,另一个对象中静态变量的值也随之变动了。

        static代码块

            在我们考虑一个场景:我们要为电视节目《年代秀》写一个程序,为他们登记参加节目的人员资料,并判断每个人的所属年代是60、70还是80、90、00,那么我们我们需要定义几个年龄段,然后根据每个人的生日来判断他属于哪个后。
package com.dyz.test;
import java.sql.Date;
public class StaticTest{	
	private Date birthday;	
	public void setBirthday(Date birthday){
		this.birthday = birthday;
	}	
	public Date getBirthday(){
		return this.birthday;
	}
	public String getYears(){
		Date years70 = Date.valueOf("1970-01-01");
		Date years80 = Date.valueOf("1980-01-01");
		Date years90 = Date.valueOf("1990-01-01");
		Date years00 = Date.valueOf("2000-01-01");
		if(this.birthday.compareTo(years70)<0){
			return "60后";
		}else if(this.birthday.compareTo(years70)>=0  && this.birthday.compareTo(years80)<0){
			return "70后";
		}else if(this.birthday.compareTo(years80)>=0  && this.birthday.compareTo(years90)<0){
			return "80后";
		}else if(this.birthday.compareTo(years90)>=0  && this.birthday.compareTo(years00)<0){
			return "90后";
		}else {
			return "00后";
		}
	}
	public static void main(String[] args){
		StaticTest t1 = new StaticTest();
		t1.setBirthday(Date.valueOf("1988-04-01"));
		String years = t1.getYears();
		System.out.println(years);
	}
}
        显然测试很正常,一切似乎很圆满,但是我们考虑一下,如果需要为一万个人建立档案,会出现什么情况?创建一个对象,输入一次年龄,执行一次判断,然后循环一万遍。我们发现,每次创建对象时,这个对象都要初始化这几个年龄段......其实我们知道,无论参加节目的人员他的生日是什么时候,我们的判断标准总是不变的,结合上面的说法,我们可以使用静态变量。
package com.dyz.test;
import java.sql.Date;
public class StaticTest{	
	private Date birthday;	
	private static Date years70,years80,years90,years00;
	static{
		years70 = Date.valueOf("1970-01-01");
		years80 = Date.valueOf("1980-01-01");
		years90 = Date.valueOf("1990-01-01");
		years00 = Date.valueOf("2000-01-01");
		System.out.println("this is a static code block");
	}
	public void setBirthday(Date birthday){
		this.birthday = birthday;
	}	
	public Date getBirthday(){
		return this.birthday;
	}
	public String getYears(){
		if(this.birthday.compareTo(years70)<0){
			return "60后";
		}else if(this.birthday.compareTo(years70)>=0  && this.birthday.compareTo(years80)<0){
			return "70后";
		}else if(this.birthday.compareTo(years80)>=0  && this.birthday.compareTo(years90)<0){
			return "80后";
		}else if(this.birthday.compareTo(years90)>=0  && this.birthday.compareTo(years00)<0){
			return "90后";
		}else {
			return "00后";
		}
	}
	public static void main(String[] args){
		StaticTest t1 = new StaticTest();
		t1.setBirthday(Date.valueOf("1988-04-01"));
		String years1 = t1.getYears();
		System.out.println(years1);
		StaticTest t2 = new StaticTest();
		t2.setBirthday(Date.valueOf("1978-05-11"));
		String years2 = t2.getYears();
		System.out.println(years2);
		StaticTest t3 = new StaticTest();
		t3.setBirthday(Date.valueOf("1998-08-01"));
		String years3 = t3.getYears();
		System.out.println(years3);
	}
}
            代码中我们用定义了70、80、90、00后的几个静态变量,然后用static{...}的方式给这几个静态变量做了赋值,在main方法中我们创建了3个对象,然后看执行情况,我们发现static{...}中间的代码被执行了一次。
            这种在类里面使用static{...}的部分叫做静态代码块,静态代码块的代码在加载类的时候会被执行,而且只会执行一次。静态代码块可以有多个,在执行的时候会按照静态代码块所处的位置先后执行,静态代码块不能出现在方法中。


            嗯,有了静态代码块,自然有非静态代码块,和静态代码块类似,但是没有static关键字修饰的就是非静态代码块。
package com.dyz.test;
import java.sql.Date;
public class StaticTest{	
	private Date birthday;	
	private static Date years70,years80,years90,years00;
	static{
		years70 = Date.valueOf("1970-01-01");
		years80 = Date.valueOf("1980-01-01");
		years90 = Date.valueOf("1990-01-01");
		years00 = Date.valueOf("2000-01-01");
		System.out.println("this is a static code block");
	}
	
	{
		System.out.println("this is a non-static code block");
	}
	
	public void setBirthday(Date birthday){
		this.birthday = birthday;
	}	
	public Date getBirthday(){
		return this.birthday;
	}
	public String getYears(){
		if(this.birthday.compareTo(years70)<0){
			return "60后";
		}else if(this.birthday.compareTo(years70)>=0  && this.birthday.compareTo(years80)<0){
			return "70后";
		}else if(this.birthday.compareTo(years80)>=0  && this.birthday.compareTo(years90)<0){
			return "80后";
		}else if(this.birthday.compareTo(years90)>=0  && this.birthday.compareTo(years00)<0){
			return "90后";
		}else {
			return "00后";
		}
	}


	public static void main(String[] args){
		StaticTest t1 = new StaticTest();
		t1.setBirthday(Date.valueOf("1988-04-01"));
		String years1 = t1.getYears();
		System.out.println(years1);
		StaticTest t2 = new StaticTest();
		t2.setBirthday(Date.valueOf("1978-05-11"));
		String years2 = t2.getYears();
		System.out.println(years2);
		StaticTest t3 = new StaticTest();
		t3.setBirthday(Date.valueOf("1998-08-01"));
		String years3 = t3.getYears();
		System.out.println(years3);
	}
}
        代码中粉色底色部分的代码分别是静态代码块和非静态代码块,我们看看执行情况:

        

            显然,和静态代码块不同,非静态代码块是随着对象创建执行的,每次创建对象时就会执行一次。

           

            final关键字


           final,就是最终的意思,它可以修饰类、方法和变量。

                    final修饰类

            用final关键字修饰类以后,这个类将不能被继承。语法
            访问修饰符 final class 标识符{...}
package com.dyz.test;
public final class SuperTest{
	public void sayHello(String name){
		System.out.println("hello,"+name);
	}		
}
package com.dyz.test;
public class SonTest extends SuperTest{
		
}	

                final修饰方法

            和修饰类一样,当final用于修饰方法的时候,它表示这个方法是的不能被重写的。在继承一章中我们知道,如果一个方法是private或者default的,那么它的子类有可能因为权限问题无法继承到这个方法,这时候我们是可以相同的方法的。但是如果子类继承到了方法,而方法是final的时候,我们是无法重写这个方法的。
            有趣的是,private的方法会被隐式的指定为final方法。



                 final修饰变量

            final修饰的变量表示该变量只能赋值一次,赋值之后就不能再改变了。
            如果变量时基本数据类型,那么这个变量的值在初始化后就固定了。如果是引用变量类型,那它初始化以后就不能再指向其他对象了,但是它指向的对象本身是可以发生变化的。
            关于引用变量,我们之前也提到过,但是未作出具体解释,这里解释一下什么是引用变量。当我们定义一个标识符时,如果指定的类型名不是基本数据类型,那么这个标识符就是一个引用变量,如
            int score = 100;
            这里的score是一个基本数据类型int类;
            SuperTest  test;
            这里的test是一个引用变量,可以看成是一个指针,它指向一个SuperTest的实例。当然此时我们未进行指向操作,它指向的是null, SuperTest test = new SuperTest();这个操作,就是定义了一个SuperTest类型的引用变量test,它指向了一个SuperTest实例。我们可以
            SuperTest test1 = new SuperTest();
            SuperTest test2 = new SuperTest();
            test1 = test2;
            上面的语句中,我们创建了两个SuperTest类型的引用变量test1和test2,它们分别指向了两个SuperTest对象实例,当我们执行test1 = test2时候,也就是把test1改为指向test2所指向的那个实例,就是第二个实例。那么第一个实例呢?由于此时没有引用变量指向它,它就被放进垃圾回收站,等待回收了。如果我们使用了final关键字,那么引用变量就只能指向最开始它指向的那个对象,无法再指向其他对象。

            请注意,当final修饰变量为成员变量时,必须要在定义的时候,或者在初始化的时候(构建方法中或者非静态代码块)对其进行初始化

package com.dyz.test;
import com.dyz.test.son.*;
public class TestSonAndSuper{
	private final String test;
}

package com.dyz.test;
import com.dyz.test.son.*;
public class TestSonAndSuper{
	private final String test = "hello";
}
package com.dyz.test;
import com.dyz.test.son.*;
public class TestSonAndSuper{
	private final String test;
	{
		test = "hello";
	}
}
package com.dyz.test;
import com.dyz.test.son.*;
public class TestSonAndSuper{
	private final String test;	
	public TestSonAndSuper(){
		test = "hello";
	}
}
        上面三种方法都可以。

        关于面向对象

        很多年前,我开始学习java的时候,我的老师跟我说过,java中其实有两个东西是违背面向对象的,一个是基本数据类型,一个是static。面向对象的思想,一切从对象出发,一切都是对象。但是基本数据类型不是对象,static,把本来是对象的东西弄成了不是对象的东西。static甚至可以在没有对象之前就创造一些东西。static是什么?创世神吗?也许吧,看看我们一切程序的入口main方法,当程序需要开始执行的时候,还没有任何对象,但是我们可以执行static的方法。或许,并不是一切都是对象吧。
            
                        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值