java常用类(包装类,String,StringBuffer,StringBuilder)和异常
1 java中的 包装类
1.1为什么java中有了基本类型为什么还要有包装类型?
为什么存在这两种类型呢?
我们都知道在Java语言中,new一个对象存储在堆里,我们通过栈中的引用来使用这些对象;但是对于经常用到的一系列类型如int,如果我们用new将其存储在堆里就不是很有效——特别是简单的小的变量。所以就出现了基本类型,同C++一样,Java采用了相似的做法,对于这些类型不是用new关键字来创建,而是直接将变量的值存储在栈中,因此更加高效。
有了基本类型为什么还要有包装类型呢?
我们知道Java是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
另外,当需要往ArrayList,HashMap中放东西时,像int,double这种基本类型是放不进去的,因为容器都是装object的,这是就需要这些基本类型的包装器类了。
二者相互转换:
1、int转Integer
1. int i = 0;
2. Integer ii = new Integer(i);
2、Integer转int
1. Integer ii = new Integer(0);
2. int i = ii.intValue();
二者的区别:
1. 声明方式不同:
基本类型不使用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间;
2. 存储方式及位置不同:
基本类型是直接将变量值存储在栈中,而包装类型是将对象放在堆中,然后通过引用来使用;
3.初始值不同
基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null;
4. 使用方式不同:
基本类型直接赋值直接使用就好,而包装类型在集合如Collection、Map时会使用到。
1.2 八种基本的数据类型对应的包装类
基本数据类型包装类byteBytebooleanBooleanshortShortcharCharacterintIntegerlongLongfloatFloatdoubleDouble
【示例】包装类的使用
public class Test {
/** 测试Integer的用法,其他包装类与Integer类似 */
void testInteger() {
// 基本类型转化成Integer对象
Integer int1 = new Integer(10);
Integer int2 = Integer.valueOf(20); // 官方推荐这种写法
// Integer对象转化成int
int a = int1.intValue();
// 字符串转化成Integer对象
Integer int3 = Integer.parseInt("334");
Integer int4 = new Integer("999");
// Integer对象转化成字符串
String str1 = int3.toString();
// 一些常见int类型相关的常量
System.out.println("int能表示的最大整数:" + Integer.MAX_VALUE);
}
public static void main(String[] args) {
Test test = new Test();
test.testInteger();
}
}
int能表示的最大整数:2147483647
1.3 自动转向和自动拆箱
自动装箱和拆箱就是将基本数据类型和包装类之间进行自动的互相转换。JDK1.5后,Java引入了自动装箱(autoboxing)/拆箱(unboxing)。
自动装箱:
基本类型的数据处于需要对象的环境中时,会自动转为“对象”。
我们以Integer为例:在JDK1.5以前,这样的代码 Integer i = 5 是错误的,必须要通过Integer i = new Integer(5) 这样的语句来实现基本数据类型转换成包装类的过程;而在JDK1.5以后,Java提供了自动装箱的功能,因此只需Integer i = 5这样的语句就能实现基本数据类型转换成包装类,这是因为JVM为我们执行了Integer i = Integer.valueOf(5)这样的操作,这就是Java的自动装箱。
自动拆箱:
每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用intValue()、doubleValue()等转型方法。
如 Integer i = 5;int j = i; 这样的过程就是自动拆箱。
我们可以用一句话总结自动装箱/拆箱:
自动装箱过程是通过调用包装类的valueOf()方法实现的,而自动拆箱过程是通过调用包装类的 xxxValue()方法实现的(xxx代表对应的基本数据类型,如intValue()、doubleValue()等)。
自动装箱与拆箱的功能事实上是编译器来帮的忙,编译器在编译时依据您所编写的语法,决定是否进行装箱或拆箱动作。
【示例】自动装箱
//自动装箱
Integer i= 100;
//相当于编译器自动为您做出以下的语法编译
Integer j = Integer.intValueOf(100);
【示例】自动拆箱
Integer i = 100;
//自动拆箱
int j = i;
//相当于编译器自动为您做出以下的语法编译
int j = i.intValue();
包装类多了一个null值
Integer i= null;
当i是null值时,不能用它进行对象操作,会报空指针异常
Integer c = null;
int d = c;//此时会报错空指针异常,原因该句就是调用c.intValue();
1.4 包装类的缓存问题 ###
整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
【示例】Integer类相关源码如下
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
一般情况下 IntegerCache.low为-128,IntegerCache.high为127
【示例】Integer类的赋值比较
public static void show(){
Integer i = 100;
Integer j = 100;
System.out.println(i == j);
Integer a1 = 130;
Integer a2 = 130;
System.out.println(a1 == a2);
}
true
false
2 Java中的String类
String类是一个对字符串进行操作的类,String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
字符串是常量;它们的值在创建之后不能更改。
原因:String底层就是通过char[]数组来实现的。char数组被final修饰,则定义为不可改变的。 private final char value[];
字符串一旦被初始化就不可以改变。
2.1String字符串变量的创建
String str = "adc";
2.2 String类常见的方法
常见的操作有哪些
1.获取
1.1 字符串中包含了字符数,也就是字符串的长度
int length();
1.2 根据位置获取位置上的某个字符。
char charAt(int index);
1.3 根据字符获取该字符在字符串的位置
int indexOf(int ch);//返回的是ch在字符串中第一次出现的位置。
int indexOf(String str);//返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex);//从fromIndex指定位置开始,返回指定子字符串在此字符串中第一次出现处的索引。
int lastIndexOf(String str);//返回指定子字符串在此字符串中最右边出现处的索引
2.判断
2.1 字符串中是否包含某一个子字符串
boolean contain(String str);
特殊之处:indexOf(str):可以索引str第一次出现的位置,如果返回-1,表示该str不在该字符串中。
所一,也可以用于对指定判断是否包含
if(str.indexOf(str) != -1)
而且该方法既可以判断,又可以获取出现的位置。
2.2 字符串是否有内容
boolean isEmpty();
2.3 字符串是否以指定内容开头
boolean startsWidth(String str);
2.4 字符串是否以指定内容结尾
boolean endsWith(String str);
2.5 判断字符串内容是否相同,不忽略大小写
boolean equals(String str);
2.6 判断内容是否相同,并忽略大小写
boolean equalsIgnoreCase();
3.转换
3.1 将字符数组装成字符串。
构造函数:String(char[])
String(char[], offset, count):将字符数组中的一部风转成字符串。
静态方法:
static String copyValueOf(char[] data,int offset, int count);
static String valueOf(char[]);
3.2 将字符串转成字符数组。
char[] toCharArray();
3.3将字节数组转成字符串
String(byte[]);
String(byte[], offset, count);//将字节数组中的一部分专场字符串。
3.4 将字符串转成字节数组
byte[] getBytes();
3.5 将基本类型转成字符串
String valueOf(int);
String valueOf(double);
4.替换
String(oldChar, newChar); 如果要替换的字符不存在,则返回原字符串。
5.切割
String[] split(regex);// str.split(",");以逗号进行切割
6.获取子字符串 获取字符串中的一部分。
subString(begin);//从指定位置到结尾,如果下标不存在,会出现字符串下标越界异常。
subString(begin, end);//从begin到end [begin, end)
7.转换
7.1 将字符串转成大写或者小写
String toUpperCase();
String toLowerCase();
7.2 将字符串两端的多余空格去除
String trim();
7.3对两个字符串进行自然顺序的比较
int compareTo(String);//第一个不同就比较第一个字符,第一个字符相同,就比较第二个,一次类推,如果都相同,则返回字符串的length差值
2.3 StringBuffer类
【示例】String类的缺点
String str = "";
for(int i = 0; i <= 100; i++){
str += i;
System.out.println(str);
}
System.out.println(str);
0
01
012
0123
01234
012345
0123456
01234567
012345678
0123456789
012345678910
012345678910
由此可见中间会产生大量的中间对象,这些东西我们需要的就是最后一 个,前面的若干个都会浪费内存。如果情况更糟的话,有几百个上千个,或者中间的字符串更长,浪费将会更加的严重。StringBuffer的出现就是为了解决这个问题的。它是可变的,当修改或者追加字符串到原来的字符串对象上时,不会生成一个新的字符串。而是在原来的对象时上进行修改。这样,就不会分配大量的空间给临时对象了。
另外StringBuffer是线程安全的。还有一个它的兄弟类StringBuilder类,它是线程不安全的,当处在单线程时,StringBuffer执行的效率比较低,推荐使用StringBuilder,效果高。
2.3.1 StringBuffer常用的方法
StringBuffer是字符串缓冲区,是一个容器,
1.长度是可变化的。
2.可以直接操作多个数据类型。
3.最终会通过toString方法变成字符串。
1.储存
StringBuffer append():将指定的数据添加到已有数据的结尾处。
StringBuffer insert(index, 数据); 可以将数据插入指定位置。
2.删除
StringBuffer delete(start, end);//将指定的位之间的字符删除[start, end)
StringBuffer deleteCharAt(index);//删除指定位置的字符
3.获取
char charAt(int index);
int indexOf(String str);
int lastIndexOf(String str);
int length();
String subString(int start, int end);
4.修改
StringBuffer replace(start, end, str);
setCharAt(index, char);
5.反转
StringBuffer reverse();
6. 将缓冲区的指定位置数据,存入字符数据中
public void getChars(int srcBegin,
int srcEnd,
char[] dst,
int dstBegin)
StringBuilder与StringBuffer的用法一样。
【示例】 StringBuffer的添加元素用法
StringBuffer sb = new StringBuffer();
sb.append("sfd").append("水").append(1213);
12334dad
append()方法可以一直在后面追加内容,append方法返回的就是调用他的当前对象this。
2 Java中的 异常
异常机制的概述:
异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生了改变,程序的控制权转移到了异常处理器。
程序错误分为三种:1.编译错误; 2.运行时错误;3.逻辑错误。
1.编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因好位置,这个也是大家刚接触编程语言最常遇到的问题。
2.运行时错误是因为程序在执行时,运行时环境发现了不能执行的操作。
3.逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。
异常: 就是程序在运行时出现了不正常的情况。
异常由来:问题也是现实生活中一个具体的事物,也可以通过java类的形式进行描述。并封装成对象。 其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分两种 一种严重问题,一种非严重的问题。对于严重的 通过Error类进行描述。
对于Error类一般不便携针对性的代码对其进行处理。 对于非严重,通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都有一些共性内容。 比如:不正常的情况信息,引发原因等。
异常的体系划分
Throwable
-- Error
-- Exception
异常处理:
java提供了特有的语句格式来处理。
try{
需要被检测的代码;
}catch(异常类 变量){
处理异常的代码(处理方式);
}finally{
一定会执行的语句;
}
【示例】异常的基本使用
public static void method01(int a, int b){
try {
int x = a / b;
System.out.println("x: " + x);
}catch (Exception e){
System.out.println("除0了");
//获取异常信息
System.out.println(e.getMessage());
//异常类名:异常信息
System.out.println(e.toString());
//打印堆栈中的错误信息
e.printStackTrace();
}
System.out.println("over");
}
2.1 声明异常
声明异常时,建议声明更为具体的异常,这样处理的可以更具体。 原则:对方声明几个异常就对应有几个catch块,不要定义过多地catch块,如果多个catch块中异常出现继承关系, 父类异常catch块放在最后面,
建议在进行catch块处理时,catch中一定要定义具体的处理方式 不要简单定义一句e.printStackTrace(); 也不要简单的输出一条简单的语句。、
【示例】java异常的声明
//声明异常时,建议声明更为具体的异常,这样处理的可以更具体。
int div(int a, int b) throws ArithmeticException {
return a/b;
}
2.2 异常的抛出
Java中异常的抛出使用throw关键字来标识的。
【示例 】java异常的声明 ####
public static void main(String[] args) {
method_01(3,0);
}
public static int method_01(int a, int b){
if(b == 0){
throw new ArithmeticException("被0除了");
}
return a;
}
throw 和throws的区别
throws使用在函数上(在函数参数列表小括号和大括号之间) throw使用在函数内
throws后面跟的是异常类,可以跟多个,用用逗号隔开 throw后面跟的是异常对象
特殊的异常类,可以不声明该类异常。
Exception中有一个特殊的子类异常RuntimeException运行时异常
如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过。
注意:之所以不用再函数上声明,是因为不需要让调用者处理
当该异常发生时,希望程序停止,因为在运行时,出现了无法继续运算的
情况,希望停止程序后, 对代码进行修正。
自定义异常时,如果该异常的发生,无法在继续进行运算时, 就让自定义异常继承RuntimeException类。
对于异常分两种:
1.编译时被检测的异常。
2.编译时不被检测的异常(RuntimeException以及其子类)
2.3 异常在子类中的覆盖表现
1.子类在覆盖父类时,如果父类的方法抛出异常,name子类的覆盖方法,只能抛父类的异常 或者该异常的子类。
2.如果父类方法抛出多个异常,那么子类在覆盖父类方法时,只能抛出父类异常的子集。
3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生异常,就必须要进行try处理,不能抛异常。
2.5 java异常的总结 ####
异常:
是对问题的描述,将问题进行对象的封装。
异常体系
Throwable
-- Error
-- Exception
---RuntimeException
异常体系中的特点:异常体系中的所有类以及建立的对象都具备可抛性。
也就是说可以被throw和throws关键字所操作。
只有异常体系具备这个提点。
throw和throws的用法:
throw定义在方法内,用于抛出异常对象。
throws定义在方法上,用于抛出异常类,可以抛出多个用逗号隔开。
当方法内容有throw抛出异常对象,并未进行try处理,必须要在方法上声明,编译失败。
注意,RuntimeException除外,也就是说,方法内如果抛出RuntimeException异常,方法上可以不声明。
如果方法声明了异常,调用者需要进行处理。处理方法可以throws可以try。
异常有两种:
编译时被检测异常
该异常在编译时,如果没有处理(没有抛也没有try),编译失败。
该异常被标识,代表这可以被处理。
运行时异常(编译时不检测)
在编译时,不需要处理,编译器不检查。
该异常的发生,建议不处理,让程序停下来,需要对代码进行纠正。
异常处理语句:
1. try{
} catch(){
}
2.try{
}finally{
}
3.try{
}catch(){
}finally{
}
注意:finally中定义的通常是关闭资源代码。。因为资源必须被释放。
finally只有一种情况不会执行,当指向到System.exit(0)的时候。finally不会执行。
自定义异常:
定义类继承Exception或者RuntimeException
1.为了该自定义类具备可抛性
2.为了该类具备操作异常的共性方法。
当要定义自定义信息时,可以使用父类已经定义好的功能。
异常信息传递给父类的构造方法。
class MyException extends Exception{
MyException(String message){
super(message);
}
}
自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装。
异常的好处:
1.将问题进行封装。
2.将正常流程代码和问题出来了代码进行分离,方便阅读。
异常处理的原则:
1.处理方式有两种:try或者throws。
2.调用到抛出异常的功能时,抛出几个,就处理几个。
一个try对应多个catch
3. 多个catch,父类的catch放到最下面。
4.catch内,需要定义正对性的处理方式,不要简单的定义printStacTrace(),输出语句。
也不要不写。
当捕获到的异常,本功能处理不了时,可以继续在catch抛出。
try{
throw new AException();
}catch(AException e){
throw e;
}
如果改异常处理不了,但并不属于改功能出现的异常。
可以将异常转换后,在抛出和该功能相关的异常。
或者异常可以处理,当需要将异常产生的功能和本功能相关的问题提供出去,
让调用者知道,并处理。也可以将捕获的异常处理后,转化新的异常。
try{
throw new AException();
}catch(AException e){
throw new BException();
}
比如汇款的例子。
异常的注意事项:
在子父类覆盖时:
1.子类抛出的异常必须是父类异常的子类或者子集。
2.如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try,不能抛。