String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1==str2); //输出结果是false
第一行代码,首先创建一个内容为“hello”的字符串实例对象,
第二行代码,新new出来一个字符串对象,在堆内存中新开辟一个空间,在栈内存中str2指向这个新的地址,所以str1与str2是指向不同地址的两个引用;
String str1 = “hello”;
String str2 = “hello”;
String str3 = “hello”;
System.out.println(str1==str2); //true
System.out.println(str1==str3); //true
System.out.println(str2==str3); //true
这是因为,通过String str1 = “hello”;直接赋值创建的对象,JVM会将该对象保存在对象池中,下次再直接赋值创建对象,如果对象池中有相同的内容,则不再堆内存重新生成对象,直接让它们指向对象池中的同一个对象。
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2); // false
第一行代码字符串的创建并没有使“hello”入池,在String中提供了intern( )方法来让我们手动入池
String str1 = new String("hello") .intern();//让"hello"入池并返回String;
String str2 = "hello" ;
System.out.println(str1 == str2); // true
在Java中,String类提供了equals(String str)方法来进行字符串的比较,它比较的是两字符串的内容,那么显然
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2)); // true
System.out.println("hello".equals(str2)); // true 字符串常量是String的匿名对象
因此建议使用直接赋值。
我们在编程中会遇到这种情况:
String str = "hello";
str = str+" world";
System.out.println(str);
结果输出:hello world
不是说字符串常量不可改变吗?为什么还会打印出helloworld? 看一下String的内存图
一开始呢,str的确是“hello”,不过在执行 str+" world"; 的时候,在堆内存中又生成了两块空间,一个是“ world”,还有一个两字符串链接后的空间“hello world”,最后str的指向发生了变化,也就是说str一开始所指向的堆内存“hello”并没有改变,而是它所指向的地址发生了变化。
public char charAt(int index) 获取索引位置的字符
public char[] toCharArray() 将字符串变为字符数组返回
public byte[] getBytes() 将字符串以字节数组返回
public int compareTo(String anotherString) 比较两字符串的大小,返回差值
1. 相等:返回0.
2. 小于:返回内容小于0.
3. 大于:返回内容大于0。
public boolean contains(CharSequence) ; //判断一个字符串是否在该字符串内
public int indexOf(Stirng str) ; //从头查找str是否在,存在返回第一个找到的下标,找不到返回-1
public int indexOf(Stirng str ,int fromIndex); //从指定位置开始查找
public int lastIndexOf(Stirng str); //从后向前查找
public int lastIndexOf(Stirng str ,int fromIndex); //从指定位置从后向前查找
public String replaceAll(String regex, String replacement); //替换所有指定内容
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_")); //将所有"l"替换为"_"
public String[ ] split(String regex); //将字符串按照给定字符串regex分割为字符串数组返回
public String[ ] split(String regex, int limit); //数组的长度的极限是limit
public String subString(int index); //从指定位置开始截取到尾部
public String subString(int begin, int end); //截取其中一段
在数组中获取长度是 .length length是数组的属性
在String中获取长度是 .length() 是Sting类的方法
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer类。在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法;
StringBuffer sb = new StringBuffer();
sb.append("Hello").append("World");
String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串的情况考虑使用StingBuffer。
StringBuffer类的常见方法
public synchronized StringBuffer reverse(); //字符串反转
public synchronized StringBuffer delete(int start, int end); //删除指定范围的数据
public synchronized StringBuffer insert(int offset, 各种数据类型 b); //插入数据
面试题:请解释String、StringBuffer、StringBuilder的区别:
1. String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
2. StringBuffer采用同步处理,属于线程安全操作;而StringBuilder采用异步处理,属于线程不安全操作。
Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。
即,所有类的对象都可以使用Object进行接收。
在输出对象时,默认输出的是一个地址编码默认Object类提供的toString()方法只能够得到一个对象的地址(而这是所有对象都共同具备
的特征)。如若觉得默认给出的toString()方法功能不足,就在需要的子类上覆写toString()方法。
class Person{
private String name ;
private int age ;
public Person(String name, int age) {
this.age = age ;
this.name = name ;
}
@Override
public String toString() {
return "姓名:"+this.name+",年龄:"+this.age ;
}
}
public class Test {
public static void main(String[] args) {
fun(new Person("yuisama",25) );
fun("Hello");
}
public static void fun(Object obj) {
System.out.println(obj.toString()); // 默认输出对象调用的就是toString()方法
}
}
对象比较
String类对象的比较使用的是equals()方法,实际上String类的equals()方法就是覆写的Object类中的equals()方法。
而我们自己定义的Person类如果没有覆写equals(Object obj),那么它只是判断传入的对象是否是该对象本身,若我们想通过该类的一些属性来比较判断它们是否相同,那我们就得自己覆写该方法;
接收引用数据类型
在之前已经分析了Object可以接收任意的对象,因为Object是所有类的父类,但是Obejct并不局限于此,它可以
接收所有数据类型,包括:类、数组、接口。
Object类可以接收所有引用数据类型。然而在Java中,数据类型分为基本数据类型和引用数据类型,那么基本数据类型如何处理呢?
包装类就是将基本数据类型封装到类中。
Java为了方便开发,专门提供了包装类的使用,而对于包装类的使用,提供了两种类型。
对象型(Object的直接子类):Boolean、Character(char);
数值型(Number的直接子类):Byte、Double、Short、Long、Integer(int)、Float;
装箱与拆箱
在包装类与基本数据类型处理之中存在有两个概念:
装箱:将基本数据类型变为包装类对象,利用每一个包装类提供的构造方法实现装箱处理。
拆箱:将包装类中包装的基本数据类型取出。利用Number类中提供的六种方法。
Integer num = new Integer(55) ; // 装箱
int data = num.intValue() ; // 拆箱
System.out.println(data);
在JDK1.5之后,提供了自动拆装箱的机制,最为重要的是,由于此类机制的
存在,可以直接利用包装类的对象进行各种数学计算。
范例:自动装箱与拆箱处理
// 自动装箱
Integer x = 55 ;
// 可以直接利用包装类对象操作
System.out.println(++x * 5 );
说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用
已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产
生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
Integer num1 = 10;
Integer num2 = 10;
System.out.println(num1==num2); //true
Integer num1 = 128;
Integer num2 = 128;
System.out.println(num1==num2); //false
数值在-128~127之间的数,对象会在IntegerCache.cache 产生,会复用已有对象,所以第一个代码返回结果为true
而数值不在这个范围内,就会在堆上产生新的对象,所以结果返回false
阿里编码规范:使用int还是Integer?
关于基本数据类型与包装数据类型的使用标准如下:
1) 【强制】所有的 POJO 类属性必须使用包装数据类型。
2) 【强制】RPC 方法的返回值和参数必须使用包装数据类型。
3) 【推荐】所有的局部变量使用基本数据类型。
字符串与基本数据类型转换
1. String变为int 类型(Integer类):public static int parseInt(String s) throws NumberFormatException
2. String变为double类型(Double类):public static double parseDouble(String s) throws NumberFormatException
3. String变为Boolean类型(Boolean类):public static boolean parseBoolean(String s)
那么如果现在要将基本数据类型变为字符串
1. 任何数据类型使用了"+"连接空白字符串就变为了字符串类型。
2. 使用String类中提供的valueOf()方法,此方法不产生垃圾。
String str = String.valueOf(100) ;