静态方法可以调用非静态变量吗_静态static修饰的方法怎么使用?

d219e3a28c6140a59ad28db2c7201c2e.png

由于今天一个小伙伴问静态static修饰的方法怎么使用,于是联想到,如果你还不会使用或者只是停留在使用层面,那么这里告诉你,静态可没你想的那么简单,比如下面的这两个问题能答上来吗?

为什么静态方法只用调用静态方法或者属性?
为什么非静态的可以方法非静态的同时还能访问静态?

知道的可以绕路去看看其他的,如果含糊或者不清楚的话,希望你认真看完,至少我认为你看完了就彻底搞清楚了java静态相关问题。

文末会给出三道面试题目

在日常工作中静态使用频率一直都是高居不下,最常用的就是工具类,比如:DateUtil,DataUtil,StringUtil等,各种util,不妨你回去翻翻你们项目里面是不是也有这些***Util.java,JDK、Spring、Dubbo等也有很多工具类也是使用static修饰其方法的。

比如:Arrays.java

package java.util;
public class Arrays {
 public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }
 public static void sort(int[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
    }  
    //.....很多  
}

比如:StringUtils.java

package com.sun.xml.internal.ws.util;
public class StringUtils {
    public static String decapitalize(String name) {
     //  .... 省略无关  
    }
    public static String capitalize(String name) {
           //  .... 省略无关 
    }
}

这里就不一一列举了,基本上每个jar包中util下面的类都有静态static出现。

什么是静态呢?

static字面意思就是静态的、静止的。java中static修饰的类,方法,变量都是静态的,也就相应称之为静态类(静态内部类),静态方法,静态变量。

静态的使用

public class StaticClassDemo {
    //静态内部类
    private static class StaticClass {
        //静态属性
        private static String NAME = "Java 后端技术栈 内部类";
    }
    //静态方法
    public static String getName() {
        return StaticClass.NAME;
    }
}
public class MyStaticTest {
    public static void main(String[] args) { 
        System.out.println(StaticClassDemo.getName());
    }
}

输出:

Java 后端技术栈 内部类

这就是一个很简单的静态static修饰的类、方法、属性的使用案例。

什么是非静态?

比如说下面的案例:

public class User {
    private int userId;
    private String userName;
    //省略 set get tostring
}
public class MyStaticTest {
    public static void main(String[] args) {
        User user=new User();
        user.setUserId(1001);
        user.setUserName("lawt");
        System.out.println(user);
    }
}

输出:

User{userId=1001, userName='lawt'}

静态方法不能调用非静态方法

public class MyStaticUtil {
    public static String test() {
         test1();//正常
         test2();//编译通不过
        return "Java后端技术栈";
    }
    public static String test1(){
        return "非静态方法";
    }
    public String test2(){
        return "非静态方法";
    }
    public static void main(String[] args) {
        test();
    }
}

静态方法是属于类的,即静态方法是随着类的加载而加载的,在加载类时,程序就会为静态方法分配内存。而非静态方法是属于对象的,对象是在类加载之后创建的,也就是说静态方法先于对象存在,当你创建一个对象时,程序为其在堆中分配内存,一般是通过this指针来指向该对象。静态方法不依赖于对象的调用,它是通过‘类名.静态方法名’这样的方式来调用的。而对于非静态方法,在对象创建的时候程序才会为其分配内存,然后通过类的对象去访问非静态方法。因此在对象未存在时非静态方法也不存在,静态方法自然不能调用一个不存在的方法。

面试题

面试题1:

public class Test {
    private static void print(){
        System.out.println("Print()");
    }
    public static void main(String[] args) {
        ((Test)null).print();
    }
}

这端代码能编译通过吗?编译不过是什么原因?编译能过将输出什么?

(1)首先,我们可以试一下去掉static,这里不会编译错误,但是运行时会抛出空指针异常,原因是什么呢,原因就是类似于上面说的静态方法不能调用非静态方法的原因了。我们很容易被null转移了视线,这里与null的关系不大(这是因为是静态方法,null没有影响),null是为了告诉我们这里的引用没有指向任何地方或者说还未初始化,也就是说对象未创建,从上面对象的创建过程可以知道,如果对象还未创建,则不会有this指针的引用,因此会报空指针异常。

(2)这里用null的话(即(Test)null)是将Test引用强制转换为Test对象,这样也可以调用静态方法,其实不需要null,也是可以调用静态方法的,即Test.Print()。

所以上面的答案是:能编译通过,并且输出

Print()

另外补充一下我觉得很有必要知道的null的知识:

  • null可以被强制转换为任何引用类型。
  • 任何含有null值的包装类在自动拆箱成基本数据类型时都会抛出一个空指针异常
  • 不能用一个值为null的引用类型变量来调用非静态方法,这样会抛出空指针异常,但是静态方法可以被一个值为null的引用类型变量调用而不会抛出空指针异常。这和对象的创建和静态方法以及非静态方法之间的关系有关。也就是上面说的那些。

面试题2:

public class Sub extends Base {
    static {
        System.out.println("test static");
    }
    public Sub() {
        System.out.println("test constructor");
    }
    public static void main(String[] args) {
        new Sub();
        new Sub();
    }
}
class Base {
    static {
        System.out.println("base static");
    }
    public Base() {
        System.out.println("base constructor");
    }
}

这段代码输出什么?

因为static在类加载的时候就已经确定了,并且类加载只有一次。所以上面代码块中,静态的值输出一次:

base static
test static
base constructor
test constructor
base constructor
test constructor

面试题3:

public static class Test {
    public static String test(){
        return "Java后端技术栈";
    }
    public static void main(String[] args) {
        System.out.println(test());
    }
}

这段代码能编译通过吗?编译失败是为什么呢?编译成功输出什么?

如果一个类要被声明为static的,只有一种情况,就是静态内部类。如果在外部类声明为static,程序会编译都不会过。在一番调查后个人总结出了3点关于内部类和静态内部类(俗称:内嵌类)

  • 静态内部类跟静态方法一样,只能访问静态的成员变量和方法,不能访问非静态的方法和属性,但是普通内部类可以访问任意外部类的成员变量和方法
  • 静态内部类可以声明普通成员变量和方法,而普通内部类不能声明static成员变量和方法。
  • 静态内部类可以单独初始化:

ok,今天就到此了!也算是自己复习一遍基础。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值