static无法访问非static变量和方法
为什么static无法访问非static变量和方法?
static是类的成员,与对象无关,优先于对象的加载,也就是说一个类出现的时候,类里面的static就已经加载了,但是此时还没有去new对象,只有new了对象之后内存里面才加载非static成员,所以在没有new对象的时候,内存中的static是访问不到非static的成员。这也就是为什么在static方法里面访问非static方法时必须先new对象,然后再通过对象的应用来访问非static成员!
注意:this和super指的都是对象,this指的是当前对象,super指的是当前对象的父类对象。由于内有new对象,所以在static成员里面访问不到this与super。
从内存的角度来分析
内存里面各个区域所存放的元素如下:
stack(栈)
存放基本类型的数据和对象的引用,即存放变量。
如果存放的是基本类型数据(非静态变量),则直接将变量名和值存入stack中的内存中;
如果是引用类型,则将变量名存入栈,然后指向它new出的对象(存放在堆中)。
heap(堆)
存放new产生的数据。
data segment 也叫作方法区
分为静态域和常量域。
静态域
存放在对象中用static定义的静态成员(即静态变量,同理,如果该静态变量是基本类型则将变量名和值存入静态域,如果是引用类型则指向new出的对象)。
常量池
存放具体的值,也就是变量所代表的值 。
code segment
存放代码。
下面我们一起看一个例子: 红色位置报错
==========================================
public class test20210121 {
private String str1 = "abcd";
private static String str2 = "static_abcd";
public void func1 (){
System.out.println(str1);
System.out.println(str2);
func2();
}
public static void func2 (){
System.out.println(str1); //此时没有new对象,func2在内存里面就找不到str1 = "abcd"变量,一般成员变量只用new对象之后才能和对象一起存在堆里面
System.out.println(str2);
func1(); //此时没有new对象,func2在内存里面就找不到func1方法,一般对象方法只有new对象之后才能在内存里面调用(调用的时候创建已经栈帧,jvm将栈帧入栈到栈里面)
test20210121 test2021 = new test20210121();
test2021.func1();
}
public static void func3 (String str){
str.toLowerCase();
System.out.println(str);
}
public void func4 (){
func3(str1); //此时没有new对象,func3在内存里面就找不到str1,所以不能直接运行。虽然没有new对象,但是func3在类加载的时候就已经加载在内存里面了,可以直接在内存里面找到func3
}
public static void main(String args[]){
func3(str1); //此时没有new对象,func3在内存里面就找不到str1
test20210121 test2021 = new test20210121();
test2021.func4(); //此时已经new了对象,又因为对象和对象的属性str1都在堆里面,所以func4里面的func3可以在内存里面找到str1
}
}
=============================================================================
public class test20210124 {
int i = 5;
static int k = 2;
public void m1(){
i = i + k + m2(i, k); //没有创建对象,此时的m2在内存里面访问不到 i ,只能访问到静态域里面的 k ,编译时不会报错,但是不能运行
System.out.println(i);
}
public static int m2(int i, int j){
return (int) (Math.pow(i, j));
}
public static void main(String[] args) {
test20210124 test2021 = new test20210124();
System.out.println(test2021.i); //输出:5,已经创建了对象,i=5和对象都存放在堆里面
test2021.m1(); //输出:32,已经创建了对象,m1里面的m2就可以在内存里面访问到i = 5
}
}
================================================================================