JAVA高级阶段知识点总结

本文详细介绍了Java中关于String、StringBuilder、StringBuffer、System、Runtime、包装类、异常处理、多线程、集合框架、IO流等相关知识点。特别强调了字符串的不可变性、可变字符串的使用场景以及效率,解释了自动装箱和拆箱的概念,还涵盖了异常的分类和处理方式,包括自定义异常。此外,还讨论了集合框架中的List、Set接口以及其实现类ArrayList和LinkedList、HashSet和TreeSet的特点与区别,以及文件操作和网络编程的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String字符串

String是一个类,属于引用类型。

Java程序中一切使用""引起来的内容,都是这个类的实例,称为字符串对象。

字符串定义后是一个常量,值不可更改。字符串实际是一个字符数组

String str="hello";//这句话在执行时,创建一个hello字符串对象,将其地址保存在str变量中 
str="abc";//这里看似是在改变字符串的值,实际是又创建了一个字符串对象abc,将其地址保存在str变 量中
//以上两句话,在内存中会有两个字符串对象hello和abc,str只引用最后赋值的字符串地址abc 
String str2="abc";
//字符串实际是一个字符数组 
char[] list = {
   'a','b','c'}; 
String str3= new String(list);
//这里str2和str3中保存的内容是一样的

在这里插入图片描述

String类使用时注意

由此可见,如果要频繁更改String类型变量的值,不要使用String对象操作字符串,效率很低又浪费内存空间。

System.out.println("程序执行开始");
String str="";
//10万次的循环,会创建10万个字符对象,但最终只有最后的字符串对象被str引用,其余字符串均为“垃圾”
for(int i=0;i<10000;i++){
   
    str+=i;
}
System.out.println("程序执行结束");

如果要频繁更改字符串中的值,建议使用StringBuilder类或StringBuffer

如何创建一个字符串对象

1.使用""赋值创建

String str="hello你好";

2.通过构造方法创建

常用构造方法 说明
String() 创建一个空白字符串对象,实际创建一个空字符数组
String(String str) 创建一个指定的字符串对象,实际是创建一个形参字符串的副本
String(char[] list) 创建一个指定字符数组的字符串对象
String(byte[] list) 按默认编码格式创建一个指定字节数组的字符串对象
String(byte[] list,String charsetName) 按指定的编码格式创建一个指定字节数组的字符串对象

不同方式创建字符串的过程

使用""赋值的形式创建

public class Test2 {
   
    public static void main(String[] args) {
   
        //这句话执行时,先判断字符串常量池中是否存在"ab",不存在则创建,将其地址保存到str1变量中
        String str1 = "ab";
        //这句话执行时,先判断字符串常量池中是否存在"ab",已存在不创建,直接使用已有的"ab"保存到str2中
        String str2 = "ab";
        //这句话执行时,+两端的内容如果都是通过""定义的字符串,拼接过程在编译时已经完成,所以判断字符串常量池中是否存在"ab"
        //依然存在,将其保存到str3中
        String str3 = "a" + "b";
        //以上三句话,只会在字符串常量池创建一个字符串对象"ab",分别引用给三个变量
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);

        System.out.println(str1 == str2);//true
        System.out.println(str1 == str3);//true
        System.out.println(str2 == str3);//true

    }
}

可以使用java自带的反编译工具javap对class文件进行反编译。

在class文件所在的目录下,进入控制台,输入**javap -c class文件名.class

在这里插入图片描述

使用构造方法String(String str)创建

public class Test3 {
   

    public static void main(String[] args) {
   
        //1.在字符串常量池中寻找"ab",不存在则创建
        //2.在堆中new String(),将字符串常量池中的"ab"保存到该空间中
        //3.将堆中new String()的地址保存到变量str1中
        String str1=new String("ab");
        //1.在字符串常量池中寻找"ab",存在直接使用
        //2.在堆中new String(),将字符串常量池中的"ab"保存到该空间中
        //3.将堆中new String()的地址保存到变量str2中
        String str2=new String("ab");

        System.out.println(str1);
        System.out.println(str2);
        //由于str1和str2保存的是堆中的两个区域,所以这里是false
        System.out.println(str1==str2);


    }
}

在这里插入图片描述

使用+拼接""和new出来的字符串对象

public class Test4 {
   
    public static void main(String[] args) {
   
        //在字符串常量池中定义"ab",保存到str1中
        String str1 = "ab";
        //1.在字符串常量池中定义"a"
        //2.在堆中创建StringBuilder对象
        //3.在字符串常量池中定义"b"
        //4.在堆中创建String对象,将“b”保存其中
        //5.将"a"和String对象添加到StringBuilder对象中
        //6.将StringBuilder对象保存到变量str2中
        String str2 = "a" + new String("b");//一共创建了4个对象"a","b",new String()、new StringBuilder()

        System.out.println(str1);
        System.out.println(str2);
        //str1和str2是两个不同地址
        System.out.println(str1 == str2);//false


    }
}

在这里插入图片描述

总结

在使用字符串时,如果要比较其值是否相同,不要使用判断,因为判断的是内存地址。

所以在比较字符串是否相同时,要使用String重写的equals方法进行判断。

String中equals方法判断的原理,大致为:将两个字符串保存到字符数组中,再对每个字符逐一比较,

如果全部一致则返回。

在使用equals方法时,通常要将已知的非空字符串作为调用者。

password.equals("123123");//如果这样写,在password变量为null的情况下,会有空指针异常 
"123123".equals(password);//这样将已知非空的字符串作为调用者,就能避免空指针异常

字符串常用方法

方法名 返回值 作用
length() int 获取字符串的长度
trim() String 去除字符串首尾的所有空格
toLowerCase() String 转换字符串为小写
toUpperCase() String 转换字符串为大写
isEmpty() boolean 判断是否为一个空字符串
getBytes() byte[] 按默认编码格式将字符串转换为字节数组
toCharArray() char[] 将字符串转换为字符数组
equalsIgnoreCase(String str) boolean 忽略大小写比较指定字符串是否相同
equals(String str) boolean 判断字符串是否相同
charAt(int index) char 获取index位置上的字符串
indexOf(String str) int 获取str第一次出现的位置,如果没有返回-1
concatains(字符序列) boolean 判断指定的字符序列(字符串)是否存在于原字符串中
concat(String str) String 将str拼接到原字符串末尾
startsWith(String str) boolean 判断是否以指定字符串开头
endsWith(String str) boolean 判断是否以指定字符串结尾
substring(int index) String 截取原字符串在[index,数组长度)区间内的字符。(从指定位置截取至末尾,包含指定位置)
substring(int from,int to) String 截取原字符串在[from,to)区间内的字符,(从from截取至to,包含from不包含to)
split(String reg) String[] 按指定字符串或正则表达式切分原字符串。如果指定内容不在末尾,n个指定字符串能得到n+1个子串;如果指定内容在末尾,n个指定字符能得到n个字串(不包含末尾的无效字符)
String.valueOf(参数) String 将一个参数转换为字符串,参数可以是原始类型,也可以是任意对象。
replace(char oldChar,char new Char) String 使用newChar替换oldChar
lastIndexOf(String str) int 获取str最后一次出现的位置,如果没有返回-1

字符串与原始类型之间的转换

原始类型转换为字符串

String.valueOf(原始类型参数);

int num=123; 
String str=String.valueOf(num); System.out.println(str.length());

字符串转换为原始类型

使用原始类型对应的包装类,调用其pareseXXX(字符串)方法

String num="123"; 
int i=Integer.parseInt(num);

可变字符串

String字符串对象是一个常量,在定义后其值不可改变。

如果使用String类的对象,对其频繁更新时,就会不停地创建新的对象,重新引用。

所以如果要执行1000次重新赋值的过程,就要创建1000个字符串对象,花费很多时间和内存空间,所以效率很低。这时就需要使用可变字符串类。

/*
 * 可变字符串
 * */
public class Test1 {
   
    public static void main(String[] args) {
   
        //定义一个空的可变字符串对象
        StringBuilder sb = new StringBuilder();
        //定义一个普通字符串对象
        String str = "";

        //1970 1 1 0:0:0   到当前这个瞬间,经过了多少毫秒。记录开始时间
        long begin = System.currentTimeMillis();
        //模拟循环多次频繁操作字符串,记录花费的时间
        for (int i = 1000000; i > 0; i--) {
   
            //如果使用字符串,每次循环都会创建一个新的String字符串对象,重写引用给str,需要花费大量时间
            // str+=i;
            //如果使用可变字符串,只有一个对象sb参与,每次都在操作这个对象,不创建新对象,很快就能结束
            sb.append(i);
        }
        //记录结束时间
        long end = System.currentTimeMillis();

        System.out.println(end - begin);



    }
}

StringBuilder类

用于表示可变字符串的一个类,是非线程安全的,建议在单线程环境下使用,效率略高于StringBuffer。

StringBuffer类

用于表示可变字符串的一个类,是线程安全的,建议在多线程环境下使用,效率略低于StringBuilder。

StringBuilder和StringBuffer中的方法作用都一致,只不过StringBuffer中的方法使用了synchronized关键字修饰,表示一个同步方法,在多线程环境下不会出现问题。

所以这里以StringBuilder为例。

构造方法

常用构造方法 作用
StringBuilder() 创建一个大小为16的字符数组。类似于String str=“”;
StringBuilder(int capacity) 创建一个指定大小的字符数组
StringBuilder(String str) 创建一个str长度+16的字符串数组后,将str添加到其中。类似于String str=“初始值”;

普通方法

方法 作用
append(Object obj) 将指定内容添加到原可变字符串对象末尾
delete(int start,int end) 删除[start,end)范围内的字符
deleteCharAt(int index) 删除指定索引的字符
Insert(int index,Object obj) 将obj添加到index位置上
replace(int start,int end,String str) 将[start,end)范围内的字符替换为str
reverse() 翻转原字符串

注意

  • 以上方法都是在直接操作原字符串,每个方法调用后,原字符串都会发生变化。

  • StringBuilder或StringBuffer中并没有重写equlas方法,所以要比较两个可变字符串对象的值是否

    相同时,需要将可变字符串对象转换为String对象后,调用equals方法比较。

可变字符串与不可变字符串之间的转换

有些方法如indexOf()、charAt()等,在String和StringBuilder中都存在,可以不用转换。

但有些方法如getBytes()、contains()等,只能通过String调用,这时就需要进行转换。

不可变字符串转换为可变字符串

通过创建一个可变字符串对象,将不可变字符串作为参数实现转换。

//定义一个不可变字符串对象 
String str="hello"; 
//创建一个可变字符串对象,将不可变字符串对象作为参数 
StringBuilder sb = new StringBuilder(str);
可变字符串转换为不可变字符串

通过调用可变字符串的toString()方法实现转换

//创建一个可变字符串对象 
StringBuilder sb = new StringBuilder("hello"); 
//调用toString()转换为String类型 
String str=sb.toString();

System类

这个类包含了一些系统相关的信息和操作数组的方法。其中的方法和属性都是静态的

常用属性和方法 作用
System.in 获取系统输入流对象,通常用于获取输入信息
System.out 获取系统打印输出流对象,通常用于打印普通信息
System.err 获取系统打印输出流对象,通常用于打印异常信息
System.exit(int statues) 终止虚拟机运行,0表示正常结束
System.getenv(String key) 获取系统指定的环境变量信息
System.arraycopy(原数组,原数组起始位置,目标数组,目标数组起始位置,原数组要赋值的元素数量) 将原数组中指定长度的元素赋值到数组中
System.currentTimeMills() 获取从1970.1.1 0:0:0(UTC)至今经过了多少毫秒。中国是UTC(+8)所以是从1970.1.1 8:0:0至今经过了多少毫秒,返回long类型

Runtime类

Runtime类的对象,用于表示程序运行时对象(程序运行环境对象)。

包含了程序运行环境相关的信息。常用于获取运行环境信息(如虚拟机内存)或执行某个命令。

特点

这个类不是一个抽象类,但不能创建对象,因为其构造方法是私有的。

但是它提供了一个静态方法getRuntime(),通过这个方法,可以获取一个Runtime类的对象。

这就是java中的一种设计模式–单例模式(只能有一个对象创建)

public class Test {
   
    public static void main(String[] args) throws IOException, InterruptedException {
   
        //通过静态方法getRuntime()获取一个Runtime类的对象
        Runtime runtime = Runtime.getRuntime();
        //获取程虚拟机空闲内存,单位为字节
        System.out.println("当前虚拟机空闲内存" + runtime.freeMemory() / 1024 / 1024 + "MB");
        //获取虚拟机总内存
        System.out.println("当前虚拟机最大内存" + runtime.totalMemory() / 1024 / 1024 + "MB");
        //获取虚拟机支持的最大内存
        System.out.println("当前虚拟机支持的最大内存" + runtime.maxMemory() / 1024 / 1024 + "MB");
        //让系统运行某个指令或程序,返回当前运行的进程对象
        Process mspaint = runtime.exec("mspaint");//打开画图工具

        Thread.sleep(3000);
        //通过进程对象调用destroy()销毁进程,关闭程序
        mspaint.destroy();

        runtime.exec("calc");//打开计算器
        runtime.exec("notepad");//打开记事本
        //打开某个可执行文件
        runtime.exec("D:\\xiaopw84in1111\\disland.xiaopw84in1\\smynesc.exe");
        //300s后关机
        runtime.exec("shutdown -s -t 300");
        //取消关机任务
        runtime.exec("shutdown -a");
    }
}

方法调用时传值问题

Person类

public class Person {
   
    private String name;

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }
}

Test类

public class Test {
   
    /*
     * 如果参数是一个原始类型,当前方法中对该参数的所有操作,不会影响实参
     * */
    public static void fun1(int i) {
   
        i = 123;
        System.out.println(i);
    }

    /*
     * 如果参数是一个字符串,当前方法中字符串"重新赋值",实际是创建了一个新字符串对象,不会影响实参
     * */
    public static void fun2(String str) {
   
        str = "new";
        System.out.println(str);
    }

    /*
     * 如果参数是一个引用类型,当前方法中直接对该参数做操作,操作的就是实参,会影响实参
     * */
    public static void fun3(Person p) {
   
        p.setName("吴彦祖");
        System.out.println(p.getName());
    }

    /*
     * 如果参数是一个引用类型,当前方法中又创建了一个新的对象,操作的就是方法中的对象,不会影响实参
     * */
    public static void fun4(Person p) {
   
        p = new Person();
        p.setName("易烊千玺");
        System.out.println(p.getName());
    }

    /*
     * 如果参数是数组(引用类型),当前方法中在直接操作数组,会影响实参
     * */
    public static void fun5(int[] list) {
   
        list[0] = 111;
        System.out.println(list[0]);
    }



    public static void main(String[] args) {
   
        //方法参数是原始类型,方法内部的操作不影响实参
        int i = 0;
        fun1(i);//123
        System.out.println(i);//0

        //方法参数是字符串,方法内部用新字符串重新赋值,不影响实参
        String str = "old";
        fun2(str);//new
        System.out.println(str);//old

        //方法参数是引用类型,方法内部直接操作该参数,会影响实参
        Person p = new Person();
        p.setName("阿张");
        fun3(p);//吴彦祖
        System.out.println(p.getName());//吴彦祖

        //方法参数是引用类型,方法内部新创建了一个对象进行操作,不会影响实参
        Person p2 = new Person();
        p2.setName("阿王");
        fun4(p2);//易烊千玺
        System.out.println(p2.getName());//阿王

        //方法参数是数组,方法内部直接操作该数组中的元素,会影响实参
        int[] list={
   3,2,1};
        fun5(list);
        System.out.println(list[0]);

    }

}

总结

参数只有是引用类型(类、数组、接口),且方法中直接操作该参数时,才会对实参造成影响。

fun3(Person p)参数为Person对象,方法中调用setxxx,是在操作实参。

fun5(int[] list)参数为数组,方法中直接操作某个索引的元素,是在操作实参。

public static void fun(char[] list,Person p){
    
    list[0]='x';//这里在直接操作数组,会影响实参 
    p=new Person();//这里对参数p重新赋值了,不会影响实参 
    p.setName("小李"); System.out.println(list[0]+"\t"+p.getName()); 
}
public static void main(String[] args){
    
    Person p= new Person(); 
    p.setName("小美"); 
    char[] list={
   'a','b','c'}; 
    fun(list,p); System.out.println(list[0]+"\t"+p.getName()); 
}
//输出结果: 
//x 小李 方法内部打印方法执行的情况 
//x 小美 数组参数直接操作,发生改变;Person参数创建了一个新对象重新赋值,没有改变

包装类

Java是纯面向对象语言,宗旨是将一切事物视为对象处理。

但原始类型不属于对象,不满足面向对象的思想,但原始类型使用时无需创建对象,保存在栈中,效率更改。

为了让原始类型也有对象的类类型,达到"万物皆对象"的思想,所以就有了包装类的概念。

**包装类就是原始类型对应的类类型。**包装类通常用于将字符串转换为对应的原始类型。

在web应用中,从浏览器中获取到后台的数据,全是String类型,一定要使用转换的方法。

包装类 原始类型 将字符串转换为原始类型
Byte byte Byte.parseByte(String str)
Short short Short.parseShort(String str)
Integer int Integer.parseInt(String str)
Long long Long.parseLong(String str)
Float float Float.parseFloat(String str)
Double double Double.parseDouble(String str)
Boolean boolean Boolean.parseBoolean(String str)
Character char

特点

  • 八个原始类型中,除了int和char之外,其余类型的包装类,都是将首字母改为大写。int为Integer,char为Character

  • 除了Character类之外,其余类都有至少两个构造方法:参数为原始类型或字符串的构造方法。Character的构造方法只有一个,参数为char变量。

  • 除了Character类之外,其余类都有静态方法parse原始类型(String str),用于将字符串转换为相应的原始类型

    • 数值型的包装类的parseXXX()方法,如果不是一个真正的对应类型的数,转换时会抛出NumberFormatException异常,如"123abc"、"123.456"都不能使用Integer.parseInt()转换
    • Boolean类型中的parseBoolean()方法,参数如果是"true"这个单词,无论大小写,都能转换为真正的boolean值的true,只要不是"true"这个单词,转换结果都为false
  • 除了Boolean类之外,其余类都有MAX_VALUEMIN_VALUE这两个静态属性,用于获取对应原始类型支持的最大最小范围

  • 所有包装类中都有一个**compareTo(参数1,参数2)**方法,用于比较两个参数

    • 如果是数值型,参数1>参数2返回1,参数1<参数2返回-1,相同返回0
    • 如果是Boolean型,两个参数相同返回0,不同时,如果参数1为true返回1,否则返回-1
    • 如果是Character型,返回参数1-参数2的值。
  • 所有包装类中都有toString()方法,用于将包装类对象转换为String字符串对象

装箱和拆箱

  • 所有包装类都有一个静态方法valueOf(原始类型),将某个原始类型的数据转换为相应的包装类对象,这个过程称为装箱
//手动装箱 
int i=123;//定义一个原始类型的数据 
Integer aInteger=Integer.valueOf(i);//调用包装类的valueOf()方法将原始类型转换为包 装类对象
  • 所有包装类都有一个原始类型Value()方法,用于将包装类对象装换为原始类型,这个过程称为拆箱
//手动装箱 
int i=123;//定义一个原始类型的数据 
Integer aInteger=Integer.valueOf(i);//调用包装类的valueOf()方法将原始类型转换为包 装类对象
  • 所有包装类都有一个原始类型Value()方法,用于将包装类对象转换为原始类型,这个过程称为****
//手动拆箱 
Integer aInteger=new Integer(123);//创建一个包装类对象 
int i = aInteger.intValue();//调用包装类的"原始类型Value()"方法将其转换为原始类型
  • 自动装箱拆箱。在jdk1.5之后,加入了自动装箱拆箱的特性,可以直接在原始类型和对应的包装类中互相赋值
//自动装箱 
Integer aInteger=123; 
//自动拆箱 
int i=aInteger;
  • 自动装箱池
//以下代码的输出结果: 
Integer i1=new Integer(100); 
Integer i2=new Integer(100); 
//i3中保存的100,在byte范围内,保存在"自动装箱池"中 
Integer i3=100; 
//i4中保存的100,在byte范围内,如果有现成的,直接引用 
Integer i4=100
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值