JavaSE----之三个特殊的类
- String 类
- Object类
- 包装类
1. java . lang.String 类
1.1 String 类的两种实例化方式
-
直接赋值(在堆上分配空间)
String str = “hello”; //str 是一个对象,指向堆内存“hello”
String 本身是一个类,因此存在构造方法,如下:
public String(String str);
-
传统方法(构造方法实例化)
String str = new String(“hello”);
Sytem.out.println(str);
1.2 字符串相等比较
首先上一段代码:观察字符串 “ == ” 比较
String str = "hello";
String str = new String("hello");
System.out.println(str1==str2); // false
我们发现字符串内容相同,而使用 “ == ”得到的结果不同,来看如下内存图
“ == ” 本身是数值进行比较的,如果现在用于对象比较,那么所比较的就应该时两个对象所保存的内存地址,而并没有比较对象的内容。
如果要比较内容,就必须使用String 类提供的equals 方法。
String str1 = "hello";
String str = new String("hello");
System.out.println(str1.equals(str));
面试题:请解释String 类”==“ 与”equals“ 的区别
1.”==“ :进行的数值比较,比较的是两个字符串对象的内存地址数值
2.”equals()“ :可以进行字符串内容比较
1.3 字符串常量是String的匿名对象
小tips:在以后开发中,如果要判断用户输入的字符串是否等同于特定字符串,一定要将特定字符串(String 常量) 写在前面,避免如下用户没有输入,出现NullPointException,而任何的字符串常量都是String的匿名对象,所以该对象永远不会为null。
public class Test{
public static void main(String[] args){
String str2 = null; //假设由用户输入
System.out.println(str2.equals("hello")); // 编译出错 null
System.out.println("hello".equals(str2)); //false
}
}
在以后进行比较的时候,强烈建议如上写法,把字符串写在前面。
1.4 String 类两种实例化的区别
在开始我们给出了String 类的两种实例化操作,两者有什么区别呢?
(1)采用直接赋值:
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); // true
并没有开辟新的堆内存空间。
string 类的设计使用了共享设计模式
JVM底层会自动维护一个字符串的对象池,如果现在采用直接赋值的形式进行String的对象实例化。该对象会自动保存在这个对象池之中,如果下次继续使用直接赋值的模式声明String 对象,此时对象池中若有指定内容,则直接引用,如果没有,则开辟新的堆空间后将其保存在对象池中供下次使用。
对象池就是一个对象数组(目的是减少内存开销)
(2)采用构造方法
类对象使用构造方法实例化是标准做法,
String str = new String("hello");
经过图解我们发现,如果使用String 构造方法实例化就会开辟两块堆内存空间,并且其中一块堆内存将会成为垃圾空间,也会堆字符串共享产生问题。
范例:
// 该字符串常量并没有保存在对象池中
String str1 = new String("hello");
String str2 = hello;
System.out.println(str1 == str2); //false
在String 类中提供有方法入池操作
手工入池(本地方法):
public native String intern();
观察入池操作
String str1 = new String("hello").intern();
String str2 = "hello";
System.out.println(str1 == str2); // true
面试题:请解释String 类中两种对象实例化的区别
1.直接赋值: 只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
2.构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用inter()方法手工入池。
因此,我们一般都会采用第一种方式直接赋值。
1.5 字符串常量不可变更
字符串一旦定义后不可改变。
原则:
- 字符串使用就采用直接赋值
- 字符串比较就使用equals()实现。
- 字符串别改变太多
1.6 字符与字符串的相互转换
-
将字符数组 -> String
public String (char[] value)
public String (char[] value,int offset,int count) -
将字符串转为单个字符
char c = “hello”.charAt(1);
System.out.println©; // echar c = “hello”.charAt(1);
System.out.println(c+32);//133 默认转为int计算 -
将字符串变为字符数组
String -> char[]
public char[] toCharArray();
取得字符串长度:
public int length( );
1.7 字节(byte)与字符串
-
将字节数组转为字符串(* * * * * * )
byte[] -> String
public String (byte[] value)
public String (byte[] value,int offset,int count)
byte[] data = new byte[]{1,3,5,7};
String str = new String(data);
System.out.println(str);
-
将字符串转为字节数组(* * * * * *)
String -> byte[]
public byte[] getBytes();
String str = "hello";
byte[] data = str.getBytes();
for(byte b :data){
System.out.println(b); // 104 101 108 111
}
-
将字符串按照指定编码转为字节数组
public byte[] getBytes(String charsetName) :
1.8 字符串比较
- 不区分大小写相等比较
public Boolean equalsIgnoreCase(String anotherString)
- 比较两个字符串大小
public int compareTo(String anotherString)
- 返回大于0:表示大于比较对象
- 返回等于0:两者相等
- 返回小于0 :表示小于比较对象
1.9 字符串查找
(1) public boolean contains(String str) : 判断str 在本字符串中是否存在
(2) public boolean startWith(String str) : 判断是否以指定字符串开头
(3) public boolean startWith(String str,int index) : 从指定位置开始判断是否以指定字符串开头
(4) public boolean endWith(String . str ) : 判断是否以指定字符串结尾
1.10 字符串替换
public String replaceAll(String regex , String replacement) : 替换所有指定内容
public String replaceFirst(String regex , String replacement) : 替换首个内容
1.11 字符串拆分
public String[] split(String regex) : 将字符串按照指定格式全部拆分
public String[] split(String regex ,int limit) : 将字符串部分拆分,数组长度为limit
1.12 字符串截取
public String substring (int beginIndex)[ : 从指定位置截取到字符串结尾
public String substring (int beginIndex,int endIndex)[ : 截取部分内容
用法如下:
public class Test{
public static void main(String[] args){
String str = "helloword";
String result1 = str.substring(5);
System.out.println(result1);
String result2 = str.substring(0,5);
System.out.println(result2);
}
}
运行结果:
word
hello
1.13 String 类其他方法
a . 去掉左右空格 ,中间保留
public string trim();
用法如下:
public class Test2{
public static void main(String[] args){
String str = " hello word ";
String result1 = str.trim();
System.out.println(result1);
}
}
运行结果:
hello word
b . 转大小写
public string toUpperCase(); // 转大写
public string toUpperCase(); // 转小写
用法如下:
public class Test{
public static void main(String[] args){
String str = "hello word";
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
}
}
运行结果:
HELLO WORD
hello word
c . 判断字符串是否为空(只能判断是否为空字符串,而不是null,因为isEmpty和对象相关,如果为null,则调不了,会出错)
public boolean isEmpty();
所以以后判断字符串为空可用
if(str == null || str.isEmpty()){};
String 类没有提供首字母大写操作,需要自己实现
首字母大写代码如下(利用字符串截取操作); * * * * * *
public class Test2{
public static void main(String[] args){
String str = "hello";
System.out.println(firstCase(str));
}
public static String firstCase(String str){
return str.substring(0,1).toUpperCase()+
str.substring(1,5);
}
}
1.14 两只sb (面试)-方便进行字符串修改 * * * * *
在java . lang 中基础包不需要导入,自动导入
StringBuffer
StringBuilder
a . 字符串修改
public StringBuffer append(各种数据类型)
字符串修改如下:
public class Test2{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
sb.append("hello").append(10);
System.out.println(sb);
}
}
运行结果:
hello10
b . stringBuffer <-> String 相互转换
I . string -> stringBuffer
调用stringBuffer的构造方法或append ();
StringBuffer sb = new StringBuffer("hello");
II . stringBuffer -> string
调用 stringBuffer . toString();
StringBuffer sb = new StringBuffer("hello");
String result = sb.toString();
c . 字符串反转
public StringBuffer reverse();
应用如下:
public class Test2{
public static void main(String[] args){
StringBuffer sb = new StringBuffer("helloword");
StringBuffer result = sb.reverse();
System.out.println(result);
}
}
结果:
drowolleh
d . 删除指定范围数据
public stringBuffer delete (int start ,int end);
应用举例:
public class Test{
public static void main(String[] args){
StringBuffer sb = new StringBuffer("helloword");
sb.delete(0,5);
System.out.println(sb);
}
}
结果:
word
e . 插入数据
public StringBuffer insert(int offset, 各种数据类型);
public class Test2{
public static void main(String[] args){
StringBuffer sb = new StringBuffer("helloworld");;
System.out.println(sb.delete(0,5).insert(5,"真好"));
}
}
结果:
world真好
(1) string 的内容不可修改,而两只sb 可以改内容(append)
(2) stringBuffer 采用同步处理,线程安全,效率较低。
stringBuilder 采用异步处理,线程不安全,效率较高,string“+”底层会将string-> stringBuilder
2.object 类(RealFather)
object 是Java 默认提供的类。
(1)java 除了object类,所有的类都存在继承关系,默认会继承object 父类,所有类对 象都可以通过object 进行接收。
2.1 取得对象信息 - toString()
直接使用对象输出,默认输出一个地址编码。如果现在输出的是string 对象,此时输出字符串内容而非地址,原因就在于string 类覆写了object的 tostring 方法
System.out.println()
系统输出默认会调用对象toString()
如果默认给出的tostring () 功能不足(不想输出地址而是输出本类信息),需要在子类中覆写toString() 方法
2.2 对象的比较 - equals() ( 一定要会写)
2.3 接收引用数据类型
object 可以接收所有引用类型,包括:类、数组、接口
3.包装类
包装类就是将基本数据类型封装到类中
3.1 分类
-
对象型包装类(object的直接子类):Boolean(boolean) 、 Character(char)
-
数值型包装类(Number 的直接子类),存在数值转换异常:Byte(byte)、Short(short)、Long(long) 、
Double(double) 、 Float(float)、 Integer(int)
3.2 装箱与拆箱-基本数据类型与相应包装类的数据处理
装箱:将基本数据类型变为包装类对象,利用每个包装类提供的构造方法实现装箱
Integer i = new Integer(10)
int result = i.intValue();
Integer i2 = 20;
int result = i2+10;
拆箱:将包装类中包装的基本类型值取出,利用Number 类提供的xxValue() 实现拆箱处理。
**阿里编码规范:**所有相同类型的包装类对象之间值的比较,全部使用equals方法比较
说明:
对于Integer var = ? 在-128—127之间的复制,Integer 对象在Integer 常量池产生,会复用已有对象,这个区间内的Integer 值可以直接使用 == 判断。除此之外的所有数据,都会在堆上产生,并不会复用已有对象。这是一个
使用int 还是 Integer ?
- [强制]所有POJO类(简单java类)属性必须使用包装类型
- [强制]RPC方法的返回值和参数必须使用包装类型
- 所有的局部变量使用基本类型(方法中)
3.3 字符串与基本类型转换
(1)将字符串转为基本类型(静态方法)
调用各个包装类.parseXX(string str)
Integer . parseInt(String str);
(2)基本类型变为字符串
a . ""+基本类型
b . 使用String 类的valueof(基本数据类型,静态方法),此方法不产生垃圾空间