上季内容回顾:
1、内部类
2、对象数组的使用
本季主要知识点:
本季要点:static关键字的使用。
本季讲解了Java中static关键字的使用以及单态设计模式。
static的使用
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static
设计一个类:Person类,有name、age、city三个属性
class Person
{
  //为了方便,属性暂时不封装
  String name ;
  int age ;
  //所在城市默认为南京
  String city = "南京" ;
  public Person(String name,int age)
  {
    this.name = name ;
    this.age = age ;
  }
  public String getInfo()
  {
    return "姓名:"+name+",年龄:"+age+",城市:"+city ;    
  }
};
public class Demo01
{
  public static void main(String args[])
  {
    Person p1 = new Person("张三",30) ;
    Person p2 = new Person("李四",31) ;
    Person p3 = new Person("王五",32) ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
  }
};
 
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_02
先把内存结构图画出来
仔细观察,这三个对象的city属性的值都是南京,就好比说我现在所产生的人都是南京人。
那么这样的设计就会存在问题:
1、 属性的内容重复存在,所有对象都有此属性
2、 如果现在假设南京变为北京了,假设已经产生了100000个对象,则此时如果要修改其所在城市属性的内容,则肯定要修改100000遍
解决方法:
· 所有的对象都共同指向同一个city属性是最好的,有一个对象将city属性修改了,则其他的也会影响。此时就需要使用static标识city属性了。
class Person
{
  //为了方便,属性暂时不封装
  String name ;
  int age ;
  //所在城市默认为南京
  static String city = "南京" ;
  public Person(String name,int age)
  {
    this.name = name ;
    this.age = age ;
  }
  public String getInfo()
  {
    return "姓名:"+name+",年龄:"+age+",城市:"+city ;    
  }
};
public class Demo02
{
  public static void main(String args[])
  {
    Person p1 = new Person("张三",30) ;
    Person p2 = new Person("李四",31) ;
    Person p3 = new Person("王五",32) ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_04
再来看下内存结构
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_05
加入static 声明之后所有的static 类型的属性都保存在了全局数据区之中,所有的对象都共同拥有同一个city属性了。
class Person
{
  //为了方便,属性暂时不封装
  String name ;
  int age ;
  //所在城市默认为南京
  static String city = "南京" ;
  public Person(String name,int age)
  {
    this.name = name ;
    this.age = age ;
  }
  public String getInfo()
  {
    return "姓名:"+name+",年龄:"+age+",城市:"+city ;    
  }
};
public class Demo03
{
  public static void main(String args[])
  {
    Person p1 = new Person("张三",30) ;
    Person p2 = new Person("李四",31) ;
    Person p3 = new Person("王五",32) ;
    System.out.println("----------修改city属性之前----------") ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
    System.out.println("----------修改city属性之后----------") ;
    //通过一个对象修改city属性值
    p1.city = "北京" ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
  }
};
验证下效果
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_06
一个对象修改static属性之后,其他的所有对象都可以更改了。
但是以上的程序有一些不妥,一个城市改变是应该由某个人(某个对象)去做的吗?应该是由对象的集合体去做,对象的集合体就是类,所以一般在访问static属性的时候都采用如下格式:
· 类名称.static属性      这是最合理的。
class Person
{
  //为了方便,属性暂时不封装
  String name ;
  int age ;
  //所在城市默认为南京
  static String city = "南京" ;
  public Person(String name,int age)
  {
    this.name = name ;
    this.age = age ;
  }
  public String getInfo()
  {
    return "姓名:"+name+",年龄:"+age+",城市:"+city ;    
  }
};
public class Demo04
{
  public static void main(String args[])
  {
    Person p1 = new Person("张三",30) ;
    Person p2 = new Person("李四",31) ;
    Person p3 = new Person("王五",32) ;
    System.out.println("----------修改city属性之前----------") ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
    System.out.println("----------修改city属性之后----------") ;
    //通过一个对象修改city属性值
    //最好是通过类名称去修改static属性,即static属性可以被类名称直接访问
    Person.city = "北京" ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
  }
};
验证一下
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_07
有些时候也有人把static类型的属性称为类属性(类变量),因为可以直接由类名称进行访问。既然static 可以声明属性,则static 也可以声明方法,使用static 声明的方法称为类方法,也可以由类名称直接调用。
class Person
{
  //为了方便,属性暂时不封装
  private String name ;
  private int age ;
  //所在城市默认为南京
  private static String city = "南京" ;
  //只编写一个可以修改city的方法
  public static void setCity(String city)
  {
    this.city = city ;
  }
  public Person(String name,int age)
  {
    this.name = name ;
    this.age = age ;
  }
  public String getInfo()
  {
    return "姓名:"+name+",年龄:"+age+",城市:"+city ;    
  }
};
public class Demo05
{
  public static void main(String args[])
  {
    Person p1 = new Person("张三",30) ;
    Person p2 = new Person("李四",31) ;
    Person p3 = new Person("王五",32) ;
    System.out.println("----------修改city属性之前----------") ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
    System.out.println("----------修改city属性之后----------") ;
    //通过一个对象修改city属性值
    //最好是通过类名称去修改static属性,即static属性可以被类名称直接访问
    //Person.city = "北京" ;
    Person.setCity("无锡") ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
  }
};
这样验证下有没问题哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_08
class Person
{
  //为了方便,属性暂时不封装
  private String name ;
  private int age ;
  //所在城市默认为南京
  private static String city = "南京" ;
  //只编写一个可以修改city的方法
  public static void setCity(String c)
  {
    //this是表示当前对象,static属性是绝对不能用this表示滴~
    //因为static属性不绝对属于某一个对象
    //this.city = city ;     ---->这是错误滴哈~~~
    city = c ;
  }
  public Person(String name,int age)
  {
    this.name = name ;
    this.age = age ;
  }
  public String getInfo()
  {
    return "姓名:"+name+",年龄:"+age+",城市:"+city ;    
  }
};
public class Demo06
{
  public static void main(String args[])
  {
    Person p1 = new Person("张三",30) ;
    Person p2 = new Person("李四",31) ;
    Person p3 = new Person("王五",32) ;
    System.out.println("----------修改city属性之前----------") ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
    System.out.println("----------修改city属性之后----------") ;
    //通过一个对象修改city属性值
    //最好是通过类名称去修改static属性,即static属性可以被类名称直接访问
    //Person.city = "北京" ;
    // 使用static声明的方法可以直接使用类名称调用
    Person.setCity("无锡") ;
    System.out.println(p1.getInfo()) ;
    System.out.println(p2.getInfo()) ;
    System.out.println(p3.getInfo()) ;
  }
};
看下程序效果
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_09
Static使用的限制:
1、使用static声明的方法能否访问static声明的属性呢?允许的
class Demo07
{
  static String name = "Michael" ;
  public static void fun()
  {
    System.out.println(name);
  }
};
编译通过哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_10
2、使用static方法能否访问非static声明的属性呢?不允许的
class Demo08
{
  String name = "Michael" ;
  public static void fun()
  {
    System.out.println(name);
  }
};
编译不能通过,说明是不允许滴~~~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_11
3、使用非static方法能否访问static声明的属性呢?允许的
class Demo09
{
  static String name = "Michael" ;
  public void fun()
  {
    System.out.println(name);
  }
};
编译通过,说明是允许滴
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_构造方法_12
4、使用非static能否访问非static声明的属性呢?允许的
class Demo10
{
  String name = "Michael" ;
  public void fun()
  {
    System.out.println(name);
  }
};
这个编译也通过,说明也是允许滴
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_13
Main方法调用其他方法的问题:
· 之前讲解方法的时候给了一个限制:如果一个方法想被主方法直接调用,则此方法声明时必须加上public static才可以。
public class Demo11
{
  public static void main(String args[])
  {
    fun();
  }
  public static void fun()
  {
    System.out.println("http://redking.blog.51cto.com");
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_14
如果我们在fun()方法前没有加上static滴话,我们看下会报什么错误
public class Demo12
{
  public static void main(String args[])
  {
    fun();
  }
  public void fun()
  {
    System.out.println("http://redking.blog.51cto.com");
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_15
注意:static类型的方法只能调用static类型的方法
public class Demo13
{
  //static类型的方法只能调用static类型的方法
  public static void main(String args[])
  {
    //如果fun()方法前不加static,则只能这样调用
    new Demo13().fun();
  }
  public void fun()
  {
    System.out.println("http://redking.blog.51cto.com");
  }
};
程序执行正常
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_16
主方法的含义:public static void main(String args[])
理解main方法
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_17
String args[]:表示运行时的参数 ==> 表示String类型的对象数组
public class Demo14
{
  public static void main(String args[])
  {
    for (int i=0;i<args.length ;i++ )
    {
      System.out.println(args[i]);
    }
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_18
我们发现没有内容输出哈,那我们在javac Demo14.java后面跟上几个数据哈,以空格分开
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_19
所有的参数会在命令后面加入空格的形式出现。
我们做个练习哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_20
public class Demo15
{
  public static void main(String args[])
  {
    //必须输入两个参数
    if (args.length!=2)
    {
      //表示不是两个参数,则要退出系统
      System.out.println("运行参数不正确,正确的格式为:");
      System.out.println("java Demo15 用户名 密码");
      System.exit(1);
    }
    //之后的程序就表示肯定已经成功的输入了用户名和密码哈~~~
    String userName = args[0];
    String userPasswd = args[1];
    //判断用户名是否为abc,密码是否为123哈~~~
    //为什么现在要用字符串.equals去判断而不是用username调用equals哈~
    //这样可以有效滴避免NullPointerException
    if ("abc".equals(userName)&&"123".equals(userPasswd))
    {
      System.out.println("欢迎访问哈~~~");
    }
    else
    {
      System.out.println("用户名和密码不正确哈~~~");
    }
  }
};
验证一下程序
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_21
解释:为什么要把字符串放在前面比较
public class Demo16
{
  public static void main(String args[])
  {
    String str = "http://redking.blog.51cto.com";
    System.out.println(str.equals("http://redking.blog.51cto.com"));
  }
};
程序执行下,看下有没问题哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_22
结果为true,没有出错哈,但是大家知道str是引用数据类型哈,如果str值为null空的话,就会出现问题。
public class Demo17
{
  public static void main(String args[])
  {
    String str = null;
    System.out.println(str.equals("http://redking.blog.51cto.com"));
  }
};
程序提示NullPointerException错误哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_23
那我们现在把str和字符串交换下位置看下效果
public class Demo18
{
  public static void main(String args[])
  {
    String str = null;
    System.out.println("http://redking.blog.51cto.com".equals(str));
  }
};
字符串http://redking.blog.51cto.com 永远不会为空哈,所以不会报NullPointerException错误哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_构造方法_24
因此我们在开发中经常把字符串写在前面,然后调用equals方法进行比较哈,这样可以避免出现错误~~
Static的基本概念已经掌握清楚了,那么还可以在以下一种情况下使用:
· 如果现在想统计一个类到底产生了多少个对象时,就需要使用static关键字了,因为所有的对象都只拥有同一个static类型的属性。
class Demo
{
  private static int count = 1;
  public Demo()
  {
    System.out.println("产生了"+(count++)+"个对象~~~~");    
  }
}
public class Demo19
{
  public static void main(String args[])
  {
    new Demo();
    new Demo();
    new Demo();
    new Demo();
    new Demo();
  }
};
这个程序只是简单测试一下哈,因为垃圾回收时间不确定,呵呵
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_static_25
 
代码块:java中存在四种代码块:
1、普通代码块:是直接写在各个方法中的代码块
public class Demo20
{
  public static void main(String args[])
  {
    //普通代码块
    {
    int i = 10;
    System.out.println(i);
    }
    //在代码块里定义的变量实际上是一个局部变量
    int i = 99;
    System.out.println(i);
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_构造方法_26
2、构造块:是直接写在类中的代码块,在实例化对象的时候调用,而且每实例化一个对象就要调用一次构造块(多次调用)。构造块优先于构造方法执行。
class Demo
{
  {
    //构造块
    System.out.println("Demo类中的构造块~~~");
  }
}
public class Demo21
{
  public static void main(String args[])
  {
    new Demo();
    new Demo();
    new Demo();
    new Demo();
    new Demo();
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_27
我们来验证一下构造块优先于构造方法执行
class Demo
{
  {
    //构造块
    System.out.println("Demo类中的构造块~~~");
  }
  Demo()
  {
    System.out.println("Demo类中的构造方法~~~");
  }
}
public class Demo22
{
  public static void main(String args[])
  {
    new Demo();
    new Demo();
    new Demo();
    new Demo();
    new Demo();
  }
};
我们看到构造块优先于构造方法执行哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_28
3、静态块:是使用static声明的代码块,静态块只调用一次,而且优先于构造块执行。
作用:为static类型的属性初始化
class Demo
{
  {
    //构造块
    System.out.println("Demo类中的构造块~~~");
  }
  Demo()
  {
    System.out.println("Demo类中的构造方法~~~");
  }
  //静态块
  static
  {
    System.out.println("Demo类中的静态块~~~");
  }
}
public class Demo23
{
  public static void main(String args[])
  {
    new Demo();
    new Demo();
    new Demo();
    new Demo();
    new Demo();
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_29
在主类中写的静态块要优先于main方法执行
class Demo
{
  {
    //构造块
    System.out.println("Demo类中的构造块~~~");
  }
  Demo()
  {
    System.out.println("Demo类中的构造方法~~~");
  }
  //静态块
  static
  {
    System.out.println("Demo类中的静态块~~~");
  }
}
public class Demo24
{
  //在主类中写的静态块要优先于main方法执行
  static{
    System.out.println("##################");
  }
  public static void main(String args[])
  {
    new Demo();
    new Demo();
    new Demo();
    new Demo();
    new Demo();
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_30
小问题:
能不能不写主方法而打印出“HELLO WORLD”? 肯定可以,使用静态块哈~
public class Demo25
{
  //在主类中写的静态块要优先于main方法执行
  static{
    System.out.println("Hello World!!!");
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_面向对象_31
我们发现可以输出字符串“Hello World!!!”哈~~~但是程序还是要查找main方法哈,为了防止程序继续执行,我们这样修改代码哈~
public class Demo26
{
  //在主类中写的静态块要优先于main方法执行
  static{
    System.out.println("Hello World!!!");
    //为了防止程序继续向后执行,去找main方法,此处可以使系统退出
    System.exit(1);
  }
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_32
4、同步代码块
(在多线程中我们来讲哈~~~)
构造方法的私有
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_33
封装性:private
可以声明一个属性,也可以声明一个方法,同样也可以使用private声明一个构造方法。
class Single
{
        private Single(){}
        public void print(){
                System.out.println("Hello World~~~");
        }
}
public class Demo27
{
        public static void main(String args[])
        {
        //如果想调用print方法,则必须产生Single类的实例化对象
        Single s = null;
        s = new Single();
        }
};
我们发现程序提示Single()被封装了哈~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_JAVA_34
class Single    
{    
        private Single(){}    
        public void getInstance()    
        {    
                //可以在类的内部产生自己的实例化对象    
                new Single();    
        }    
        public void print(){    
                System.out.println("Hello World~~~");    
        }    
}    
public class Demo27    
{    
        public static void main(String args[])    
        {    
        //如果想调用print方法,则必须产生Single类的实例化对象    
        Single s = null;    
        //s = new Single();    
        // 对象有引用传递。有没有一种可能可以在Single类的内部产生自己的对象呢?    
        }    
};
编译正常哈,可以在类的内部产生自己的实例化对象
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_构造方法_35
class Single    
{    
        private Single(){}    
        public static Single getInstance()    
        {    
                //可以在类的内部产生自己的实例化对象    
                return new Single();    
        }    
        public void print(){    
                System.out.println("Hello World~~~");    
        }    
}    
public class Demo27    
{    
        public static void main(String args[])    
        {    
        //如果想调用print方法,则必须产生Single类的实例化对象    
        Single s = null;    
        s = Single.getInstance();    
        // 对象有引用传递。有没有一种可能可以在Single类的内部产生自己的对象呢?    
        s.print();    
        }    
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_36
结论:
一个类的构造方法如果被私有化了,则外部肯定无法看见,则此时就可以在类的内部产生实例化对象之后将此对象传递到外面去就可以了。
构造方法私有化的目的:在于限制对象的产生
· 如果一个类只能要求有一个实例化对象的时候呢?
· 唯一可以做的就是在产生实例化对象的入口处加入限制 —— 构造方法的私有化

单态设计:
一个类永远只能产生一个实例化对象。  JAVA 类库中有很多地方都使用了单态。
//一个类只能产生一个实例Single@35ce36,这就叫单态设计    
class Single    
{    
        //在类内部产生自己的实例化对象,只实例化一次    
        private static Single s = new Single();    
        private Single(){}    
        public static Single getInstance()    
        {    
                //可以在类的内部产生自己的实例化对象    
                return s;    
        }    
        public void print(){    
                System.out.println("Hello World~~~");    
        }    
}    
public class Demo27    
{    
        public static void main(String args[])    
        {    
        //如果想调用print方法,则必须产生Single类的实例化对象    
        Single s1 = null;    
        s1 = Single.getInstance();    
        // 对象有引用传递。有没有一种可能可以在Single类的内部产生自己的对象呢?    
        s1.print();    
        //要产生第二个对象,也是取滴s对象    
        Single s2 = Single.getInstance();    
        System.out.println(s2);    
        System.out.println(s1);    
        }    
};
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_37 
总结
本季重点哈~~~
[零基础学JAVA]Java SE面向对象部分-12.面向对象基础(07)_零基础学JAVA_38
#############################################################################
ps:面向对象基础本季就完结了哈,下季学习面向对象高级部分:继承和多态O(^_^)O
#############################################################################