一、String
String:是一个字符的容器,既然是一个容器 ,他一定符合容器的基本操作:求长,定位,替换
String的两种创建对象的方式
String str = "zhangaoqi";
String str1 = new String("zhangaoqi");
内存实现:
这两个创建的str不一样,不是同一个对象
public class Test1{
public static void main(String[] args){
String str = "zhangaoqi";
String str1 = new String("zhangaoqi");
String str2 = "zhangaoqi";
String str3 = new String("zhangaoqi");
System.out.println(str == str1);//输出false
System.out.println(str == str2);//输出true
System.out.println(st1 == str3);//输出false
System.out.println(str.equals(str1);//输出true
}
}
-
str == str1,输出false
这是因为 == 判断的是地址,str直接指向常量池得地址,而str1先指向堆的对象再指向常量池,地址不一样,所以输出false。
-
str == str2,输出true
这是因为常量池已经出现的数据不会出现第二次
-
st1 == str3,输出false
这是因为有new,又先创建了一个对象,新开辟了一个空间,所以地址不一样了
-
如果只需要对比字符串的内容而不是地址,则使用equals()方法
-
从以上例子中也可以看出 ==与 equals的区别
注意:
public class Test2{
public static void main(String[] args){
int a = 3;//3在常量池中
int b = 3;//3在常量池中,与a指向的一样
System.out.println(a == b);//输出true 常量池中的内容可用 == 比较
}
}
因为String有两种赋值方式,这时引入四类八种,它们有没有类,int也有两种复制方式吗?
所有基础数据类型的对象类型都有两种赋值方式:直接写和创建对象赋值
String的一些方法
//String的一些方法
String str = "zhangaoqi";
System.out.println(str.concat("aaa"));//字符串拼接
System.out.println(str.contains("zhang"));//true 判断是否包含zhang字符串
System.out.println(str.startsWith("zh"));//true 判断是否以zh开始
注意String的replace()方法和replaceAll()方法的区别
工作中常用的一个操作
如果一个前端传过来文件的编码是GBK的,你看到的是乱码的,则需要先把他转换为字节的数据,然后重新创建String对象,按GBK方式编码。(电脑只认识二进制,将字符串转为字节,再用另一个编码方式编回来)
public class Test3{
public static void main(String[] args){
String str = "张澳琪";
byte[] arrays = str.getBytes();
try {
String str2 = new String(arrays,"GBK");
System.out.println(str2); //输出:娑ㄥ晩浜插摝
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
二、StringBuffer
StringBuffer:用来对字符串进行操作
字符串一旦定义则不可改变,这时直接操作字符串会遇到一个效率损耗问题
例如:有两个字符串a,b需要拼接,拼接完后会有三个对象(不考虑栈),原来a存在在常量池,b存在在常量池,新拼接出来的字符串还需要放在常量池。如果有5个字符串拼接则需要9个对象,执行效率低。
对String常用类的两个操作工具StringBuffer和StringBuilder,这两个工具的方法没太大区别,只是一个是线程安全的一个是线程不安全的
public class Test4{
public static void main(String[] args){
StringBuffer sb = new StringBuffer("zhang");
System.out.println(sb);//输出 zhang
sb.append("ao");
System.out.println(sb); //输出 zhangao
sb.delete(1,3);//从角标1开始删,删(3-1)个,结果为 zngao 这是因为StringBuffer的内容而可以改变
sb.reverse();
System.out.println(sb); //输出 oagnz
sb.insert(1,"ha"); //从角标1开始插,插ha
sb.toString();//将StringBuffer型转为字符串型
}
}
StringBuffer创建的对象内容可以改变,而String一旦定义内容不可变!
public class Test5{
public static void main(String[] args){
String str = "zhangaoqi";
str.replace('z','c');
System.out.println(str);//输出还是zhangaoqi,这是因为str的内容不能变
//replace()方法是返回了一个新的字符串
String a = str.replace('z','c');
System.out.println(a);//输出 changaoqi
StringBuffer sb = new StringBuffer("zhang");
sb.reverse();
System.out.println(sb); //输出 gnahz ,内容可以改变
}
}
练习一下
判断字符串是否是回文字符串(用StringBuffer实现)
import java.util.Scanner;
public class BackString {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String temp = sc.next();
StringBuffer str = new StringBuffer();
str.append(temp);
String result = str.reverse().toString();
System.out.println(result.equals(temp));
}
}
三、基础数据类型的对象类型
Integer
- int是Integer 的缩写
- Integer是int的对象类型
public class Test6{
public static void main(String[] args){
Integer a1 = 3;
Integer a = new Integer(3);
Integer b = 3;
int c = 3; //基础数据类型
System.out.println(a1);//输出3
System.out.println(a == a1);//输出false
System.out.println(a == b);//输出false 一个在堆中,一个在常量池中
//只要是基础数据类型就只比较内容
System.out.println(b == c);//输出true
System.out.println(c == a);//输出true//这里因为c是基础数据类型,没有equals比较方法
}
}
Integer的一个诡异的地方
public class Test7{
public static void main(String[] args){
Integer a = 14;
Integer b = 14;
System.out.println(a == b); //输出true
Integer c = 144;
Integer d = 144;
System.out.println(c == d); //输出false
}
}
这是因为Java的JVM一开始在静态常量池里面创建了256个值(-128,127),这些值一开始就存在在常量池里,这时等于127以内的值指向同一个值,但是如果大于127后,它指向了不同的地址,这就相当于new一个对象的过程,这就是Integer不同的地方,所以int类型的数据比较大小时应该用基础数据类型比较。
总结
- int和int之间,用== 比较,肯定为true。基本数据类型没有equals方法
- int和Integer比较,Integer会自动拆箱,== 和 equals都肯定为true
- int和new Integer比较,Integer会自动拆箱,调用intValue方法, 所以 == 和 equals都肯定为true
- Integer和Integer比较的时候,由于直接赋值的话会进行自动的装箱。所以当值在[-128,127]中的时候,由于值缓存在IntegerCache中,那么当赋值在这个区间的时候,不会创建新的Integer对象,而是直接从缓存中获取已经创建好的Integer对象。而当大于这个区间的时候,会直接new Integer。
- 当Integer和Integer进行== 比较的时候,在[-128,127]区间的时候,为true。不在这个区间,则为false
- 当Integer和Integer进行equals比较的时候,由于Integer的equals方法进行了重写,比较的是内容,所以为true
- Integer和new Integer : new Integer会创建对象,存储在堆中。而Integer在[-128,127]中,从缓存中取,否则会new Integer.
所以 Integer和new Integer 进行==比较的话,肯定为false ; Integer和new Integer 进行equals比较的话,肯定为true- new Integer和new Integer进行== 比较的时候,肯定为false ; 进行equals比较的时候,肯定为true
原因是new的时候,会在堆中创建对象,分配的地址不同,==比较的是内存地址,所以肯定不同- 装箱过程是通过调用包装器的valueOf方法实现的
- 拆箱过程是通过调用包装器的xxxValue方法实现的(xxx表示对应的基本数据类型)
- 总结:下面的Byte、Short、Integer、Long这几个类的valueOf方法实现类似的。所以在[-128,127]区间内,==比较的时候,值总是相等的(指向的是同一对象),在这个区间外是不等的。
而Float和Double则不相等, Boolean的值总是相等的
Byte
public class Test8{
public static void main(String[] args){
Byte a = 3;
Btye b = new Byte((byte)3);//这里需要强转是因为如果直接写3默认是int型
System.out.println(a); //输出3
System.out.println(b); //输出3
System.out.println(a == b); //输出false 一个申请空间了一个没有
System.out.println(a.equals(b)); //输出true
}
}
Short、Long
public class Test9{
public static void main(String[] args){
Short a = 3;
Short b = new Short((short)3);//这里需要强转是因为如果直接写3默认是int型
System.out.println(a); //输出3
System.out.println(b); //输出3
System.out.println(a == b); //输出false 一个申请空间了一个没有
System.out.println(a.equals(b)); //输出true
Long a1 = 3L;
Long b2 = new Long(3);
System.out.println(a.equals(b)); //输出true
}
}
Float、Double
public class Test10{
public static void main(String[] args){
Float f = 3.4f;
Float a = 3.4f
System.out.println(f == a); //输出false 这是因为浮点型根本不能确定精度
//f可能是3.400000000000001f a可能是3.400000000000002f
System.out.println(f.equals(a);//输出true 这是因为此时只是根据字面量来比较的
Double d1 = new Double(3.4);
Double d2 = 3.4;
System.out.println(d1 == d2); //输出false
}
}
Character
public class Test11{
public static void main(String[] args){
Character c = 'c';
Character a = new Character('c');
System.out.println(a == c); //false
Character b = 'c';
System.out.println(a == c); //true char不是浮点型的
}
}
Boolean
public class Test12{
public static void main(String[] args){
Boolean b = false;
Boolean a = new Boolean(false);
Boolean c = false;
System.out.println(a == b); //false
System.out.println(b == c); //true Boolean不是浮点型的
}
}
基础数据类型的对象类型到底用来干什么?
常用的一般不用它来做业务,用它来作为辅助该种类型变量的工具来使用
eg:有一个字符串,想把字符串型变为其他型
int a = Integet.parseInt("55");//可以直接调用parseInt()方法是因为他是静态方法
System.out.println(a); //输出55
int a = Integet.parseInt("a5"); //不行
byte b = Byte.parseByte("55");
double b = Double.parseDouble("55");
boolean b = Boolean.parseBoolean("55");
byte b = Integet.parseByte("55");
注意:Character没有parseCharacter()方法,因为本来就有charAt(0)方法可以把字符串转为字符,所以没必要再有parseCharacter()方法。
其他方法工具
public class Test13{
public static void main(String[] args){
System.out.println(Integer.compare(13,14)); //输出-1,如果大于零则前面的大于后面的
System.out.println(Integer.bitCount(4)); //输出1,看数占了几位,所有的0都不数
System.out.println(Integer.decode("0x05"));//将字符串中的16进制转为10进制int型
System.out.println(Integer.reverse(50)); //输出:1275068416 将int型的二进制数反转过来
System.out.println(Integer.MIN_VALUE);//最小值
}
}
//Double、Float...等的方法都类似