Java static,final和常量设计

6 static、final和常量设计

6.1static(静态)
6.1.1static变量
  • static关键字可用在变量、方法、类和匿名方法块中,在内存中只有一种拷贝
  • 静态变量是类的共有成员
public class Potato 
{
    static int price = 5;
    String content = "";
    public Potato(int price,String content)
    {
        this.price = price;
        this.content = content;
    }
    public static void main(String[] args) 
    {
        System.out.println(Potato.price);//5
        //System.out.println(Potato.content);// wrong
        System.out.println("-------------");
        Potato obj1 = new Potato(10,"青椒土豆丝");
        System.out.println(Potato.price);//10
        System.out.println(obj1.price);//10
    }
}
6.1.2static方法
  • static变量只依赖于类存在(通过类即可访问),不依赖对象实例存在。
  • 在静态方法中,只能使用静态变量,不能使用非静态变量
  • 静态方法中禁止引用非静态方法
public class StaticMethodTest 
{
    int a = 1;
    static int b = 2;//静态变量
    public static void hello()//静态方法
    {
        System.out.println("0");
        System.out.println(b);
        //System.out.println(a);//error,cannot call non-static variables
        //hi();//error,cannot call non-static method
    }
    public void hi()
    {
        System.out.println("3");
        hello();                //ok,call static methods
        System.out.println(a); //ok,call non-static methods
        System.out.println(b); //ok,call static variables
    }
    public static void main(String[] args) 
    {
        StaticMethodTest.hello();//02
        //StaticMethodTest.hi();//error,不能使用类名来引用非静态方法
        StaticMethodTest foo = new StaticMethodTest();
        foo.hello();//warning,but it is ok,不建议使用对象调用静态方法,常用类调用//02
        foo.hi();//right//30212
    }
}
6.1.3static快
  • 只在类第一次被加载时调用,在程序运行期间,这段代码只运行一次
  • 执行顺序:static快>匿名快>构造函数
class StaticBlock
{
    //static block > anonymous block > constructor function
    static
    {
        System.out.println("1");
    }//static block
    {
        System.out.println("2");
    }//匿名代码块
    public StaticBlock()//constructor function
    {
        System.out.println("3");
    }
    {
        System.out.println("4");
    }//匿名代码块

}
public class StaticBlockTest 
{
    public static void main(String[] args) 
    {
        System.out.println("0");//0
        StaticBlock obj1 = new StaticBlock();//1243
        StaticBlock obj2 = new StaticBlock();//243
    }
}

不建议编写块代码,因为块代码会给程序带来混淆。建议将块代码封装成函数再调用。

6.2单例模式(单态模式)
  • 限定某一个类在整个程序运行过程中,只能保留一个实例对象在内存空间(内存空间中,一个类只有一个对象存在)
  • 设计模式:在软件开发过程中,经过验证的用于解决在特定环境下的、重复出现的、特定问题的解决方案。
  • 单例模式:保证一个类有且只有一个对象
    • 采用static来共享对象实例
    • 采用private构造函数,防止外界new操作
public class Singleton 
{
    private static Singleton obj = new Singleton();//共享同一个对象
    private String content;
    private Singleton()//确保只能在Singleton类内部调用构造函数
    {
        this.content = "abc";
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public static Singleton getInstance()
    {
        //静态方法使用静态变量
        //另外可以使用方法内的临时变量,但是不能引用非静态的成员变量
        return obj;
    }
    public static void main(String[] args) 
    {
        Singleton obj1 = Singleton.getInstance();
        System.out.println(obj1.getContent());//abc
        Singleton obj2 = Singleton.getInstance();
        System.out.println(obj2.getContent());//abc
        obj2.setContent("def");
        System.out.println(obj1.getContent());//def
        System.out.println(obj2.getContent());//def
        System.out.println(obj1==obj2);//ture,obj1和obj2指向同一个对象
        Singleton obj3 = new Singleton();
        System.out.println(obj3.getContent());//abc
        System.out.println(obj3==obj1);//false
    }
}
6.3 final
  • 可以用来修饰类,方法和字段

  • final修饰的类不能被继承

    final public class FinalFather 
    {
        
    }
    class Son1 extends FinalFather//继承报错
    {
    
    }
    
  • 父类如果有final的方法,子类不能改写此方法

    class FinalMethodFather
    {
        public final void f1()
        {
    
        }
    }
    public class FinalMethodSon extends FinalMethodFather
    {
        public void f1()//不可改写父类final方法
        {
    
        }
    }
    
  • final的变量,不能再次赋值

    • 如果是基本型别的变量,则不能修改其值

      public class FinalPrimitive 
      {
          public static void main(String[] args) 
          {
              final int a = 5;
              a = 10;//报错
          }
      }
      
    • 如果是对象实例,那么不能修改其指针(但是可以修改对象内部的值)

      class FinalObject
      {
          int a = 10;
      }
      public class FinalObjectTest
      {
          public static void main(String[] args) 
          {
              final FinalObject obj1 = new FinalObject();
              System.out.println(obj1.a);
              obj1.a = 20;
              System.out.println(obj1.a);
              // obj1 = new FinalObject();//报错,不能修改其指针
          }
      }
      
6.4常量设计和常量池
6.4.1常量设计
  • 常量:一种不会修改的变量

    • Java没有constant关键字
    • 不能修改final
    • 不会修改/只读/只要一份,static
    • 方便访问public
  • Java中的常量

    • public static final
    • 建议变量名字全大写以”__“相连。
public class Constants 
{
    public static final double PI_NUMBER = 3.14;
    public static final String DEFAUT_COUNTRY = "China";
    public static void main(String[] args) 
    {
        System.out.println(Constants.PI_NUMBER);
        System.out.println(Constants.DEFAUT_COUNTRY);
    }
}
  • 一种特殊的常量:接口内定义的变量默认是常量
interface SpecialAnimal
{
    String color = "yellow";//default:public static final
    public void move();//抽象类
}
public class Cat implements SpecialAnimal
{
    public void move()//补全抽象类
    {
        System.out.println("I can move");
    }
    public static void main(String[] args) 
    {
        Cat cat = new Cat();
        // cat.color = "white";//error,the variables ininterface are constants
    }
}
6.4.2常量池
  • Java为很多基本类型的包装类/字符串都建立常量池
  • 常量池:相同的值只存储一份,节省内存,共享访问
  • 基本类型的包装类
    • Boolean:true,false
    • Byte:-128~127
    • Character:0~127
    • Short,Int.Long:-128~127
    • Float,Double:没有缓存(常量池)
public class CacheTest 
{
    public static void main(String[] args) 
    {
        Boolean b1 = true;//ture ,false
        Boolean b2 = true;
        //判断指针是否相同
        System.out.println("Boolean Test: " + String.valueOf(b1==b2));//true
        Byte b3 = 127;//-128~127
        Byte b4 = 127;
        System.out.println("Byte Test: " + String.valueOf(b3==b4));//true
        Character c1 = 127; //\u0000-\u007f
        Character c2 = 127; 
        System.out.println("Charater Test: " + String.valueOf(c1==c2));//true
        Short s1 = -128;//-128~127
        Short s2 = -128;
        System.out.println("Short Test: " + String.valueOf(s1==s2));//true
        Integer i1 = -128;//-128~127
        Integer i2 = -128;//-128~127
        System.out.println("Integer Test: " + String.valueOf(i1==i2));//true
        Long l1 = -128L;//-128~127
        Long l2 = -128L;//-128~127
        System.out.println("Long Test: " + String.valueOf(l1==l2));//true
        Float f1 = 0.5f;//没有常量池
        Float f2 = 0.5f;
        //在内存中会有两个0.5float类型
        System.out.println("Float Test: " + String.valueOf(f1==f2));//false
        Double d1 = 0.5;//没有常量池
        Double d2 = 0.5;
        System.out.println("Double Test: " + String.valueOf(d1==d2));//false
    }
}
  • Java为常量字符串都建立常量池缓存机制
public class StringConstantTest 
{
    public static void main(String[] args) 
    {
        String s1 = "abc";
        String s2 = "abc";
        String s3 = "a" + "b" + "c";
        String s4 = "ab";
        String s5 = s4 + "c";
        String s6 = "ab" + c;
        System.out.println(s1==s2);//true
        System.out.println(s1==s3);//true,java编译器会优化已经确定的变量
        System.out.println(s1==s5);//false,有变量不优化
        System.out.println(s1==s6);//true都是确定的变量会优化
    }
}
  • 基本类型的包装和字符串有两种创建方式

    • 常量式赋值创建,放在栈内存(将被常量化)

      Integer a = 10;
      String b = "abc";
      
    • new对象进行创建,放在堆内存(不会常量化)

      Integer c = new Integer(10);
      String d = new String("abc");
      
public class BoxClassTest 
{
    public static void main(String[] args) 
    {   
        int i1 = 10;
        Integer i2 = 10;//自动装箱
        System.out.println(i1==i2);//true
        //自动拆箱 基本类型和包装类进行比较,包装类自动拆箱
        Integer i3 = new Integer(10);
        //i2是常量,放在栈内存常量池中,i3是new出对象,放在堆内存中
        System.out.println(i2==i3);//false,两个对象比较,比较其地址
        System.out.println(i1==i3);//true
        Integer i4 = new Integer(5);
        Integer i5 = new Integer(5);
        //i4和i5操作将会使得i4和i5自动拆箱为基本类型并运算得到10,相当于i4+i5变成了int类型
        System.out.println(i1==(i4+i5));//true
        System.out.println(i2==(i4+i5));//true
        System.out.println(i3==(i4+i5));//true
    }
}
6.5 不可变对象和字符串
6.5.1不可变对象
  • 不可变对象
    • 一旦创建,这个对象(状态/值)就不能更改了
    • 且内在的成员变量的值也不能修改
    • 八个基本型别的包装类
    • String,BigInteger和BigDecimal等
String a = new String("abc");//a-->"abc"
String b = a;//b-->"abc"
a = "def";//a-->"def"
System.out.println(b);//abc
public static void change(String b)
{
	b = "def";
}
a = new String("abc");//a-->"abc"
change(a);//b-->"abc",b-->"def"
System.out.println(a);//abc

:只要是对象,函数调用都是传指针

  • 可变对象

    • 普通对象
  • 如何创建不可变对象

    • immutable对象是不可改变的,有改变,请clone/new一个对象进行修改
    • 所有的属性都是final和private的
    • 不提供setter方法
    • 类是final的,或者所有的方法都是final
    • 类中包含mutable对象,那么返回拷贝需要深度clone
  • 不可变对象优点

    • 只读,线程安全
    • 并发读,提高性能
    • 可以重复使用
  • 不可变对象缺点

    • 制造垃圾,浪费空间
6.5.2字符串(一种典型的不可变对象)
  • String的两种定义

    • String a = “abc”;//常量复制,栈分配内存
    • String b = new String(“abc”);//new对象,堆分配内存
  • 字符串内容比较:equals方法

  • 是否指向同一个对象:指针比较==

  • 字符串的加法

    String a = "abc";
    a = a + "def";//由于String不可修改,效率差
    //使用StringBuffer/StringBuider类的append方法进行修改
    //StringBuffer/StringBuilder的对象都是可变对象
    //StringBuffer(同步,线程安全,修改快速),StringBuilder(不同步,线程不安全,修改更快)
    
  • 比较三种字符串加法的效率

    import java.util.Calendar;
    public class StringApeendTest 
    {
        public static void main(String[] args) 
        {
            int n = 50000;
            Calendar t1 = Calendar.getInstance();
            String a = new String();
            for(int i=0;i<n;i++)
            {
                a = a + i + ",";
            }
            System.out.println(Calendar.getInstance().getTimeInMillis()-t1.getTimeInMillis());//2895ms
            Calendar t2 = Calendar.getInstance();
            StringBuffer b = new StringBuffer("");
            for(int i=0;i<n;i++)
            {
                b.append(i);
                b.append(",");
            }
            System.out.println(Calendar.getInstance().getTimeInMillis()-t2.getTimeInMillis());//5ms
            Calendar t3 = Calendar.getInstance();
            StringBuilder c = new StringBuilder("");
            for(int i=0;i<n;i++)
            {
                c.append(i);
                c.append(",");
            }
            System.out.println(Calendar.getInstance().getTimeInMillis()-t3.getTimeInMillis());//2ms
        }
    }
    
  • 不可变对象的传递

    public class ArgumentPassing 
    {
        public static void changeValue(int a)
        {
            a = 10;
        }
        public static void changeValue(String s1)
        {
            s1 = "def";
        }
        public static void changeValue(StringBuffer s1)
        {
            s1.append("def");//可变对象,原地扩张
        }
        public static void main(String[] args) 
        {
            int a = 5;
            String b = "abc";//不可变对象
            StringBuffer c = new StringBuffer("abc");//可变对象
            changeValue(a);//传值,5
            changeValue(b);//传指针,abc,b-->"abc",s1-->"abc",s1-->"def".
            changeValue(c);//abcdef
            System.out.println(a);
            System.out.println(b);
            System.out.println(c);
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值