Java学习笔记2

static

  1. static变量:
    ①只依赖于类存在,可以直接用类名直接引用,不依赖于对象实例存在,无需new对象来引用
    ②不管new多少个对象,static变量的值都共同存储在一个共同的空间(栈)。如果改变static变量的值,再次new新的对象时,相应的static值也是改变后的值
    ③static变量的生存期是从程序开始到结束一直存在。

    public class Potato{
    	static int price = 5;//静态变量
    	String content = "";
    	public Potato(int price, String content){
    		this.price = price;
    		this.content = content;
    	}
    	//main函数
    	public static void main(String[] args)
    	{
    		System.out.println(Potato.price);//静态变量可以用类名直接引用,无需new对象。这里不可以Potato.content,content不是静态变量
    		Potato obj1 = new Potato(10,"青椒肉丝")//这里改变price的值
    		Potato obj2 = new Potato;
    		System.out.println(Potato.price);//10
    		System.out.println(obj1.price);//10
    		System.out.println(obj2.price);//10
    		//这三个在内存里是同一个东西
    	}
    }
    
  2. static方法:
    ①也直接可以用类名直接引用,无需new对象来引用
    ②静态方法中,只能使用静态变量
    ③静态方法禁止引用非静态方法

    public class StaticMethodTest{
    	int a = 111111;
    	static int b = 222222;//静态变量
    	//静态方法
    	public static void hello
    	{
    		System.out.println("000000");
    		System.out.println(b);//right
    		System.out.println(a);//error 静态方法中不能使用非静态变量
    		hi();//error 
    	}
    	 //非静态方法
    	public static void hi
    	{
        	System.out.println("333333");
        	hello();//ok
    	}
    }
    
  3. static块:
    ①static块只在第一次被加载的时候运行
    ②执行顺序:static块 > 匿名块 > 构造函数
    static块:

    static{
    	...
    }
    

    匿名块:

    {
    	...
    }
    

单例模式

单例模式:内存空间中,一个类有且只有一个对象存在。
单例模式属于设计模式中经典的一种,属于创建型模式类型
设计模式: 在软件开发过程中,经过验证的,用于解决在特定环境下的、重复出现的、特定问题的解决方案。设计模式包括:创建型、结构型和行为型
单例模式特点:

  1. 采用static来共享对象实例
  2. 采用private构造函数,防止外界new操作

eg.

public class Singleton{
	//属性全部私有化,只能用方法来获取属性值
	private static Singleton obj = new Singleton();//只在这里new一次,obj是静态变量,会一直存在
	private String content;
	
	//构造函数私有化,确保只能在类的内部调用构造函数,外界无法new(new操作就是调用构造函数)
	private Singleten(){
		this.content = "abc";
	}
	
	//只能用方法来获取属性值
	public String getContent(){
		return content;
	}
	public void setContent(String content){
		this.content = content;
	}
	
	//用静态方法来获取对象
	public static Singleton getInstance(){
		return obj;//返回静态Singleton对象
		//不关在外界调用多少次getInstance(),所获取的对象都是这唯一的一个obj
	}
	
	//main函数
	public static void main(String[] args){
		Singleton obj1 = Singleton.getInstance();//获取对象
	}
}

获取对象方法:

Singleton a = Singleton.getInstance();

由此达到了单例模式的要求(只new一次)

final

  1. final可以用来修饰:类、方法、字段

    //修饰类
    final public class FinalFather{...}
    //修饰方法
    public final void f1(){...}
    //修饰字段
    final int a;
    
  2. final的类,不能被继承,没有子类。

  3. 父类如果有final的方法,子类中不能重写此方法

  4. final修饰的变量,不能被再次赋值(有点类似于c的const)

  5. final修饰的对象,不能修改其指针(但是可以修改对象内部的值)
    一个类:

    public class FinalObject{
    	int a = 10;
    }
    

    main:

    public class FinalObjectTest{
    	public static void main(){
    		final Finalobject obj1 = new Finalobject();//final修饰对象,意思是final对象的指针固定了,obj1只能指向这一个对象,不可改变
    		//可以改变obj1.a的值
    		obj1.a = 20;//right
    		//不可以将新对象赋给obj1
    		obj1 = new FinalObject();//error
    	}
    }
    

常量设计

Java中没有const关键字
不能修改:final;不会修改/只读/只要一份:static;方便访问:public

  1. 因此:public static final + 变量类型 + 变量名
  2. Java常量的变量命名规则:全大写,以连字符相连
  3. 接口内定义的变量编译器会默认是常量,如果修改其值会报错

常量池

常量池:就是一块特殊的内存,保存在编译期间就已经确定的数据
特点:相同的值只储存一份,节省内存,共享访问(Java将有常量池的常量的每个值(有限)都保存在一个固定的内存地址里)

基本类型的包装类的常量池

  1. Boolean:true, false
  2. Byte: -128~127
  3. Character: 0~127(ASCLL码的基础部分)
  4. Short,Int,Long:-128~127
  5. Float, Double: 没有缓存(常量池),因为小数太多了
    eg.
    //这样创建的对象b1和b2指向了同一块内存
    Boolean b1 = true;
    Boolean b2 = true;
    System.out.println(String.valueOf(b1 == b2))//true  
    //注意,这里的==是判断指针值是否相同(因为b1和b2是对象,可以看成一个指针),即判断是否指向同一个地址,而不是判断该地址的值是否相同
    
    Float f1 = 0.5f;//Float没有常量池,f1和f2指向的内存不同
    Float f2 = 0.5f;
    System.out.println(String.valueOf(f1 == f2))//false  ,没有常量池,不指向同一个地址
    

常量字符串也有常量池缓存机制

这里就有一个基本类型的包装类和字符串的创建问题了:
1. 常量式(字面量)赋值创建,放在栈内存(将被常量化),栈内存读取速度块但容量小

//这样直接赋值就会被常量化
Integer a = 10;
String b = "abc"

2.new对象进行创建,放在堆内存(一个新的地址中,不会常量化),堆内存读取速度慢但容量大

//这样不会常量化
Integer c = new Integer(10);
String d = new String("abc");

因为new会根据构造函数来创建对象;而直接赋值会有一个基本变量自动装箱变成对象的过程,此时产生的对象就会指向变量池中该值的固定内存

eg.基本类型的包装类

public class BoxClassTest{
	public static void main(String[] args){
		int i1 = 10;
		Integer i2 = 10;//自动装箱操作,将基本变量变成常量对象,使i2指向10
		System.out.println(i1 == i2)//true
		//自动拆箱,基本类型和包装类型进行比较,包装类型自动拆箱

		Integer i3 = new Integer();//这里直接new一个对象
		System.out.println(i1 == i3)//true
		//自动拆箱,基本类型和包装类型进行比较,包装类型自动拆箱
		System.out.println(i2 == i3)//false
		//两个对象比较,比较其地址,一个在堆内存,一个在栈内存,地址肯定不同了三

		Integer i4 = i2 + i3//i4是常量对象,因为对象加法也会自动拆箱
	}
}

eg.字符串

public class StringNewTest{
	public static void main(String[] args){
		String s0 = "abcdef";
		String s1 = "abc";
		String s3 = s1 + "def";//涉及到变量,编译器不优化
		String s4 = "abc" + "def"//都是常量,编译器自动优化成abcdef
		System.out.println(s3 == s4)//false
		System.out.println(s0 == s3)//true
	}
}

不可变对象

  1. 不可变对象:一旦创建,不能更改的对象(的状态/值)

  2. 不可变对象有:八个基本类型的包装类,String,BigInteger,BigDecimal等

  3. 不可变对象也是对象,所以函数还是传指针,但由于不可变,形参变量在函数体内修改后指向新内存,外部的实参的指针不改动
    eg.

    public static void change(String b)//这里的b也指向abc
    {
    	b = "def";//这里的b指向abc的指针断掉,重新指向def
    }
    String a = new String("abc");//这里a指针指向abc
    change(a);//a仍然指向abc,没变
    System.out.println(a);//abc
    
  4. 如何创建不可变对象
    ①使用final(使值固定)和private(不可访问),创建的对象是不可变的
    ②不提供setter方法,没有setter方法,外部就不可修改
    ③将类设成final,或所有的方法都是final

Java字符串

  1. 字符串是典型的不可变对象,那么是怎样的不可修改呢:
    eg.
    String a ="abc";//这里的a指向abc
     a = a + "def"//内存里的abc仍然在,只是a的指针断掉重新指向abcdef这一块新的内存地址,abc的这块内存就浪费了
    
    例子说明这里的abc是不可修改的,abcdef在一个新的内存里
  2. String 定义:
    1. String a = "abc";//常量赋值,栈内存
    2. String b = new String("abc");//new对象,堆内存
  3. 字符串内容比较:equals方法
  4. 判断是否指向同一个对象:指针比较==
  5. StringBuffer和StringBuilder是可变对象,我们可以使用他们的很多方法处理字符串
    append(String str)//在末尾添加的字符串
    delete(int start, int end)//删除开始、结束位置
    insert(int offset, String str)//插入位置,插入字符串
    replace(int start, int end, String str)
    reverse()//翻转字符串

String,StringBuffer和StringBuilder的效率区别:

import java.util.Calendar;//导入时间包
public class StringAppendTest {
    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());//输出所需时间 2399ms

       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());//12ms

       Calendar t3 = Calendar.getInstance();
       StringBuilder c = new StringBuilder();
       for(int i=0;i<n;i++)
       {
           b.append(i);
           b.append(",");
       }
        System.out.println(Calendar.getInstance().getTimeInMillis() - t3.getTimeInMillis());//8ms
    }
}

可变对象和不可变对象传递参数的区别:

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.replace(0,3,"def");
    }
    public static void main(String[] args) {
        int a = 5;
        String b = "abc";
        StringBuffer c = new StringBuffer("abc");
        changeValue(a);
        changeValue(b);//String类型的b是不可变对象,虽然传的是指针,但是当形参修改时,并不会修改形参指向的数据,而是会重新创建一个空间储存改变的值,形参的指针重再指向它,原值不改,那么很显然,实参指向这个原来的值也不会改变
        changeValue(c);//StringBuffer类型的c是可变对象,形参和实参指向同一块内存,当形参改变是,可以直接改变形参指向的空间的变量
        
        System.out.println(a);//5
        System.out.println(b);//abc
        System.out.println(c);//def
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值