前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【刨根问底】java静态

【刨根问底】java静态

作者头像
田维常
发布2019-07-16 11:03:31
4460
发布2019-07-16 11:03:31
举报

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

代码语言:javascript
复制
为什么静态方法只用调用静态方法或者属性?
为什么非静态的可以方法非静态的同时还能访问静态?

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

代码语言:javascript
复制
文末会给出三道面试题目

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

比如:Arrays.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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修饰的类,方法,变量都是静态的,也就相应称之为静态类(静态内部类),静态方法,静态变量。

静态的使用

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

输出:

代码语言:javascript
复制
Java 后端技术栈 内部类

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

什么是非静态?

比如说下面的案例:

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

输出:

代码语言:javascript
复制
User{userId=1001, userName='lawt'}

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

代码语言:javascript
复制
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指针来指向该对象。静态方法不依赖于对象的调用,它是通过‘类名.静态方法名’这样的方式来调用的。而对于非静态方法,在对象创建的时候程序才会为其分配内存,然后通过类的对象去访问非静态方法。因此在对象未存在时非静态方法也不存在,静态方法自然不能调用一个不存在的方法。

建议阅读Java类初始化顺序

面试题

面试题1:

代码语言:javascript
复制
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()。

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

代码语言:javascript
复制
Print()

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

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

面试题2:

代码语言:javascript
复制
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");
    }
}

这段代码输出什么?

其实通过这篇文章Java类初始化顺序 是很容易知道一个new Sub();的答案。但是两个new Sub()那就不一定了,哈哈,因为static在类加载的时候就已经确定了,并且类加载只有一次。所以上面代码块中,静态的值输出一次:

代码语言:javascript
复制
base static
test static
base constructor
test constructor
base constructor
test constructor

面试题3:

代码语言:javascript
复制
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,今天就到此了!也算是自己复习一遍基础。

参考:

blog.csdn.net/a5650892/article/details/78708343

blog.csdn.net/ning1994724/article/details/87919945

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档