Java中的静态方法与非静态方法的区别、以及和继承类之间的关系

    科技2024-02-22  100

    静态方法和非静态方法

    静态方法在类加载(第一次创建一个实例或者调用静态方法会发生类加载)的时候就被初始化了,内存在方法区中被开辟。

    访问方式:类.静态方法或者类对象.静态方法。

    静态方法可以通过类对象.静态方法这种引用方式,但是其在执行上与具体的类对象是无关的。静态方法可以看成是不依赖其它类实例,这可以看成是一个面向过程的函数。

    从上面静态方法的特性就应该可以看出,静态方法只可以访问静态属性,无法访问非静态成员变量,非静态成员变量是依赖于具体的对象的,不同类的实例化(具体的对象)的非静态成员变量是不同的。所以,静态成员函数是不可以访问非静态的成员变量。而非静态成员函数是可以访问静态成员变量的。

    静态方法的继承问题

    静态方法是可以被继承的,可以通过子类.静态方法和子类对象.静态方法来调用静态方法。

    静态方法为什么不可以被重写? 参考一 参考二

    静态方法是不依赖具体的对象的,而多态是在运行时表现出来的特性,根据对象所属的类而表现出不同的属性,重写需要“对象所属类型”,但是静态方法是没有对象的,所以没法重写。

    方法的重写意味着什么,意味着子类继承父类,重写父类的方法。这就会产生一个多态的概念。多态会造成调用方法的不确定性!调用哪一个方法由反射机制来判断。

    为什么静态方法不能调用实例方法? 静态方法的调用的是通过在编译器静态绑定的,而实例方法的调用是在运行时动态绑定的,2者的调用的方式不同,所以二者只能存在其一,否则会存在歧义!

    为什么静态方法能调用静态方法? 因为调用方式一致,不会像上面造成歧义,虽然父类和子类都定义了同样的函数,但是编译器会根据对象的静态类型激活对应的静态方法的引用,造成了重写的假象,实则不是重写!

    Person student= new Student(); student.work(); 静态类型就是编译器编译期间认为对象所属的类型,这个主要根据声明类型决定,所以上述Person就是静态类型 实际类型就是解释器在执行时根据引用实际指向的对象所决定的,所以Student就是实际类型。 方法接受者就是动态绑定所找到执行此方法的对象,比如student。

    认识到上面的静态类型、实际类型后看下面的代码: 用对象调用子类中的静态方法,可以看到,name对象在编译期间会被认为是A类型的,这就是静态类型。

    类加载过程

    /** * 加载方法不等于执行方法,初始化变量则会赋值 * 类加载顺序应为 加载静态方法-初始化静态变量-执行静态代码块 * 实例化时 先加载非静态方法-实例化非静态变量-执行构造代码块-执行构造函数 * @author panteng * */ public class StaticTest { /**第一个加载*/ public static int k = 0; /**第二个加载,因为是new一个实例, * 首先初始化j 打印出 1:j i=0 n=0 * 执行构造块 打印出 2:构造快 i=1 n=1 * 执行构造方法 打印出 3:t1 i=2 n=2 * 实例化完成 */ public static StaticTest t1 = new StaticTest("t1"); /**第三个加载 过程同上 * 首先初始化j 打印出 4:j i=3 n=3 * 执行构造块 打印出 5:构造快 i=4 n=4 * 执行构造方法 打印出 6:t2 i=5 n=5 */ public static StaticTest t2 = new StaticTest("t2"); /**第四个加载 * 打印出 7:i i=6 n=6 */ public static int i = print("i"); /** * 第五个加载 */ public static int n = 99; /** * 此变量在类加载的时候并不初始化,在实例化类的时候初始化 */ public int j = print("j"); { print("构造快"); } /** * 第六个加载 此时,n已经被初始化 所以打印出 * 8:静态块 i=7 n=99 */ static{ print("静态块"); } //-----------以上属于类加载--------------------- /** * 实例化过程: * 首先加载非静态方法集; * 初始化非静态变量:9:j i=8 n=100 * 执行构造块:10:构造快 i=9 n=101 * 执行构造方法:11:init i=10 n=102 * 实例化完成 */ /** * 执行构造函数 实例化完成 * @param str */ public StaticTest(String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++n; ++i; } /** * 这个应该是最先加载 但是,加载不等于执行 * 因为如果不加载此函数,静态变量是无法初始化的 * @param str * @return */ public static int print(String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++i; return ++n; } public static void main(String[] args) { /**首先加载类,然后实例化: * 类加载过程: * 首先加载所有的静态方法,但不执行; * 然后按照静态变量的顺序开始初始化 * 静态变量初始化完毕后执行静态构造块(不执行构造块) * 此时类加载完毕 * 实例化过程: * 加载非静态方法 * 初始化非静态变量 * 执行构造代码块 * 执行构造函数 * 此时实例化完毕 */ StaticTest t = new StaticTest("init"); } }

    静态static的小代码:

    public class TestA { public static boolean getcheck(){ return true; } public static void getf() { System.out.println("father"); } public void getrun() { System.out.println("你好哇"); } //静态代码块,类加载的时候进行一次初始化即可 static { System.out.println("类加载-->1"); } static { System.out.println("类加载-->2"); } } public class TestB extends TestA{ public static boolean getcheck(){ return true; } public static void getf() { System.out.println("mother"); } public static void gets() { System.out.println("son"); } public static void main(String[] args) { if(TestA.getcheck()) { System.out.println("Static方法被继承了"); } System.out.println("你是猪"); TestA test=new TestB(); test.getf(); } } //执行结果 类加载-->1 类加载-->2 Static方法被继承了 你是猪 father

    更新 一个小小的测试:静态变量因为在类加载的时候就已经被分配内存了,静态变量是全局变量不是属于某一个对象所有的,当静态属性被修改,那么后来的其他访问这个静态属性就是被修改后的。(所以说其是全局变量)

    package threadsafe; public class Threadsafe2 { private static int age; private static Account a; public void set(int age) { this.age=age; } public void s(Account a) { this.a=a; } public String g() { return a.toString(); } public int get() { return age; } public static void main(String[] args) { // TODO Auto-generated method stub Threadsafe2 t1=new Threadsafe2(); Threadsafe2 t2=new Threadsafe2(); t1.set(50); System.out.println(t1.get()); System.out.println(t2.get()); Account a1=new Account(100); Threadsafe2 t3=new Threadsafe2(); Threadsafe2 t4=new Threadsafe2(); t3.s(a1); System.out.println("!!!!!!!!"+t3.g()+" "+t4.g()); } } class Account { private String account; private int accountmoney; public Account(String name,int money) { this.account=name; this.accountmoney=money; } public Account(int n) { this.accountmoney=n; } //取钱 public void withdraw(int m) { accountmoney-=m; } //显示账户余额 public int getmoney() { return accountmoney; } @Override public String toString() { // TODO Auto-generated method stub return ""+accountmoney; } }
    Processed: 0.014, SQL: 8