static块,final, 常量设计,常量池,不可变对象和字符串

static

	// static 
	pubilc class Student{
		private static int age; // 静态的变量
		private double score;   // 非静态的变量

		public void run(){
		}
		
		public static void go(){
		}

		public static void main(String[] args){
			Student s1 = new Student();
				
			System.out.println(Student.age);
			System.out.println(s1.age);
			System.out.println(s1.score);
		
			// 非静态方法调用
			new Studnet().run();
			// 静态方法的调用
			// 静态方法不能调用非静态方法
			// 或者在当前类中直接go(); 也可以类名.静态方法名();
			Studnet.go();
		}
	}

单独类的执行顺序

public class Person{
	// 2.赋初值~
	{
		System.out.println("匿名代码块");
	}
	// 1.只执行一次
	static{
		System.out.println("静态代码块");
	}
	// 3
	public Person(){
		System.out.println("构造方法");
	}
	
	public static void main(String[] args){
		Person p1 = new Person();
		System.out.println("=================");	
		Person p2 = new Person();
		// 执行结果为:
		// 静态代码块
		// 匿名代码块
		// 构造方法
		// =================
		// 匿名代码块
		// 构造方法
	}
}
静态导入包
// 静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test{
	public static void main(String[] args){
		System.out.println(random());
		System.out.println(PI);
	}
}

final关键字

  • Java的final关键字用来修饰

    • 方法
    • 字段
  • final的类, 不能被继承

  • 父类中如果有final的方法, 子类不能改写此方法

  • final的变量, 不能再次赋值
    - 如果是基本类型, 不能修改其值
    - 如果是对象实例, 那么不能修改其指针(但是可以修改其内部的值)

常量设计

  • 常量: 一种不会修改的变量
    • java没有constant关键字
    • 不能修改, final
    • 不会/修改/只读/只要一份, static
    • 方便访问public
      Java中的常量
    • public static final
    • 建议变量名字全大写, 以连字符相连, 如PI_NUMBER
  • 一种特殊的常量: 接口内定义的变量默认就是常量

常量池

public static void main(String[] args) {
	Integer n1 = 127;
	Integer n2 = 127;
	System.out.println(n1 == n2);// true
	Integer n3 = 128;
	Integer n4 = 128;
	System.out.println(n3 == n4);// false
	Integer n5 = new Integer(127);
	System.out.println(n1 == n5);// false
}
  • Java为很多基本类型的包装类/字符串都建立常量池
  • 常量池: 相同的值只存储一份, 节省内存, 共享访问
  • 基本类型的包装类
    - Boolean, Byte, Short, Integer, Long, Character, Float, Double
    - Boolean: true, false
    - Byte: -128~127, Character: 0~127
    - Short, Int, Long: -128~127
    - Float, Double: 没有缓存(常量池)
字符串常量池
public static void main(String[] args){
	String s1 = "abc";
	String s2 = "abc";
	String s3 = "ab" + "c";
	String s4 = "a" + "b" + "c";// 都是常量, 编译器将优化, 下同
	System.out.println(s1 == s2);// true
	System.out.println(s1 == s3);// true
	System.out.println(s1 == s4);// true
}
  • 基本类型的包装类和字符串有两种创建方式
    • 常量式(字面量)赋值创建, 放在栈内存(将被常量化)
      • Integer a = 10;
      • String b = “abc”;
    • new 对象进行创建, 放在堆内存(不会常量化)
      • Integer c = new Integer(10);
      • String d = new String(“abc”);
  • 这两种创建方式导致创建的对想存放的位置不同
自动拆装箱
int 与Integer
public static void main(String[] args) {
	int i1 = 10;
	Integer i2 = 10;	// 自动装箱
	System.out.println(i1 == i2);// true
	// 自动拆箱 基本类型和包装类进行比较, 包装类自动拆箱
	
	Integer i3 = new Integer(10);
	System.out.println(i1 == i3); // true
	// 自动拆箱, 基本类型和包装类进行比较, 包装类自动拆箱

	System.out.println(i2 == i3);// false
	// 两个对象比较, 比较其地址。
	// i2是常量, 放在栈内存常量池中, i3是new出对象, 放在堆内存中

	Integer i4 = new Integer(5);
	Integer i5 = new Integer(5);
	System.out.println(i1 == (i4 + i5));// true
	System.out.println(i2 == (i4 + i5));// true
	System.out.println(i3 == (i4 + i5));// true
	// i4 + i5操作将会使得i4 + i5自动拆箱为基本类型并运算得到10
	// 基本类型10和对象比较, 将会使对象自动拆箱, 做基本类型比较

	Integer i6 = i4 + i5; // +操作使得i4,i5自动拆箱, 得到10, 因此i6 == i2.
	System.out.println(i1 == i6);// true
	System.out.println(i2 == i6);// true
	System.out.println(i3 == i6);// false
}
String类
public static void main(String[] args) {
	String s0 = "abcdef";
	String s1 = "abc";
	String s2 = "abc";
	String s3 = new String("abc");
	String s4 = new String("abc");
	System.out.println(s1 == s2); // true 常量池
	System.out.println(s1 == s3); // false 一个栈内存, 一个堆内存
	System.out.println(s3 == s4); // false 两个都是堆内存
	System.out.println("=================");

	String s5 = s1 + "def";// 涉及到变量, 故编译器不优化
	String s6 = "abc" + "def";// 都是常量 编译器会自动优化成abcdef
	String s7 = "abc" + new String("def");// 涉及到new对象, 编译器不优化
	System.out.println(s5 == s6);// false
	System.out.println(s5 == s7);// false
	System.out.println(s6 == s7);// false
	System.out.println(s0 == s6);// true
	System.out.println("=================");

	String s8 = s3 + "def";// 涉及到new对象, 编译器不优化
	String s9 = s4 + "def";// 涉及到new对象, 编译器不优化
	String s10 = s3 + new String("def");// 涉及到new对象, 编译器不优化
	System.out.println(s8 == s9);// false
	System.out.println(s8 == s10);// false
	System.out.println(s9 == s10);// false
	
}

不可变对象

  • 不可变对象(Immutable Object)
    • 一旦创建, 这个对象(状态/值)不能被更改了
    • 其内在的成员变量的值不能修改了。
    • 八个基本类型的包装类
    • String, BigInteger 和 BigDecimal等
  • 可变对象(Mutable Object)
    • 普通对象
String a = new String("abc");// 该值在堆中
String b = a;// 将a的指针复制给b
System.out.println(b);// abc
a = "def";// 因为string是不可变对象, 这一步相当于, 又新开了一个内存空间"def", 将a的指针指向它, 之前指向"abc"的指针断掉
System.out.println(b);// abc, b的指针还是指向abc

public static void change(String b){// b的指针指向堆中"abc"
	b = "def";// 在栈中申请一个"def"内存空间, 让b指向栈中的值, 故b不指向堆中的"abc"
}

a = new String("abc");// 该值在堆中
change(a);// 值a的指针传入
System.out.println(a);// abc
如何创建不可变对象
- immutable 对象是不可改变, 有改变, 请clone/new一个对象进行更改
- 所有属性都是final 和private的
- 不提供setter方法
- 类是final, 或所有的方法都是final
- 类中包含mutable对象(可变对象), 那么返回拷贝需要深度clone
不可变对象的优缺点
优点: 
- 只读, 线程安全
- 并发读, 提高性能
- 可以重复使用
缺点:
- 制造垃圾, 浪费空间
- 对不可变对象进行修改时, 会新开辟空间, 旧对象则会被搁置, 直到垃圾回收。

Java字符串

- 字符串是Java使用最多的类, 是一种典型的不可变对象
- String 定义有两种
	- String a = "abc";// 常量赋值, 栈分配内存
	- String b = new String("abc");// new对象, 堆分配内存
- 字符串内容比较: equals方法
- 是否指向同一对象: 指针比较==
- Java常量池
	- 保存在编译期间就已经确定的数据
	- 是一块特殊的内存
	- 相同的常量字符只存储一份, 节省内存, 共享访问 
	- 注: 常量字符串, 如果是new关键字的字符串是不算上一条规则的

字符串的加法

- String a = "abc";
- a = a + "def";// 由于string不可修改, 效率差
- 使用StringBuffer/StringBuilder类的append方法进行修改
- StringBuffer/StringBuilder的对象都是可变对象
- StringBuffer(同步, 线程安全, 修改快速), StringBuilder(不同步, 线程不安全, 修改更快)
public static void main(String[] args) {
	Calendar t1 = Calendar.getInstance();
	String string = new String("");
	for (int i = 0; i < 50000; i++) {
		string += i + ",";
	} 
	System.out.println(Calendar.getInstance.getTimeInMillis() - t1.getTimeInMillis());

	Calendar t2 = Calendar.getInstance();
	StringBuffer stringBuffer = new StringBuffer("");
	for (int i = 0; i < 50000; i++) {
		stringBuffer.append(i);
		stringBuffer.append(",");
	}
	System.out.println(Calendar.getInstance.getTimeInMillis() - t2.getTimeInMillis());

	Calendar t3 = Calendar.getInstance();
	StringBuilder stringBuilder = new StringBuilder("");
	for (int i = 0; i < 50000; i++) {
		stringBuilder.append(i);
		stringBuilder.append(",");
	}
}
public static void changeValue(int a){
	a = 10;
}
public static void changeValue(String string){
	string = "def";// 创建一个"def", 将string的指针指向"def"
}
public static void changeValue(StringBuffer stringBuffer){
	stringBuffer.append("def");// 是在原有基础增加
	stringBuffer = new StringBuffer("zzz");// 可理解成新建一个stringBuffer对象, 将stringBuffer的指针指向新建的stringBuffer对象	
}  
public static void main(String[] args) {
	int a = 5;
	String s1 = "abc";
	StringBuffer stringBuffer = new StringBuffer("abc");
	changeValue(a);
	changeValue(s1);
	changeValue(stringBuffer);
	System.out.println(a);// 5
	System.out.println(s1);// abc
	System.out.println(stringBuffer);// abcdef
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值