由于今天一个小伙伴问静态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指针来指向该对象。静态方法不依赖于对象的调用,它是通过‘类名.静态方法名’这样的方式来调用的。而对于非静态方法,在对象创建的时候程序才会为其分配内存,然后通过类的对象去访问非静态方法。因此在对象未存在时非静态方法也不存在,静态方法自然不能调用一个不存在的方法。
建议阅读Java类初始化顺序
面试题
面试题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的知识:
面试题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");
}
}
这段代码输出什么?
其实通过这篇文章Java类初始化顺序 是很容易知道一个new Sub();的答案。但是两个new Sub()那就不一定了,哈哈,因为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点关于内部类和静态内部类(俗称:内嵌类)
ok,今天就到此了!也算是自己复习一遍基础。
参考:
blog.csdn.net/a5650892/article/details/78708343
blog.csdn.net/ning1994724/article/details/87919945