2021-01-20

day_15_常用API(String,Integer,常量池)

/*

  • java.lang.String : 字符串类,并且该类加 final修饰
  •  底层就是char数组  private final char value[];
    
  •  所以 字符串很多特性 就是数组的特性
    
  •  1 字符串一旦创建不可更改
    
  •  2 为了提升字符串的访问效率,Java中提出了字符串常量池,相当于是一个缓存区
    
  •  	引用类型对象应该保存在堆内存,但是字符串不同,保存在静态区的字符串常量池中
    
  •  3 在程序的执行过程中,如果程序要用到某个字符串,如"abc",虚拟机会先去常量池中搜索,有没有这个字符串
    
  •  	如果已经有了,就直接指向该字符串即可,如果没有就新建一个字符串对象,并指向
    
public class String_01_ {
	public static void main(String[]args){
		
				String s1 = "abc";
				// 这里并没有改变字符串abc的值,而是新建了一个字符串叫a2 并让s1指向a2
				s1 = "a2";
				System.out.println(s1);
				
			
				String s2 = "abc";
				String s3 = "abc";
				String s4 = "Abc";
				// true , == 比较基本类型比较值,比较引用类型比较内存地址
				// 而 s2 和 s3 指向的地址 是相同的
				System.out.println(s2 == s3);
				// 创建两个对象,abc和Abc
				// true  比较的是值
				System.out.println(s2.equals(s3));
				
				// 第三部分
				// new的方式,s5不再指向常量池,而是指向堆内存对象,堆内存中保存常量池的地址
				String s5 = new String("123");
				String s6 = new String("123");
				// 以上两句 : 创建三个对象(堆内存两个,常量池一个),占用5块空间(栈内存两个,堆内存两个,常量池一个)
				// == 就是在比较 堆内存地址,而不是常量池中 123的地址了,因为new了两次,所以不一致
				System.out.println(s5 == s6);
				System.out.println(s5.equals(s6));
	}
}

因为String一旦创建不可更改,所以使用的时候,要注意,不要频繁拼接字符串
`因为效率比较低,还浪费空间,并且垃圾回收也会有一定问题

public class String_02_ {

	public static void main(String[] args) {
		String[] strs = {"a","b","c","d"};
		String tmp = ""; 
		
		for (String string : strs) {
			tmp+=string;
		}
		System.out.println(tmp);
		// a,b,c,d,"",ab,abc,abcd
		// TODO Auto-generated method stub

	}
}
  • String中常用构造方法
  • 创建String对象的方式
public class String_03_ {

	public static void main(String[] args) {
		// 1
				String s1 = "abc";

				// 2
				String s2 = new String("xxx");

				// 3 字节数组
				// byte[] aaa = {1,2,3};
				// byte[] aaa = new byte[]{1,2,3,4};
				// byte[] aaa = new byte[5];
				byte[] aaa = { 97, 98, 99 };
				String s3 = new String(aaa);
				String s4 = new String(new byte[] { 97, 98, 99 });
				// abc : 因为把数字转换为char  97 就是a 
				System.out.println(s4);

				// 4 字节数组 , 截取一部分
				// 从下标 1 开始(包含),取两个
				String s5 = new String(aaa, 1, 2);
				System.out.println(s5);
				
				// 5 字符数组
				char[] chars = {'a','b','c','d'};
				String s6 = new String(chars);
				System.out.println(s6);
				// 6 截取一部分
				String s7 = new String(chars,2,2);
				System.out.println(s7);
				
				// 7 无参 空字符串
				String s8 = new String();
				System.out.println(s8);
			}
		// TODO Auto-generated method stub

	}

public class String_04_ {
	public static void main(String[] args) {
		// 1 int length() : 返回该字符串长度
		String s1 = "qwert!";
		System.out.println(s1.length()); // 6
		
		// 2 char charAt(int index) : 获取字符串某个位置上的字符
		char c1 = s1.charAt(2);
		System.out.println(c1); // e
		
		// 3 boolean endsWith(String suffix) :  判断字符串是否以指定字符串结尾
		// boolean startsWith(String prefix) : 判断字符串是否以指定自己开始
		System.out.println("HelloWord.java".endsWith(".java"));// true
		System.out.println("HelloWord.java".endsWith(".java "));// false 有空格
		
		// 4 boolean equalsIgnoreCase(String anotherString) : 不区分大小写比较两个字符串是否相等
		System.out.println("abc".equals("AbC")); // false
		System.out.println("abc".equalsIgnoreCase("AbC")); // true
		
		// 5 byte[] getBytes() : 把字符串转换为字节数组
		byte[] byteArr = "abc".getBytes();
		for (byte b : byteArr) {
			System.out.println(b);
		}
		System.out.println("----------");
		
		// 6 int indexOf(String str) : 获取指定字符串的起始索引值,找不到返回-1,如果有多个 ,找到第一个就不找了
		System.out.println("abcdce".indexOf("cd"));
		
		// 7 int indexOf(String str,int fromIndex) : 从指定位置开始找(包含),找不到返回-1
		System.out.println("abcdeabc".indexOf("a",1));
		
		// 8 int lastIndexOf(String str) : 获取最后一次出现的位置,找不到返回-1(倒着遍历,第一次出现,就是最后一次)
		//  int lastIndexOf(String str,int fromIndex) : 获取最后一次出现的位置,找不到返回-1,从指定位置反向搜索,第一次出现的位置
		System.out.println("abcdeabc".lastIndexOf("a"));
		
		// 9 String replaceAll(String regex, String replacement) : 把一个字符串替换为指定字符串
		// 一个类似的  replace : 这两个功能是一样的,只不过 replace 不支持正则表达式
		System.out.println("123321".replaceAll("1", "a")); // a2332a
		System.out.println("1.2.3".replaceAll(".", "-")); // ----- , 因为 会把 . 解析为正则表达式,而 . 代表 任何字符
		// 1-2-3 , 正则表达式中 可以通过 \ 把 .  转义为无意义字符,但是在java中 \ 是转移符,所以 要写 \\ 对\进行转义才可以
		System.out.println("1.2.3".replaceAll("\\.", "-")); 
		System.out.println("1.2.3".replace(".", "-")); // 1-2-3  , 因为不支持正则表达式,所以 . 就是 .
		
		
		// 10 String[] split(String regex) : 分割字符串,通过指定分隔符,来分割字符串,返回分割后的新字符串数组,支持正则表达式
		String myTime = "2021-1-20";
		String[] myTimes = myTime.split("-");
		for (String string : myTimes) {
			System.out.println(string);
		}
		System.out.println("==========");
		
		// 11 String substring(int begin) : 获取该字符从某个下标开始到结尾的子字符串(包含)
		System.out.println("abcde".substring(3));
		
		// 12 String substring(int beginIndex,int endIndex) : 获取该字符从某个下标开始(包含) 到某个下标结束的子字符串(不包含)
		System.out.println("qwerttyuyikjn".substring(3, 6));
		
		// 13 char[] toCharArray() : 转换为字符数组
		char[] c2 = "abc".toCharArray();
		for (char c : c2) {
			System.out.println(c);
		}
		System.out.println("+++++++++++++++");
		
		// 14 String toUpperCase() : 转为大写
		System.out.println("asdDGDHshdjbsaj".toUpperCase());
		// 15 String toLowerCase() : 转为小写
		System.out.println("asdDGDHshdjbsaj".toLowerCase());
		
		// 16 String trim() : 删除字符串两边的空格
		System.out.println("              ab              cd                      ");
		System.out.println("              ab              cd                      ".trim());
		
		// 17 static String valueOf(Object obj) : 调用指定对象的toString方法,并且 避免了空指针异常
		// (obj == null) ? "null" : obj.toString();
		String_04_ ss = null;
		System.out.println(ss);
		
	}

}

1 StringBuffer和StringBuilder是是一个可变的字符串缓冲区
*

  • 2 原理
  •  	预先在内存中申请一块空间,可以容纳字符序列(字符数组)
    
  •  	如果 预留空间不够,会进行自动扩容
    
  •  	底层都是char[] ,并且默认初始化容量是16个字符
    
  • 3 String,StringBuffer,StringBuilder最大的区别
  •  	1 String不可变字符序列,而StringBuilder和StringBuffer是可变字符序列
    
  •  	2 StringBuffer是线程安全,在多线程环境下,不会出现问题,所以效率低,一般常用于类中
    
  •  	3 StringBuilder是非线程安全,在多线程环境下可能出现问题,效率高,一般用于方法中
    
  • 4 如何选择StringBuilder和StringBuffer
  •  	多线程环境下,是否有可能出现多个线程同时操作同一个数据 的可能(增,删,改)
    
public class String_05_ {
	public static void main(String[] args) {
		StringBuffer sb = new StringBuffer();
		String[] strs = {"a","b","c","d"};
		for (String string : strs) {
			sb.append(string+".").append(".");
		}
		// 引用类型转String  调用toString方法
		String str = sb.toString();
		System.out.println(str);
		
		StringBuilder sbr = new StringBuilder();
		for (String string : strs) {
			sbr.append(string);
		}
		System.out.println(sbr.toString());
		System.out.println(sbr.reverse());
	}

}

tring 不可以任意拼接的字符串

  •  	String s2 = "a" + "b"; 这种写法,在编译阶段,就会把+ 去掉
    
  •  	"a" +"b"  a和b都是字面量,需要在编译阶段说明临时空间,所以需要通过值确定类型
    
  •  	编译时看到是两个字符串相加,就直接把+省略,保存ab
    
  •  	所以 s1 ==s2  是true
    
  •  String s3 = a + b;
    
  •  	a和b是变量,编译阶段是不确定变量的值的
    
  •  	在运行的时候,由于是两个字符串变量相加,
    
  •  	所以会自动创建一个StringBuffer对象,然后把两个变量拼接到一起,最终转换为String类型
    
  •  	而是以    return new String(value, 0, count);   所以 s3是指向堆内存的
    
public class String_06_ {
	public static void main(String[] args) {
		String s1 = "ab";
		String a = "a";
		String b = "b";
		String s2 = "a" + "b";
		String s3 = a + b;
		String s4 = new String("ab");
		// true
		System.out.println(s1 == s2);
		// false
		System.out.println(s1 == s3);
		System.out.println(s1.equals(s3));
		// false
		System.out.println(s1 == s4);
	}

}

包装类 : 封装了基本类型的操作,

  •  byte -- java.lang.Byte
    
  •  short -- java.lang.Short
    
  •  int  -- java.lang.Integer
    
  •  long -- java.lang.Long
    
  •  float -- java.lang.Float
    
  •  double  -- java.lang.Double
    
  •  char  -- java.lang.Character
    
  •  boolean -- java.lang.Boolean
    
public class Intrger_01_ {
	public static void main(String[] args) {
		// 基本类型
		byte b1 = 2;
		// 引用类型
		Byte b2 = null;
		// 把 b1 基本类型封装到b2引用类型中
		b2 = new Byte(b1);
		
		// 可以把b2 传入 接收Object的方法中,因为发生了多态
		m1(b2);
	}
	public static void m1(Object obj){
		// 由于 覆写了toString方法,所以可以直接打印 2 ,而不是内存地址
		System.out.println(obj);
	}

}

public class Integer_02_ {
	public static void main(String[] args) {
		// 1 获取最大值和最小值
		System.out.println("int最大值 : " + Integer.MAX_VALUE);
		System.out.println("int最小值 : " + Integer.MIN_VALUE);
		System.out.println("long最大值 : " + Long.MAX_VALUE);
		System.out.println("long最小值 : " + Long.MIN_VALUE);
		System.out.println(Short.MAX_VALUE);
		System.out.println(Short.MIN_VALUE);
		System.out.println((int) (Character.MAX_VALUE));
		System.out.println((int) (Character.MIN_VALUE));
		
		// 2 创建对象
		Integer i1 = new Integer(12); // int -- Integer
		// 可以传入纯数字的字符串
		Integer i2 = new Integer("19776"); // String -- Integer
		
		System.out.println(i1);
		System.out.println(i2);
		// 编译可以通过,但是运行出错
		// java.lang.NumberFormatException: For input string: "19776a"
		Integer ie = new Integer("19776a");
	}

}

public class Integer_03_ {
	public static void main(String[] args) {
		// 1 int --> Integer
		Integer i1 = new Integer(22);

		// 2 Integer --> int
		int i2 = i1.intValue();

		// 3 重要 : static int parseInt(String s) : 把字符串转换为int
		// String --> int
		int i3 = Integer.parseInt("123");
		System.out.println(i3);

		// 4 重要
		double d1 = Double.parseDouble("12.3");
		System.out.println(d1);

		// 5 static String toBinaryString(int value) : 把指定int值转换为二进制的字符串形式展示
		String s1 = Integer.toBinaryString(10);
		System.out.println(s1);

		// 6 十六进制展示
		System.out.println(Integer.toHexString(30));
		// 7 八进制展示
		System.out.println(Integer.toOctalString(10));
		
		// 8 int --> Integer 
		Integer i31 = Integer.valueOf(28);
		// String --> Integer
		Integer i32 = Integer.valueOf("123");
		
		// 9 Integer -- String
		String s2 = i31.toString();
		System.out.println(i31);
		System.out.println(s2);
	}

}

//类型转换
public class Integer_04_ {
	public static void main(String[] args) {
		// 1 int -- > Integer
		Integer i1 = new Integer(222);
		Integer i2 = Integer.valueOf(222);
		
		// 2 Integer --> int
		int i3 = i2.intValue();

		// 3 String --> Integer
		Integer i4 =  Integer.valueOf("123");
		Integer i5 = new Integer("12313");

		// 4 Integer --> String
		String s1 = i5.toString();

		// 5 String --> int
		int i6 = Integer.parseInt("12321");

		// 6 int --> String
		String s2 = 333+"";
	}

}

/*

  • 自动装箱
  • 把 基本数据类型 自动转换为 对应的包装类
  • 自动拆箱
  • 把 包装类 自动转换为 基本数据类型
  • 自动装箱和自动拆箱是编译时 完成的
public class Integer_05_ {
public static void main(String[] args) {
		
		//1.5版本之前
		// 自动装箱之前的转换方式
		Integer i1 = new Integer(223); // Integer.vlaueOf(2222)
		// 自动拆箱之前的转换方式
		int i3 = i1.intValue();
		
		
		// 1.5 开始
		// 自动装箱之后的转换方式
		Integer i2 = 222;  // 编译完后 就等于是 : Integer i2  = Integer.vlaueOf(222);
		// 自动拆箱之后的转换方式
		int i4 = i1; // 拆箱
		
		// 2 是基本类型,会先自动装箱转换为Integer类型,然后再向上转型(多态) 转换为Object
		m1(2);
	}
	public static void m1(Object obj){
		// 由于 覆写了toString方法,所以可以直接打印 2 ,而不是内存地址
		System.out.println(obj);
	}

}

深入理解自动装箱和自动拆箱
*

  •  1 都是编译时的概念,和运行时无关
    
  •  2 装箱的时候,会在编译时自动把赋值操作变成 Integer.valueOf(222)
    
  • String , Integer,Double 等 八种包装类 和String 都覆写了toString(),equals() , hashCode() 方法

  • Integer.valueOf(xxx) : 方法实现
    public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
    }

  •  valueOf : 把基本类型转换为Integer类型
    
  •  但是里面初始化了一个整型常量池,值的范围是在 -128~127之间
    
  •  其实就是一个Integer[] 数组 有 256个对象,对象中的int值 分别为 -128,-127.....126,127  下标 是 0~ 255
    
  •  		在  private static class IntegerCache 类中 是 Integer中的一个静态内部类
    
  •  					三个变量 
    
  •  							       static final int low = -128;
     									static final int high;
     									static final Integer cache[];
     					并且在 static 代码块中 对这个数组进行了初始化操作
    
  •  如果值在 -128~127之间 就直接去这个缓存数组中找对应的对象即可,不用再重新创建Integer对象
    
  •  	   return IntegerCache.cache[i + (-IntegerCache.low)];  
    
  •  			// IntegerCache.low 是 -128   
    
  •  			// (-IntegerCache.low) : 就是 128  负负得正
    
  •  			// 加上 我们要添加的数据,就能得到 对应的值所在缓存数组中的下标索引
    
  •  			// 把该对象返回
    
  •  那么这样的话,如果是通过自动装箱或者是通过valueOf方法赋值的两个值都符合该范围,那么 这两个变量保存的内存地址是一致的,则使用 == 也是true
    
  •  	如  Integer i1 = 123;  Integer i2 = 123;  或者 Integer i3 = Integer.valueOf(123);  他们的内存地址是相等的,找到的是同一个对象
    
  •  反之 , 就等于new Integer(xxx)
    
  •  	 	 return new Integer(i);  既然是new  那么 堆内存会重新创建新的对象,那么尽管初始化的int值一样,但是内存地址也不同
    
  •  			所以 使用 == 也是false,此时 应该使用equals 来比较是否相等
    
  •  		如 Integer i4 = Integer.valueOf(128);  Integer i5 = Integer.valueOf(128);    或者是 Integer i6 = new Integer(1) 
    
public class Integer_06_ {
public static void main(String[] args) {
		
		// 自动装箱 , 就等于 Integer i1 = Integer.valueOf(123);
		Integer i1 = 123;
		Integer i2 = 123;
		System.out.println(i1 == i2);
		// 等于 Integer i3 = Integer.valueOf(128); 和 new Integer(128)  没区别,
		Integer i3 = 128;
		Integer i4 = 128;
		System.out.println(i3 == i4);
		
		// 以下  结果 和 上面结果 相同
		Integer i5 = Integer.valueOf(123);
		Integer i6 = Integer.valueOf(123);
		System.out.println(i5 == i6);
		
		Integer i7 = Integer.valueOf(128);
		Integer i8 = Integer.valueOf(128); 
		System.out.println(i7 == i8);
		
		// new 的方式是不行的,因为new了两次,对象内存地址不同,所以 == 比较内存地址,是false,但是 使用equals 是true,因为都是1
		Integer i9 = new Integer(1);
		Integer i10 = new Integer(1);
		System.out.println(i9 == i10);
		System.out.println(i9.equals(i10));
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值