深入理解静态类(static)和非静态类之间的区别

2017-07-29 09:32 阅读 1,544 次 评论 0 条
版权声明:本文著作权归TeachCourse所有,未经许可禁止转载,谢谢支持!
转载请注明出处:http://teachcourse.cn/2454.html

摘要:

在理解静态类和非静态类的区别之前,先了解static关键字的含义,static修饰的变量称为类变量static修饰的方法称为类方法,类变量的特点:不同的对象共享同一个类变量,类方法的特点:加载字节码文件时分配入口地址,因此会有如下的定义:

  1. 类方法内不允许调用实例方法
  2. 类方法内不允许调用实例变量
  3. 可以通过类名直接调用类方法
  4. 可以通过实例对象调用类方法

如果你现在还不能都明白上面定义的含义,没有关系,接下来钊林会提供demo的方式深入分析static关键字的使用,进而深入理解静态类和非静态类直接的区别。

一、类变量和实例变量的区别

static修饰的变量被称为类变量,不使用static修饰的变量称为实例变量,实例变量的特点:不同对象的实例变量被分配不同的内存,为了更好说明类变量和实例变量的区别,下面先举一个例子:demo打印公司所在地址信息

demo目录结构:

目录结构

public class PrintAddress {
    static String DEFAULT_ADDRESS="广东省广州市天河区创意软件园";
    String currentAddress;
    public PrintAddress(String currentAddress) {
        this.currentAddress = currentAddress;
    }

    public void print(){
        System.out.println(currentAddress);
    }

    public static void defaultPrint(){
        System.out.println("默认公司地址:"+DEFAULT_ADDRESS);
    }
}

创建两个PrintAddress对象:addressAaddressB,创建对象时传入一个地址,代码如下:

public class DemoTestDrive {

    public static void main(String[] args) {
        PrintAddress addressA=new PrintAddress("当前公司A地址:"+"广州天河北路");
        PrintAddress addressB=new PrintAddress("当前公司B地址:"+"广州越秀区");
        addressA.print();        
        addressB.print();
        addressA.defaultPrint();
        addressB.defaultPrint();
    }

}

运行demo,打印结果:

static关键字

分析:

(1)创建PrintAddress对象时,给实例变量currentAddress赋值,两个对象的两个实例变量分别打印自己赋值的内容,说明不同对象的实例变量被分配不同的内存空间

为了说明类变量分配相同的内存,先打印默认类变量的值,然后改变默认类变量的值,再打印类变量,代码如下:

public class DemoTestDrive {

    public static void main(String[] args) {
        PrintAddress addressA=new PrintAddress("当前公司A地址:"+"广州天河北路");
        PrintAddress addressB=new PrintAddress("当前公司B地址:"+"广州越秀区");
        addressA.print();    
        addressB.DEFAULT_ADDRESS="广东省广州市华夏路10富力中心";
        addressA.defaultPrint();         
        addressB.print();    
        addressB.defaultPrint();
    }

}

运行demo,打印结果:

static关键字

分析:

(1)类变量被分配相同的一处内存,改变其中一个对象的类变量,其它对象的类变量也会改变,不同对象的类变量共享同一处内存。

类变量和实例变量的区别:

(1)类变量共享同一处内存
(2)实例变量被分配不同的内存

实例应用:
改变类变量的值,所有引用到该类变量的地方会受到影响,为了记录用户的登录状态,在用户类UserInfo声明了一个类变量loginState,记录登录或退出的状态,在所有需要使用登录功能的地方,通过检测loginState属于false或true,识别是否登录。

当用户点击了注销,程序改变loginState的状态为false,所有使用loginState的地方同时检测到false,即退出登录。

二、类方法和实例方法的区别

static修饰的方法称为类方法,没有使用static修饰的方法被称为实例方法,实例方法的特点:创建对象后,类中的实例方法分配入口地址,通过对象调用实例方法;类方法的特点:类的字节码加载到内存时分配入口地址,可以通过类名调用类方法。

为什么类方法不能调用实例变量、实例方法?

分析:明白了类方法和实例方法的特点后,你会很清楚将字节码加载到内存时,类方法就分配了入口地址,但因为没有通过new关键字创建对象,故实例变量还没有分配内存,同时实例方法也没有分配入口地址,这个时候通过类方法调用实例变量、实例方法会报错。

在前面的例子:打印公司所在地址信息,可以改成通过类名调用类方法defaultPrint()或类变量DEFAULT_ADDRESS,代码如下:

public class DemoTestDrive {

    public static void main(String[] args) {
        PrintAddress addressA=new PrintAddress("当前公司A地址:"+"广州天河北路");
        PrintAddress addressB=new PrintAddress("当前公司B地址:"+"广州越秀区");
        addressA.print();
        PrintAddress.DEFAULT_ADDRESS="广东省广州市华夏路10富力中心";
        PrintAddress.defaultPrint();

        addressB.print();    
        PrintAddress.defaultPrint();
    }

}

运行demo,打印结果:

static关键字

实例应用:
如果一个方法不需要操作实例成员就可以实现某种功能,就可以考虑将这样的方法声明为类方法。这样做的好处是避免创建对象浪费内存。

三、静态类和非静态类的区别

static关键字修饰的类称为静态类,不使用static修饰的类被称为非静态类。总结前面static修饰变量、方法的特点:(1)修饰变量,表明该变量被分配相同的内存空间,(2)修饰方法,表明该方法在类的字节码加载到内存时分配入口地址

静态类更准确的地说应该是静态嵌套类,静态嵌套类的特点:

(1)原本可以独立存在的类,却要借助外部类的壳来隐藏自己
(2)静态嵌套类不能直接引用外部类实例变量或实例方法
(3)静态嵌套类可以通过外部类的类名访问

在前面的例子:打印公司的地址,添加一个Builder的静态嵌套类,通过该例子演示上述三个特点

public class PrintAddress {
    static String DEFAULT_ADDRESS="广东省广州市天河区创意软件园";
    String currentAddress;
    public PrintAddress(String currentAddress) {
        this.currentAddress = currentAddress;
    }

    public void print(){
        System.out.println("当前公司地址:"+currentAddress);
    }

    public static void defaultPrint(){
        System.out.println("默认公司地址:"+DEFAULT_ADDRESS);
    }
    /**
     * 静态嵌套类(Static Nested Class)
     * @author Administrator
     *
     */
    public static class Builder{
        public Builder setCurrentAddress(String address) {
            this.address = address;
            return this;
        }

        public PrintAddress build(){
            return new PrintAddress(address);
        }

        public static void about(){
            System.out.println("I'm a static nested class!");
        }
        private String address;            
    }

    /**
     * 内部类(Inner Class)
     */
    public class Company{
        String companyName;

        public Company(String companyName) {
            this.companyName = companyName;
        }

        public String getCompanyName(){
            return companyName;
        }

        public void print(){
            System.out.println(currentAddress);
        }

    }
}

特点一演示:静态嵌套类Builder可以独立于PrintAddress而存在,另外一种写法,将Builder独立成一个类,如下图:

静态嵌套类

特点二演示:静态嵌套类Builder,如果想要访问外部类的实例变量currentAddress或实例方法print(),将会报错,如下图:

静态嵌套类

但是,内部类可以访问外部类的实例变量currentAddress或实例方法print(),如下图:

内部类

特点三演示:类似于类方法一样,静态嵌套类作为外部类的一部分,通过外部类类名访问静态嵌套类,获取静态嵌套类的实例,代码如下:

        PrintAddress.Builder builder=new PrintAddress.Builder();
        builder.setCurrentAddress("当前公司地址:"+"广东省越秀区北京路");

调用静态嵌套类的静态方法,代码如下:

PrintAddress.Builder.about();

类似于实例方法一样,获取内部类的实例,首先需要创建外部类的对象,通过对象调用内部类,代码如下:

        PrintAddress printAddress=new PrintAddress("当前公司地址:"+"广东省越秀区北京路");
        PrintAddress.Company company=printAddress.new Company("人力资源公司");
        company.getCompanyName();

内部类的特点:不允许在内部定义静态的成员,否则报错

比如,如果开发者在内部类Company定义了静态方法about(),提示出错,如下图:

内部类

总结:静态嵌套类无法访问外部类的实例变量、实例方法,但可以访问外部类的类变量、类方法;内部类可以访问外部类的实例变量、实例方法,但不允许定义额外的静态变量、静态方法;静态嵌套类和内部类实例化的方式区别如下:

静态嵌套类实例化:

OuterClass.StaticNestedClass nestedObject =
     new OuterClass.StaticNestedClass();

内部类实例化:

OuterClass outerClass=new OuterClass();
OuterClass.InnerClass innerClass=outerClass.new InnerClass();

参考资料:http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

关注公众号 扫一扫二维码,加我QQ

如果文章对你有帮助,欢迎点击上方按钮关注作者

来源:TeachCourse每周一次,深入学习Android教程,关注(QQ1589359239或公众号TeachCourse)
转载请注明出处:http://teachcourse.cn/2454.html
Android Spinner控件自定义样式分析 Android Spinner控件自定义样式
Android开发之versionName和versionCode的命名规则小说 Android开发之versionName和ve
Window/Linux下Genymotion快捷键大全 Window/Linux下Genymotion快捷
为什么Genymotion在Window10运行不了? 为什么Genymotion在Window10运

发表评论

呲牙 憨笑 坏笑 偷笑 色 微笑 抓狂 睡觉 酷 流汗 鼓掌 大哭 可怜 疑问 晕 惊讶 得意 尴尬 发怒 奋斗 衰 骷髅 啤酒 吃饭 礼物 强 弱 握手 OK NO 勾引 拳头 差劲 爱你

表情