----------android培训、java培训期待与您交流!----------
static关键字
从前面可以知道,如果使用一个类分别开辟栈内存及堆内存,在堆内存中要保存对象的属性,如果希望一些属性被所有对象共享,则就要将其声明为static属性,如果一个类中的方法要由类调用,则可以声明为static方法
static个特点
1 随着类的加载而加载
2 优先于对象的存在
3 被所有对象共享
4 可以直接被类名所调用
首先看如下代码
class Person{ //定义Person类
String name ; //定义name属性,暂时不封装
int age ; //定义age属性,暂时不封装
String country = "A城" ; //定义城市属性,有默认值
public Person(String name, int age){
this.name = name ;
this.age = age;
}
public void info(){ //得到信息
System. out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ;
}
};
public class Demo{
public static void main(String args[]){
Personp1 = new Person("张三" ,30) ; // 实例化对象
Personp2 = new Person("李四" ,31) ; // 实例化对象
Personp3 = new Person("王五" ,32) ; // 实例化对象
p1.info();
p2.info();
p3.info();
}
};
结果:姓名:张三,年龄:30,城市:A城
姓名:李四,年龄:31,城市:A城
姓名:王五,年龄:32,城市:A城
此时如果城市名字要修改为"A城",而且此类已经有100个对象了,那么这意味着要把这100个对象中的城市属性都修改一次,这样肯定是不行的。最好的做法是一次修改后,所有对象的城市信息都可以修改成功,此时,就可以把城市的属性使用static关键字进行声明
使用static关键字声明城市属性
class Person{ //定义Person类
String name ; //定义name属性,暂时不封装
int age ; //定义age属性,暂时不封装
static String country = "A城" ; //定义城市属性,有默认值,static
public Person(String name, int age){
this.name = name ;
this.age = age;
}
public void info(){ //得到信息
System. out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ;
}
};
public class Demo{
public static void main(String args[]){
Personp1 = new Person("张三" ,30) ; // 实例化对象
Personp2 = new Person("李四" ,31) ; // 实例化对象
Personp3 = new Person("王五" ,32) ; // 实例化对象
System. out.println("---------------修改之前 -------------" ) ;
p1.info();
p2.info();
p3.info();
p1. country = "B城" ; //修改static属性
//类的公共属性最好由类进行修改,因为用户不知道一个类到底产生了多少个对象
Person.contry = "B"
System. out.println("---------------修改之后 -------------" ) ;
p1.info();
p2.info();
p3.info();
}
};
结果:---------------修改之前 -------------
姓名:张三,年龄:30,城市:A城
姓名:李四,年龄:31,城市:A城
姓名:王五,年龄:32,城市:A城
--------------- 修改之后 -------------
姓名:张三,年龄:30,城市:B城
姓名:李四,年龄:31,城市:B城
姓名:王五,年龄:32,城市:B城
PS:如上所述,只修改了一个对象的城市属性,全部对象的城市属性内容都发生了变化,说明使用static声明的属性是所有对象共享的
PS:在java中,主要存在4块内存空间
栈内存空间:保存所有对象的对象名称(保存了引用的堆内存空间地址)
堆内存空间:一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收,保存每个对象的属性内容
全局数据区:保存static类型的属性(全局变量,静态变量和字符串常量,不释放)
全局代码区:存放程序中方法的二进制代码,而且是多个对象共享一个代码空间区域
使用static声明方法
用static声明的方法,又是也称为类方法.
代码实例---使用static声明方法
class Person{ //定义Person类
private String name ; //定义name属性,暂时不封装
private int age ; //定义age属性,暂时不封装
private static String country = "A城" ; //定义城市属性,有默认值,static
public static void setCountry(String c){ // 此方法可以直接由类名称调用
country = c ;
}
public static String getCountry(){
return country ;
}
public Person(String name, int age){
this.name = name ;
this.age = age;
}
public void info(){ //得到信息
System. out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ;
}
};
public class Demo{
public static void main(String args[]){
Personp1 = new Person("张三" ,30) ; // 实例化对象
Personp2 = new Person("李四" ,31) ; // 实例化对象
Personp3 = new Person("王五" ,32) ; // 实例化对象
System. out.println("---------------修改之前 -------------" ) ;
p1.info();
p2.info();
p3.info();
Person. setCountry("B城") ; //调用静态方法修改static属性的内容
System. out.println("---------------修改之后 -------------" ) ;
p1.info();
p2.info();
p3.info();
}
};
结果:---------------修改之前 -------------
姓名:张三,年龄:30,城市:A城
姓名:李四,年龄:31,城市:A城
姓名:王五,年龄:32,城市:A城
--------------- 修改之后 -------------
姓名:张三,年龄:30,城市:B城
姓名:李四,年龄:31,城市:B城
姓名:王五,年龄:32,城市:B城
PS:在此说明,非static声明的方法可以去调用static声明的属性或者方法。但是static声明的方法是不能调用非static类型声明的属性或者方法。因为程序中所有的属性和方法必须在对象开辟堆内存之后才可以调用。而static类型的方法在对象没有初始化就可以调用。
static关键字的应用
统计一个到底产生了多少对象
class Demo1{ //定义Person类
private static int count = 0 ; // 所有对象共享此属性
public Demo1(){
count++; //只要有对象产生就应该自增
System. out.println("产生了" + count + "个对象!" ) ;
}
};
public class Demo{
public static void main(String args[]){
new Demo1(); //增加新对象
new Demo1(); //增加新对象
new Demo1(); //增加新对象
}
};
结果:产生了1个对象!
产生了2个对象!
产生了3个对象!
PS:static是一个修饰符,用来修饰成员(成员变量,函数),当一个成员被静态修饰后,就多了一个调用方法,除了可以被对象调用外,还可以直接被类名调用,类名.静态成员
main方法
之前使用的mian方法的定义中,一直有static关键字存在,那么主方法每个参数的含义是什么?
public:表示此方法可以被外部调用,权限static:表示主函数随着类的加载就已经存在了
void:表示主函数没有具体的返回值
main:不是关键字,但是是一个特殊的单词,表示可以被jvm识别
(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。主函数是固定格式的;Jvm识别。jvm在调用输函数时,传入的是new String[0]
http://lavasoft.blog.51cto.com/62575/53263/可参考此学习
代码块
所谓的代码块,是指使用{}括起来的一段代码,根据位置不同,代码块可以分为普通代码块,构造块,静态代码快,同步代码块4种。
普通代码块
直接在方法或是语句中定义的代码块
public class Demo{
public static void main(String args[]){
{ //普通代码块
int x = 30 ; //就属于一个局部变量
System. out.println("普通代码块 --> x = " + x) ;
}
int x = 100; //与局部变量名称相同
System. out.println("代码块之外 --> x = " + x) ;
}
};
结果:普通代码块 --> x = 30
代码块之外 --> x = 100
构造块
直接写在类中的代码块
class Demo1{
{ //直接在类中编写代码块,称为构造块
System. out.println("1、构造块。" ) ;
}
public Demo1(){ //定义构造方法
System. out.println("2、构造方法。" ) ;
}
};
public class Demo{
public static void main(String args[]){
new Demo1(); //实例化对象
new Demo1(); //实例化对象
new Demo1(); //实例化对象
}
};
结果:1、构造块。
2、构造方法。
1、构造块。
2、构造方法。
1、构造块。
2、构造方法。
ps:构造块优先于构造方法执行
静态代码块
静态代码块是使用static关键字声明的代码块
class Demo1{
{ //直接在类中编写代码块,称为构造块
System. out.println( "1、构造块。" ) ;
}
static{ //使用static,称为静态代码块
System. out.println( "0、静态代码块" ) ;
}
public Demo1(){ //定义构造方法
System. out.println( "2、构造方法。" ) ;
}
};
public class Demo{
static{ //在主方法所在的类中定义静态块
System. out.println( "在主方法所在类中定义的代码块" ) ;
}
public static void main(String args[]){
new Demo1(); //实例化对象
new Demo1(); //实例化对象
new Demo1(); //实例化对象
}
};
结果:
在主方法所在类中定义的代码块
0、静态代码块
1、构造块。
2、构造方法。
1、构造块。
2、构造方法。
1、构造块。
2、构造方法。
PS:静态代码块优先于主方法执行,而在类中定义的静态代码块会优先于构造块执行,而且不管多少个对象产生,静态代码块只执行一次。
PS:优先级顺序:main中静态代码块>一般静态代码块>构造代码块>普通代码块
而且静态代码块只执行一次!
构造方法私有化
类的封装性不只体现在对属性的封装上,实际上方法也是可以被封装的,当然,在方法封装中也包含了对构造方法的封装
代码
class Singleton{
private Singleton(){ //此处将构造方法进行封装
}
public void print(){
System. out.println("hello" );
}
}
一个类要想使用,必须有实例化对象的产生,而且现在要是想调用Singleton类中的print()方法,而且现在要是想调用Singleton类中的print()方法,则一定要首先产生Singleton的实例化对象,但是由于此时构造方法被私有化,如果直接声明对象调用,肯定会出错.
此时可以在类内部,生产一个instance对象,再传递出去.(引申出单例设计模式)
实例代码--单例设计模式
饿汉式---直接将对象定义出来
class Singleton{
private static Singleton instance = new Singleton() ; // 在内部直接产生本类的实例化对象
public static SingletongetInstance(){ //通过静态方法取得instance对象
return instance ;
}
private Singleton(){ //将构造方法进行了封装,私有化
}
public void print(){
System. out.println("Hello World!!!" ) ;
}
};
public class Demo{
public static void main(String args[]){
Singletons1 = null ; //声明对象
s1= Singleton. getInstance() ; //取得实例化对象
s1.print(); //调用方法
}
};
结果:Hello World!!!
懒汉式---只给出变量,并不将其初始化
class Singleton{
//先定义,但是不创建对象,并将属性进行封装
private static Singleton instance =null;
private Singleton(){
}
public void print(){//实现一个print方法,打印信息
System. out.println("Hello World!!!" );
}
public static Singleton getInstance(){ //通过静态方法取得对象
if(instance ==null){//当前没有Singleton对象时,才创建
synchronized(Singleton.class){//使用synchronized,保证同步读取数据的安全性
if(instance ==null){
instance = new Singleton();//实例化Singleton对象,只有在对象需要的时候才会有对象
}
}
}
return instance;
}
}
public class Test3{
public static void main(String[] args){
Singletons1 = Singleton.getInstance();//取得Singleton对象的实例
s1.print(); //打印信息
}
}
结果:Hello World!!!
小结:
1 使用static关键字修饰的属性,称为类属性
2 在java中,主要存在4块内存空间
栈内存空间:保存所有对象的对象名称(保存了引用的堆内存空间地址)
堆内存空间:一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收,保存每个对象的属性内容
全局数据区:保存static类型的属性(全局变量,静态变量和字符串常量,不释放)