A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

------<a  target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


----------


**概述:**
       
        * 随着类的加载而加载
        * 被所有对象所共享/明确一点,静态是先存在,对象是后存在的.
        * 优先于对象存在
        * 可以直接被类名调用

*特性*:
1. 随着类的加载和消失而加载和消失,生命周期最长.
非static变量称为成员变量,实例变量.
Static变量称为静态成员变量,类变量.可以通过对象名和类名调用.
实例变量和类变量的区别:
1,存放位置
类变量随着类的加载而存在于方法区中
实例变量随着对象的建立而存在于堆内存中
2,生命周期:
类变量生命周期最长,随着累的消失而消失.
实例变量生命周期随着对象的消失而消失.

**访问机制**
1. 静态方法只能访问静态成员,非静态方法可以访问静态也可以访问非静态.
2. 静态方法中不可以定义this,super关键字.因为静态优先于对象存在,所以静态方法中不可以出现.
3. 主函数是静态函数.主函数是一个特殊的函数,可以被jvm调用,是成语的起始点.

> **主函数的定义**
        * public 代表该函数访问权限最大
        * Static 代表主函数随着类的加载而加载.
        * void 主函数没有具体的返回值.
        * main  不是关键字,但是是一个特殊的单词,可以被jvm识别.
        * 函数的参数(String [] args) 参数的类型是一个数组,元素是字符串类型.     (注意:args可以随意更改)
        * 主函数是固定格式的,jvm识别的唯一函数,不可改变!
        * Jvm在调用主函数的时候,传入的是new String[0];

**静态之利弊**
利:对对象的共享数据进行单独空间的存储,节省内存空间,没有必要每个对象中都存一份./可以直接被类名调用.
弊:生命周期过长.访问出现局限性.(静态虽好,只能访问静态).

**静态的使用场景**
关于何时使用静态,我们要从两方面下手:
因为静态修饰的内容有成员变量和成员函数.
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被static修饰.对象中的特有数据要定义成非静态,存在于堆内存中.
什么时候定义静态函数呢?
当功能内部没有访问非晶态数据(对象的特有数据)时,该功能可以定义为静态的.

```
class Person
{
        String name;
        Public static void show() { // 该功能没有访问到非静态数据,就可以定义为static函数.
        System.out.println("haha");
        }
}
```
每一个应用程序中都有共性的功能,可以讲这些功能进行抽取,独立封装.以便复用,
我们在定义一个工具类的时候,虽然可以通过建立tool的对象使用tool工具这些方法,对数组操作,但是对象是用于封装数据的,tool并没有封装其特有数据,操作数组的每一个方法都没有用到其特有的数据.这时候就应该考虑让程序更加严谨,是不需要对象的.我们可以让tool里面的方法都定义成static.
这样即可直接通过类名调用即可.将方法都静态后可以方便使用,但是该类还是可以被其他程序建立对象的,为了更为严谨,强制让该类不能建立对象,此时私有化其构造函数就可以实现.将编译好的工具类发送给别人别人就可以用这个工具类,需要设置classpath后即可使用.

```
构造代码块----------------------------------
静态代码块  //随着类的加载而执行(不需要调用),只执行一次,优先于主函数执行.
Class StaticCode
{
        Static{
        System.out.println();
        }
}
```
![静态代码块运行顺序实例](http://img.blog.csdn.net/20151110173455031)


我们在面试的时候多会遇到这样的问题:
在下面的代码中,调用StaticCode.show()运行结果是?

```
class StaticCode{
        StaticCode(){
                System.out.println("b");
        }
        static{
                System.out.println("a");
        }
        {
                System.out.println("c");
        }
        StaticCode(int x){
                System.out.println("d");
        }
        public static void show(){
                System.out.println("show run");
        }
}
```
答案应该是:
*a*//静态代码块优先执行
*show run*//由于未产生对象,所以构造带代码块未执行,同理,构造函数也没有执行.

如果调用new StaticCode().show();
运行结果应该是:
*a*
*c*
*b*
*show run*

**那么在初始化一个对象的时候,调用顺序又是如何呢?**

假设一个class Person{}
那么在对象的初始化过程
Person p = new person();


        1. 从硬盘中通过jvm将class文件加载到内存.因为new用到了Person.class文件,因此加载到内存
        2. 静态代码块被执行.给该类初始化.
        3. 在堆内存中开辟空间,分配内存地址.
        4. 在堆内存中建立对象的特有属性,并进行默认初始化
        5. 对属性进行显式初始化.
        6. 对对象进行构造代码块初始化.
        7. 对对象进行与之对应的构造函数初始化.
        8. 将内存地址赋给栈内存中的对象名.

**静态在单例模式中的应用**

我们要想保证对象的唯一性,首先想到的就是单例设计模式.
        1. 为了避免其他程序过多,保证对象唯一,先禁止其他程序建立该类对象.
        2. 为了让其他程序可以访问到该对象,可以在本类中自定义一个对象.
        3. 为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式.

这三步怎么用代码体现呢?

        1. 将构造函数私有化.
        2. 在类中创建一个本类的对象.
        3. 提供一个方法可以获取到该对象.

构造函数代码:

```
Private Single()
{
        Private Static Single s = new Single();
        Public static Single getInstance(){
                return s;
        }
}
```

通过语句Single s = Single.getInstance();得到Single的实例对象.对于类中对事物的描述遵循以前的原则,当需要将该事物的对象保证在内存中唯一时,加上上述三步.

面试考试多的是懒汉式
两种不同的地方是饿汉式直接定义一个对象,Single类一进内存就已经创建了对象.懒汉式则在方法中创建.Single类进内存,对象还没有存在,只有滴哦啊用了getInstance方法时,才建立对象.
懒汉式容易出现同步的问题,出现多重对象.所以在应用中多选择饿汉式.

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马