一、static关键字
理解:关于static我们可能最熟悉的就是main函数了,因为main函数就是被static所修饰,而我们也知道当我们想在main所在的类中定义功能并在main方法中调用这个功能的时候,这个功能必须被static所修饰,否则就会编译报错。那时候大家应该都会很疑惑吧,为什么呢?那是因为被static修饰的成员,我们通常称之为:静态成员或类成员,被static修饰的成员有一个很大的特点:静态成员优先于非静态成员存在于内存中,因为是静态成员先进入的内存,所以说当我们在main方法中调用非静态方法时才会出现编译报错,下面就详细说说static吧
static用法
static是一个关键字,用于修饰类中的成员(成员变量和成员函数),被static修饰的成员我们称之为静态成员(也就是类成员)。
被静态修饰的成员具备的特点:
1、随着类的加载而加载
2、优先于对象存在
3、被所用对象所共享
4、可以直接使用类名调用
注:静态方法只能访问静态成员
静态方法中不可以使用this、super关键字
主函数是静态的
那么静态变量和成员变量有什么区别呢?
1、存放位置
静态变量随着类的加载就存在与内存中的方法区中了,成员变量是随着对象的建立才存在于堆内存中,如果对象不存在,则成员变量就不存在。而静态变量则不同,静态变量可以使用类名.变量名访问
2、生命周期
静态变量生命周期最长,是随着类的消失而消失,而成员变量生命周期是随着对象的消失而消失
静态使用注意事项:
1,静态方法只能访问静态成员。
非静态方法既可以访问静态也可以访问非静态。
2,静态方法中不可以定义this,super关键字。
因为静态优先于对象存在。所以静态方法中不可以出现this。
3,主函数是静态的。静态有利有弊
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。
可以直接被类名调用。
弊端:生命周期过长。
访问出现局限性。(静态虽好,只能访问静态。)
什么时候使用静态变量呢?
当对象中出现了共享数据时(共享数据不是属性,而是属性值 如:人都有共同的属性:姓名,但是姓名却不相同,有的叫张三,有的叫李四,但是不管是张三还是李四都是中国人 这个国籍就可以作为共享数据存在),而对象特有的数据(属性 如姓名)要定义成非静态,存在于堆内存中
什么时候使用静态方法呢?
当功能内部没有访问到非静态数据(或对象的特有数据时)可以把该函数定义成静态的
二、API帮助文档的生成
//定义一个工具类,实现对数组的操作注:1、要生成文档注释的类必须被public所修饰
//文档注释提示作者和版本号,作者用@ author声明 版本号用@version声明
/**
这是一个可以对数组进行操作的类,可使用该类对已有数组进行排序、遍历、查找等操作
@author 马凯
@version v.1
*/
public class Tool
{
/*因为类中没有用到成员变量,却都是静态方法,让使用者创建对象也毫无
意义而言,所以直接控制该类不可以实例化,只能通过类名.方法名调用相应功能
*/
private Tool(){}
//开始文档注释
/**
该方法是对提供的数组进行遍历,输出格式为[参数1,参数2....]
@param array 形式参数,接收一个int类型的数组
*/
public static void printArray(int [] array){
System.out.print("[");
for(int i=0;i<array.length;i++){
if(i==array.length-1)
System.out.print(array[i]+"]");
else
System.out.print(array[i]+",");
}
}
/**
该方法是查找已知数组中是否包含要查找的元素
@param key 接收一个int类型的数值
@return 会返回该数值所在数组中的下标
*/
public static int getFind(int [] arr,int key){
for(int i=0;i<arr.length;i++){
if(key==arr[i])
return i;
}
return -1;
}
public static void getSort(int [] arr){
for(int i=0;i<arr.length-1;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = arr[i];
}
}
}
}
}
2、生成API文档必须使用文档注释
3、@author(提取作者内容)
4、@version(提取版本信息)
5、@param 参数名称//形式参数的变量名称
6、@return 函数运行完返回的数据
最总要的一点:如果你的文档注释中声明了author和version这两个参数,那么在生成API文档时,也要指定这两个参数 那么用DOS命令行生成API文档格式为: javadoc -d myclss -author -version Tool.java
格式定义: Javadoc用来生成API文档的工具
-d:是指当前目录
myclass:指生成的API文档存放的文件夹
-author和-version:如果文档注释中声明了这两个参数 那么在生成API文档时必须要写这两个参数
Tool.java:指要生成的Java文件
二、主函数的定义
public static void main(String [] args){}
publci:代表该函数的访问权限是最大的
static:代表该主函数是随着类的加载就已经存在了
void:代表主函数没有具体的返回值
main:不是关键字,但是一个特殊的单纯,他可以被虚拟机所识别
String [] args:代表函数的参数是一个字符串类型的数组
注:主函数是一个函数,它也具有重载的特性,只不过虚拟机只识别参数为String类型的数组的main函数
三、静态代码块
格式:
static{
执行语句
}特点:随着类的加载就已经存在,而且只执行一次,并且优先于主函数
作用:给类进行初始化
类的加载:只有使用到类中的内容时,类才会被加载
举例:
Person p = null; 不会加载类,因为没有使用到类中的内容
Person p = new Person(); //会加载类,因为使用到了Person类中无参的构造函数
四、创建一个对象,计算机的执行流程
如:Person p = new Person();
这句话到底都做了什么事情呢?
1、因为new用到了Person.class文件,所以会先找到Person.class文件并加载到内存中
2、执行该类中的静态代码块,如果有的话,给Person类进行初始化
3、在栈内存中开辟空间p,在堆内存中开辟new Person()
4、在堆内存中建立对象的特有属性并进行默认初始化
5、对属性进行显示初始化
6、对对象进行构造代码块初始化
7、对对象进行与之对应的构造函数初始化
8、将内存地址赋值给栈内存中的变量p
五、设计模式
什么是设计模式
设计模式就是一种思想,用来解决某一类问题最之有效的方法
Java*有23中设计模式
设计模式中的一种:单例设计模式
什么是单例设计模式?
单例设计模式就是用来保证一个类在内存中只存在一个对象
想要保证对象唯一,要实现的步骤:
1、为了避免其他程序过多的建立该类对象,应先禁止其他程序建立该类对象
2、为了让其他程序可以访问到该类对象,只好在本来中自定义一个对象
3、为了方便其他程序对自己对象的访问,可以在本类中提供一个访问方式
单例设计模式实现方式一:
饿汉式
class Demo
{
private String name;
private int age;
//第二步,在本类内部自定义一个对象
private Demo demo = new Demo();
//第一步,把构造函数是私有化,禁止该类实例化(就是建对象)
private Demo(){}
/*第三步,对外提供访问对象的方式,因为本类禁止实例化,
所以只能使用类名.方法名访问类内部的功能,所以对外提供访问对象的
方法应该是静态方法*/
public static Demo getDemo(){
return demo;
}
}单例设计模式实现方式二、
懒汉式
class Demo1
{
private String name;
private int age;
//第二步,在本类内部定义类类型变量,初始化为null
private Demo demo = null;
//第一步,把构造函数是私有化,禁止该类实例化(就是建对象)
private Demo(){}
/*第三步,对外提供访问对象的方式,因为本类禁止实例化,
所以只能使用类名.方法名访问类内部的功能,所以对外提供访问对象的
方法应该是静态方法*/
public static Demo getDemo(){
if(demo==null){
demo = new Demo();
}
return demo;
}
}
/*但是发现上述代码并不一定能够保证对象的唯一,
因为CPU是在多个程序中来回切换的,所以有可能会在执行“demo = new Deno()
”前回跳到另一个程序继续执行(这个进程我们用“A”表示)
在cpu执行另一个程序的同时,可能会有新的程序(“B”)也调用
了getDemo方法,因为“A”还没有建立对象就去执行下一个程序了,
所以demo此时还是为“null”,所以这时“B”是满足“demo==null”这个
条件的,这时“B”就有可能会创建了对象,而“A”因为在之前也是
满足“demo==null”的,所以这时“A”也是可以执行“demo=new Demo()”的,
当执行到这里,我们发现此时对象已经不唯一了,
所以应该怎么办呢?
解决方法一:
在函数上声明锁:
public static synchronized Demo getDemo(){
if(demo==null)
demo = new Demo();
}
//synchronized 是同步的意思 表示在调用该函数后,
在“A”没有执行完该函数以前,“B”是进不来的,当“A”执行完后,
“B”在进来时demo就已经不为null了,条件不成立,所以“B”是
创建不了对象的,这样就保证了对象的唯一性,但是这样写会严重
影响程序的效率,有没有其他效率比价高的方法呢?
解决方法二、
在函数内部声明锁:
public static Demo getDemo(){
if(demo==null){
synchronized(Demo1.class){ //类名.class
if(demo==null){
demo = new Demo();
}
}
}
}
}*/