-------android培训、java培训、期待与您交流! ----------
本日志doc文档下载
一、static关键字
1、用法
Static是一个修饰符,用于修饰成员,包括成员变量和成员函数。当成员被静态修饰后,就多了一种调用方式,除了可以被对象调用外,还可以直接被类名调用。
2、特点
2.1 随着类的加载而加载,也就是说静态会随着类的消失而消失,说明它的生命周期最长。
2.2 优先于对象存在:静态是先存在的,对象是后存在的。
2.3 被所有对象共享
2.4 可以直接被类名所调用
3、实例变量和类变量的区别
3.1 存放位置
类变量随着类的加载而存在与方法区中
实例变量随着对象的建立而存在于堆内存中
3.2 生命周期
类变量生命周期最长,随着类的消失而消失
实例变量生命周期随着对象的消失而消失
4、静态使用注意事项
4.1 静态方法只能访问静态成员
非静态方法既可以访问静态也可以访问非静态
4.2 静态方法中不可以定义this,super关键字
因为静态优先于对象存在。所以静态方法中不可以出现this
5、静态的利与弊
5.1 利处:对对象的共享数据进行单独空间的存储,节省空间;没有必要为每一个对象都存储一份,可以直接被类名调用。
5.2 弊处:生命周期过长,访问出现局限性(静态虽好,只能访问静态)
二、Main函数详解
主函数:一个特殊的函数,作为程序的入口,可以被JVM调用。
主函数的定义:
public:代表着该函数访问权限是最大的
static:代表主函数随着类的加载就已经存在了
void:主函数没有具体的返回值
main:不是关键字,但是是一个特殊的单词,可以被JVM识别
(String [] args ):函数的参数,参数类型是一个字符串类型的数组。
总而言之:主函数是固定格式的,可以被JVM识别。JVM在调用主函数时,传入的是new String[0]
代码段一:
public class TestMain { public static void main(String[] args) { System.out.println("这里是可以被JVM识别的主函数格式"); } public static void main(int args) { System.out.println("main并不是一个关键字,但是是一个特殊的单词,可以被JVM识别"); } public static void main(String args) { System.out.println("名字为main的方法重载形式"); } }
代码段二:
public class TestMain02 { public static void main(String[] args) { System.out.println("主函数中参数长度:" + args.length); for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } }
运行结果如下所示
三、什么时候使用静态
因为静态修饰的内容有成员变量和函数,所以从两方面下手:
什么时候定义静态变量(类变量)?
当对象出现共享数据时,该数据被静态所修饰。
对象中的特有数据要定义成非静态类型,存在与堆内存中。
什么时候定义静态函数?
当功能内部没有访问到非静态数据(对象的特有数据),那么可以将该功能定义成静态的。
四、静态的应用
每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。
五、制作程序的说明书
Java的说明书通过文档注释类完成。
代码块一
/** * 这是一个可以对数组进行操作的工具类,该类中提供了获取最值的功能 * * @author LeeYou * @version v1.0 */ public class ArrayTool { private ArrayTool() { } /** * 获取一个整型数组中的最大值 * * @param arr 接收一个int类型的数组 * @return 会返回一个该数组中的最大值 */ public static int getMax(int[] arr) { int max = 0; for (int i = 1; i < arr.length; i++) { if (arr[i] > arr[max]) { max = i; } } return arr[max]; } /** * 获取一个整型数组中的最小值 * @param arr 接收一个int类型的数组 * @return 会返回一个该数组中最大值 */ public static int getMin(int[] arr) { int min = 0; for (int i = 1; i < arr.length; i++) { if (arr[i] < arr[min]) { min = i; } } return arr[min]; } }
利用控制台运行命令如下:
生成的API截图如下:
6、静态代码块
格式:
Static { 静态代码块中的执行语句 }
特点:随着类的加载而执行,只执行一次,用于给类进行初始化
代码块一:
class StaticCode { StaticCode() { System.out.println("无参构造函数运行了..."); } static { System.out.println("静态代码块运行了..."); } { System.out.println("构造代码块运行了..."); } StaticCode(int x) { System.out.println("带参数的构造函数执行了..." + "传入整形参数:" + x); } public static void show() { System.out.println("静态方法运行了..."); } } public class StaticCodeDemo { static { System.out.println("主类的静态代码快运行了..."); } public static void main(String[] args) { new StaticCode(8); } }
运行结果如下所示:
7、对象建立和调用过程
BubbleSort bs = new BubbleSort();
这句代码做了一些什么事情?
1,因为new用到了BubbleSort.class,所以会先找到BubbleSort.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给BubbleSort.class类执行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性,并进行默认的初始化。
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址赋给栈内存中的bs变量。
理解这段执行顺序比较绕,但是很重要,理解创建一个对象在底层到底是怎样被创建被赋值的有助于以后深入JVM的学习。
关于带静态属性和方法的类加载时,内存中的分配情况见下图:
8、单例设计模式
设计模式:解决某一类问题最行之有效的方法
单例设计模式:解决一个类在内存中只存在一个对象
想要保证对象的唯一:
1,为了避免其他程序过多的建立该类对象,先禁止其他程序建立该类对象
2,为了让其他程序可以访问到该类对象,在本类中自定义一个对象
3,为了方便其他程序对自定义对象的访问
这三步怎么用代码体现呢?
1,将构造函数私有化
2,在类中创建一个本类对象
3,提供一个方法可以获取到该对象
饿汉式单例模式代码块:
/** * 这个是先初始化对象,称为:饿汉式 * Single_LazyMan 类一加载进内存,就已经创建好了对象 * 实际开发中一般采用这种方式 * @author LeeYou * */ public class Single_HungryMan { private static Single_HungryMan s = new Single_HungryMan(); private Single_HungryMan() { } public static Single_HungryMan getInstance() { return s; } }
懒汉式单例模式代码块:
/** * 对象是方法被调用时,才初始化,也叫做对象的延时加载。称为:懒汉式 Single_LazyMan * 类加载进内存,对象还没有存在,只有调用了getInstance()方法时,才建立对象 但是这种方式在""处存在问题,解决办法如下 public static Single_LazyMan getInstance() { if (s == null) { synchronized (Single_LazyMan.class) { if (s == null) { s = new Single_LazyMan(); } } } return s; } * @author LeeYou * */ public class Single_LazyMan { private static Single_LazyMan s = null; private Single_LazyMan() { } public static Single_LazyMan getInstance() { if (s == null) s = new Single_LazyMan(); return s; } }