java基础--static和final的用法

static

被static修饰的变量或者方法不依赖于对象来进行访问,只要对应的类被加载,就可以通过类名直接访问

简言之static就是用来在没有创建对象的情况下访问类的变量或者方法

用途
  • static修饰的变量或者方法被称作静态变量或者静态方法,因为它们是不依赖于任务对象的,因此静态方法中也就没有this这个说法。同时在静态方法中只能访问静态变量/方法,不能访问非静态变量/方法;而非静态方法可以访问静态变量/方法。这是因为非静态方法/变量必须依赖具体的对象才能存在和被调用。

  • 因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。


类的构造器是静态方法吗?

很多资料上说即使没有显示地声明为static,类的构造器实际上也是静态方法,其实这句话是有歧义的

  • 首先可以确定静态方法是无法使用this的,因为不依赖具体的对象

    在Java语言规范中有提到这样一段话

    “类方法”(“静态方法”)与“实例方法”在概念中的JVM上的区别:在调用类方法时,所有参数按顺序存放于被调用方法的局部变量区中的连续区域,从局部变量0开始;在调用实例方法时,局部变量0用于存放传入的该方法所属的对象实例(Java语言中的“this”),所有参数从局部变量1开始存放在局部变量区的连续区域中。

    从效果上看,这就等于在调用实例方法时总是把“this”作为第一个参数传入被调用方法。

  • 其次从Java语言规范对“方法”的定义来说,构造器根本不是“方法”;二清,实例构造器有一个隐式参数,“this”,在实例构造器中可以访问“this”,可以通过“this”访问到正在初始化的对象实例的所有实例成员。

    因此构造器不属于静态方法,但实例构造器无法被隐藏或覆写,不参与多态,因而可以做静态绑定。从这个意义上可以认为实例构造器是“静态”的,但这种用法与Java语言定义的“静态方法”是两码事。

  • Java语言中,实例构造器只能在new表达式(或别的构造器)中被调用,不能通过方法调用表达式来调用。new表达式作为一个整体保证了对象的创建与初始化是打包在一起进行的,不能分开进行;但实例构造器只负责对象初始化的部分,“创建对象”的部分是由new表达式本身保证的。


  • static修饰变量是静态变量,静态变量与非静态变量的区别是:静态变量是对象共享的,内存中只有一个副本,是在类加载时被初始化的,一旦初始化就不能被改变;而静态变量是对象所拥有的,每个对象之间互不干扰。

  • static可以修饰代码块,称作静态代码块,只有在类被加载的时候按照static代码块的位置顺序执行,且只执行一次,静态代码块可以用来优化代码

public class Student {


    //入学年份
    private int inSchoolYear;

    public Student(int year){

        this.inSchoolYear = year;

    }

    //判断是否2010-2017入学的学生
    boolean isTrue(int inSchoolYear){

        int startYear = 2010;
        int endYear = 2017;

        return (startYear <= inSchoolYear && endYear > inSchoolYear) ? true : false;
    }

}

可以看到,每次调用都要对startYear和endYear进行赋值,如果将这两块放入static代码块,只需要在类加载是执行赋值一次,后面就可以一直使用

public class Student {

    static int startYear,endYear;

    static {
        startYear = 2010;
        endYear = 2017;
    }

    //入学年份
    private int inSchoolYear;

    public Student(int year){

        this.inSchoolYear = year;

    }

    //判断是否2010-2017入学的学生
    boolean isTrue(int inSchoolYear){

        return (startYear <= inSchoolYear && endYear > inSchoolYear) ? true : false;
    }

}

总结

  • static不会改变变量的访问权限

  • static变量可以通过this访问,但前提是要先有一个具体的对象,才能通过这个对象的this访问static变量

  • static不能修饰局部变量

final

在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下final关键字的基本用法。

修饰类

被final修饰的类是不能被继承的,要重点说明的是被final修饰的类它的成员变量可以根据实际情况被不同的关键字所修饰,但是它的方法会被隐式的修饰为final类型。

注意只有在确定处于安全考虑或者确定不让类被继承的情况下的才能用final修饰。

修饰方法

被final修饰的方法主要出于两个目的

  • 不想让子类去修改这个方法

  • 提高方法的执行效率(但这一点在后来的jdk版本中已经不需要通过final来实现了,此用法现在可以忽略)

因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。

修饰变量

这也是final用法最多也是最容易出问题的地方

final修饰的基本数据变量必须在定义时进行初始化或者在构造方法中进行初始化,一旦初始化就不能再改变;对于引用数据类型,则引用变量所指向的对象是不能改变的,但对象自身的数据是可以改变的。

    public static void main(String[] args) {


        final MyTest myTest = new MyTest();

        System.out.println("mytest.num = " + myTest.getNum());

        //不能改变引用变量的指向
        //myTest = new MyTest();

        //但可以改变对象自身的值
        myTest.setNum(10);

        System.out.println("mytest.num = " + myTest.getNum());

    }

输出结果

mytest.num = 0
mytest.num = 10

Process finished with exit code 0
statci和final的区别
  • static一旦修饰一个变量,变量需要在类加载时候就进行初始化,且内存中只有一个拷贝值,所有对象共享该变量的值

  • final修饰的变量属于对象所有,在对象初始化时候需要进行初始化,且一旦初始化就不能改变。属于对象自身的值,每个对象之间有多份该变量的拷贝,且每个拷贝的值可以不一样

所以两者最大的区别就是static修饰的变量属于类变量,内存拷贝只有一份;而final修饰的变量属于对象变量,每个对象各有一份。

public class Student {


    private final double  age1 = Math.random();

    private static double age2 = Math.random();


    public static void main(String[] args) {


        Student stu1 = new Student();
        Student stu2 = new Student();


        System.out.println("stu1.age1 =" + stu1.getAge1()+", stu1.age2 = "+stu1.getAge2());


        System.out.println("stu2.age1 = " + stu2.getAge1()+", stu2.age2 = "+stu2.getAge2());

    }

    /**
     *  Getter  method for property  age1.
     *
     *  @return property value of age1
     */

    public double getAge1() {
        return age1;
    }

    /**
     *  Getter  method for property  age2.
     *
     *  @return property value of age2
     */

    public static double getAge2() {
        return age2;
    }

    /**
     *  Setter method for property age2
     *
     *  @param age2 value to be assigned to property age2
     */

    public static void setAge2(double age2) {
        Student.age2 = age2;
    }
}


执行结果:

stu1.age1 =0.9167458637588903,   stu1.age2 = 0.7316995482947469
stu2.age1 = 0.39822634358146847, stu2.age2 = 0.7316995482947469

Process finished with exit code 0

从以上执行结果可以看到,final修饰的变量,每个对象的值是可以不一样的,而且每个对象有自己的变量值的拷贝;而static修饰的变量只会有一个值,有人说两个对象不是都有这个age2的值吗?其实是类在加载的时候就把age2的值已经加载到静态数据存储内存区域了,每个具体的对象都是去这个静态数据区获取的age2的值,因为每个对象获取的是通过一静态值,所以值才是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值