【Java进阶篇】第三章 常用类

有时候,不是因为你没有能力,也不是因为你缺少勇气,只是因为你付出的努力还太少,所以,成功便不会走向你。而你所需要做的,就是坚定你的梦想,你的目标,你的未来,然后以不达目的誓不罢休的那股劲,去付出你的努力,成功就会慢慢向你靠近。

导读:本篇文章讲解 【Java进阶篇】第三章 常用类,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

在这里插入图片描述

一、String类

1、String类概述

  • String表示字符串类型,属于引用数据类型
  • 在Java中,随便使用双引号括起来的都是String对象,如”abc”、”Hello world!”就是两个String对象
  • Java中,字符串是不可变的
  • JDK中,双引号括起来的字符串,如”abc”都是直接存储在方法区的字符串常量池中(因为字符串在实际开发中使用频繁,为了执行效率)

2、String字符串的存储原理

凡是双引号括起来的,都在字符串常量池中有一份
new对象的时候一定在堆内存当中开辟空间

String s1 = "abcdef";
//实际在底层创建了三个字符串对象,都在字符串常量池中
//这就是Java中的字符串一旦创建就不可变,即不可在abcdef后直接补xy
String s2 = "abcdef"+"xy";
String s3 = new String("xy");

在这里插入图片描述

3、有String型属性的对象

class User{
	int id;
	String name;
}
....
User user = new User(110,"张三");

在这里插入图片描述
注意:name中存的是指向字符串常量池中的字符串对象的内存地址

4、两种字符串对象创建方式的区别

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);//true

在这里插入图片描述

String x = new String("xyz");
String y = new String("xyz");
System.out.println(x == y); //false

在这里插入图片描述
综上:String类的比较直接使用equals()方法:

String k = new String("testString");
//这么写更优,可以避免空指针异常
System.out.println("testString".equals(k));

//这么写k为null时空指针异常
System.out.println(k.equals("testString"));

String的特殊性:

  • int i = 100; i中存的是100这个值

  • String s = “abc”; s中存的是”abc”这个字符串对象在字符串常量池中的内存地址!!!

5、String类的特殊构造方法

构造方法中传入数组

//97即a,98是b,99是c
byte[] bytes = {97,98,99}; 
//传入一个数组
String s3 = new String(bytes);
//输出abc字符串
System.out.println(s3);

构造方法中传入数组和偏移量

//String(字节数组,数组元素起始下标。长度)
String s4 = new String(bytes,1,2);
//输出bc,即只将byte数组中的一部分转化为字符串
System.out.println(s4);

对于char数组char[] charArray以上构造方法同样可以用

总结String类的构造方法:

  • String s = new String(“xxx”);
  • String s = “xxx”;
  • String s = new String(char数组);
  • String s = new String(char数组,起始下标,长度);
  • String s = new String(byte数组);
  • String s = new String(byte数组,起始下标,长度);

6、String类中的方法

1)charAt方法—char

用法:

字符串对象 . charAt(int下标);

示例:

//返回一个char
char c = "中国人".charAt(1);
System.out.println(c);           //国

2)compareTo方法—int

作用:

按字典顺序比较两个字符串,靠后的字母是大的

示例:

//0 ,代表前后一致
int result1 = "abc".compareTo("abc");
//-1;代表前小后大,类比8-9
int result2 = "abcd".compareTo("abce");
//1, 代表前大后小,类比9-8
int result3 = "abce".compareTo("abcd");

//第一位的比较已经得出结论,x < y,-1
System.out.println("xyz".compareTo("yxz");

可以看到:equals只能看到是否相等,但compareTo方法还能看到谁打谁小:

//随便写个静态的自己编的equals方法协助理解

public static boolean equals(byte[] value,byte[] other){
        if(value.length == other.length) {
            for(int i=0;i<value.length;i++){
                if(value[i] != other[i]){
                    return false;
                }
            }
            return true;
        }
        return false;
}

3)contains方法—boolean

作用:

判断前面的字符串是否包含后面的字符串

示例:

//true
System.out.println("HelloWorld.java".contains(".java"));

4)endsWith方法—boolean

作用:

判断当前字符串是否以某个字符串结尾

示例:

//false
System.out.println("text.txt".endWith(".java"));

类似的,也有startWith方法,用法与endWith方法相同

5)equalsIgnoreCase方法—boolean

作用:
判断两个字符串是否相等,且忽略大小写

示例:

System.out.println("ABC".equalsIgnoreCase("abc"); //true

6)getBytes方法—byte[]

作用:
将字符串对象转换成字节数组,即返回一个byte数组

示例:

byte[] byteArray = "abcdef".getBytes();
for(int i=0;i<byteArray.length;i++){
	System.out.println(byteArray[i]);
}

运行:
在这里插入图片描述

7)indexOf()方法–int

作用:
判断某子字符串在当前字符串中第一次出现的索引下标

示例:

//6
System.out.println("oraclejava++java#".indexOf("java"));

//-1
System.out.println("abc".indexOf("qwe"));

判断最后一次出现的索引可以用lastIndexOf()

8)isEmpty()方法–boolean

作用:
判断某个字符串是否为空

示例:


String e = "";
System.out.println(e.isEmpty());  //true
//源码
public boolean isEmpty(){
	return value.length == 0;
}
//底层调用了字符串对象的length()方法
//System.out.println("abc".length());   //3

判断数组长度和字符串长度不一样,判断数组长度是length属性,判断字符串长度是length()方法

9)replace()方法—String

作用:
完成字符串对象某部分的替换

示例:

String newString = "http://code-9527.com".replace("http://","https://");
System.out.println(newString);
System.out.println("name=9527&age=22".replace("=",":"));

10)split()方法—-String[]

作用:
拆分字符串

示例:

String[] ymd = "2022-11-16".split("-");
for(int i=0;i<ymd.length;i++){
    System.out.println(ymd[i]);
}
//输出结果:2022 11 16

11)subString()方法—String

作用:
截取字符串

示例:

//传入要截取的起始下标
String a = "http://www.baidu.com".subString(7);

//重载后可以:
subString(int beginIndex,int endIndex)
//注意是左闭右开

12)toCharArray()方法—char[]

作用:
将字符串转换成char数组

示例:

char[] chars = "中国人".toCharArray();
for(int i=o;i<chars.length;i++){
	System.out.println(char[i]);
}

//输出: 中 国 人

13)toLowerCase()方法—String

作用:
将字符串中的大写字母转化为小写

示例:

String str ="AbcDEF".toLowerCase();
//即abcdef

//相反的:
toUpperCase()方法,将小写转化为大写

14)trim()方法—String

作用:
去除字符串前后的空白

示例:

String s = "    hello World   ".trim();

//输出hello world ,注意去除的只是前后的空格

15)valueOf()方法—String

作用:
将非字符串转化成字符串。
“String类中只有一个方法是静态的,不用new对象—valueOf()方法”

示例:

String s1 = String.valueOf(true);
String s2 = String.valueOf(100);

当静态方法valueOf传入参数是一个对象的时候,会自动调用该对象的toString()方法

class Customer{
//未重写toString方法
}
String s1 = String.valueOf(new Customer());
//输出s1结果是Customer@10f7689

为什么println输出一个引用时,默认调用引用的toString()方法?

println源码中:String s = String.valueOf(x); 而valueOf方法又调用了toString()

二、StringBuffer类

在实际的开发中,进行字符串频繁的拼接,又什么影响?
😉
Java中,字符串是不可变的,每一次拼接都会产生新的字符串,从而占用大量的方法区内存,造成空间浪费

Strings = "abc";
s += "hello";
//以上,在方法区字符串常量池中共创建了三个对象

当进行大量的字符串拼接时,用JDK中自带的java.lang.StringBuffer和java.lang.StringBuilder(Buffer即缓冲)

1、StringBuffer类的构造方法

构造一个其中不带字符的字符串缓冲区,初始容量为16字符

//源码
public StringBuffer(){
	super(16); //调用了父类的构造方法
}

//父类
AbstractStringBuilder(int capacity) {
        if (COMPACT_STRINGS) {
            value = new byte[capacity];
            coder = LATIN1;
        } else {
            value = StringUTF16.newBytesFor(capacity);
            coder = UTF16;
        }
    }

StringBuffer底层实际是一个byte[]数组,往StringBuffer中放字符串,实际上是放到byte数组中了

//创建一个初始化容量为16的byte[]数组(字符串缓冲区对象)
StringBuffer sb = new StringBuffer();
//append方法拼接字符串
sb.append("a");
sb.append("b");
//append方法和println相似,对各类型数据有重载
sb.append(3.14);
sb.append(true);
System.out.println(sb);   //结果:ab3.14true

注意:

append方法中调用了arrayCopy()方法,在进行字符串追加的时候,若byte数组满了,会自动扩容

2、String类和StringBuffer类的区别

  • String类底层是一个private final byte[] value
  • StringBuffer类底层是一个byte[] value

图示:

在这里插入图片描述

String和StringBuffer的底层虽然都是一个byte[]数组,但String的byte[]用了final修饰,而数组一旦创建长度不可变,且final修饰的引用一旦指向某个对象,就不可再指向其他对象,故String不可变
在这里插入图片描述

如何优化StringBuffer的性能?

在创建StringBuffer的时候,尽可能给定一个初始化容量(即使用有参构造),以减少底层数组扩容的次数。(预估后,给一个大点的初始化容量,默认16)

StringBuffer sb = new StringBuffer(100);

初始化容量太小,追加(拼接)没几次数组就满了,底层就得调用arrayCopy扩容,从而影响效率。

3、StringBuffer和StringBuilder的区别

StringBulider sb = new StringBulider();
sb.append("code");
sb.append(9527);
……

不同之处:

StringBuffer中的方法都有synchronized关键字修饰,表示StringBuffer在多线程环境下运行是安全的,相反,StringBuffer是非线程安全的

三、基础类型对应的8个包装类

1、包装类出现的背景

Java中为8种基本数据类型对应准备了8种包装类型,8种包装类属于引用数据类型,父类是Object。包装类存在的意义如图:
在这里插入图片描述

//写段代码帮助理解包装类的实现

public class MyInt{
    int value;
    public MyInt(){
        
    }
    public MyInt(int value){
        this.value = value;
    }
}
--------
//通过构造方法把100包装成了对象
MyInt mi = new MyInt(100);
//此时图中的doSome()方法可传参了
doSome(mi);

2、八种包装类

八种包装类
其中,前六种的父类的Number类。Boolean和Character的父类是Object。Number类是一个抽象类,不能直接new对象。

3、包装类的构造方法和常量

Integer类:

//Integer的两个构造方法:
//Integer(int)
//Integer("String")
Integer x = new Integer(100);
Integer y = new Integer("123");
//Integer类已经重写了toString()方法

Double类和Integer类相似:

Double d1 = new Double(1.23);
Double d2 = new Double("1.23");

通过访问包装类常量,可以获取最大值和最小值

System.out.println("int的最大值:" + Integer.MAX_VALUE);
//Integer.MIN_VALUE
//Byte.MIN_VALUE

4、自动装箱和自动拆箱

了解自动装箱、拆箱前先看一下装箱、拆箱:

装箱
//通过构造方法,将基本数据类型转化为引用数据类型
Integer i = new Integer(123);

------------
拆箱
//通过xxValue方法,将引用数据类型转化为基本数据类型
int retValue = i.intValue();
float f = i.floatValue();

在这里插入图片描述
自动装箱与自动拆箱:

//自动装箱
Integer x = 100;
//自动拆箱
int y = x;
Integer z = 1000;
//+两边要求基本数据类型,故z自动拆箱
System.out.println(z+1);
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);//,两对象的内存地址不同,false

//虽然是自动装箱,但本质还是Integer a = new Integer(1000);

比较坑爹的一个点:

//这里是false
Integer a = 128;
Integer b = 128;
System.out.println(a == b);
---------
//这里是true
Integer a = 127;
Integer b = 127;
System.out.println(a == b);

Java中,为了提高程序效率,将[-128,127]之间所有的包装对象提前创建好,放到了方法区的整数型常量池中,这个区间的数据不再需要new,直接从整数型常量池中取用,所哟后者是true

示意图:

Integer类加载的时候,会初始化整数型常量池,256个对象
在这里插入图片描述

5、Integer类的常用方法(拆箱)

Integer x = new Integer("123");  //123
Integer y = new Integer("string"); //error
Integer z = new Integer("中文");  //error

不是一个数字的字符串时,不能包装成Integer类型,编译不报错(因为构造方法中允许传入一个字符串)但运行出错。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

四、日期相关类

import java.util.Date;

1、获取系统当前时间

//调用Date类的无参构造,精确到毫秒

Date nowTime = new Date();

//Date类的toString方法已经被重写,英文格式的日期
System.out.println(nowTime);
//整理到这会儿突然有些emo,记录下此刻的时间吧。

在这里插入图片描述

2、日期格式化

import java.text.SimpleDateFormat;

Date nowTime = new Date();
//创建日期格式化对象
//yMd HmsS字符不可变,中间的格式连接符随意
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
//Date转成了String
String nowTimeStr = sdf.format(nowTime);
System.out.println(nowTimeStr); 

以上格式化日期的同时,也将Date类型转化成了String类型,那String类型如何转成Date类型

String time = "2022-11-17 22:36:26 666";

//此处的格式要和上面字符串中的格式一致,否则后面会java.text.ParseException异常
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

Date dateTime = sdf2.parse(time);

System.out.println(dateTime); //Thu Nov 17 22:36:26 CST 2022

3、currentTimeMillis方法

获取自1970年1月1日00:00:00起,到当前系统时间的毫秒数。

long nowTimeMillis = System.currentTimeMillis();

该方法可用于统计某方法执行所需时长:

long beginTime = System.currentTimeMillis();

xxx方法执行

long endTime = System.currentTimeMillis();
//endTime-beginTime

除了这个方法,System类中的方法还有:

  • System.g() 建议启动垃圾回收器
  • System.exit(0)退出JVM

4、Date类的有参构造方法


Date time =  new Date(1); //参数单位是毫秒,即1970-01-01 00:00:00 01

//获取昨天此时的时间

Date time2 = new Date(System.currentTimeMillis()-1000*24*60*60);

五、Random类

1、数字格式化

import java.text.DecimalFormat;

//#代表任意数字,逗号代表4分位, 点.代表小数点,0代表不够时补0
DecimalFormat df = new DecimalFormat("###,###.##");

String s2 = df.format(1234.56789);  //1,234.57

2、BigDecimal

发音big dai sei mao,属于大数据,精度极高,不属于基本数据类型,属于引用数据类型,常用于财务软件当中。

BigDecimal v1 = new BigDecimal(100);
BigDecimal v2 = new BigDecimal(200);

//别使用v1+v2
//v1和v2是引用,别用+
BigDecimal v3 = v1.add(v2);

//除
BigDecimal v4 = v2.divide(v1);

3、产生随机数

//创建random对象
Random random = new Random();

//产生一个随机数
int num1 = random.nextInt();

//netInt(101),即下一个是100
//所以产生一个[0~100]之间的随机数
int num2 = random.nexInt(101);

练习:生成五个不重复的随机数

/**
 * 先理清思路,梳理逻辑,再提取方法,最后填充代码实现
 * 可先写个长度为5的初始数组,再产生一个个随机数,放入数组
 * 为了保证不重复,进入数组前需要比较(此处需要一个比较是否相同,或元素是否包含于数组的方法)
 */

import java.util.Arrays;
import java.util.Random;
public class RandomTest {
    public static void main(String[] args) {
        int[] array = new int[5];
        /**
         * 改一下数组中元素的初始值
         * 赋初值-1
         */
        for(int i=0;i<array.length;i++){
            array[i] = -1;
        }
        int index = 0;
        Random random = new Random();
        while(index<array.length){
            int element = random.nextInt(10001);
            //这里的if条件,一开始可以用汉字先占位表达逻辑
            //if(元素不包含于数组)
            if(!contains2(array,element)){
                array[index] = element;
                index++;
            }

        }
        //遍历输出即为5个不重复的随机数
        for(int i=0;i<array.length;i++){
            System.out.println(array[i]);
        }

    }

    /**
     * 判断元素是否包含于数组
     * “是否”即boolean返回类型
     * @param array
     * @param num
     * @return
     */
    public static boolean contains(int[] array,int num){
        Arrays.sort(array);
        //返回>=0的索引即找到了,也就是包含,反之不包含
        return Arrays.binarySearch(array,num) >=0;
    }

    /**
     * 不用Arrays类提供的排序和二分查找,我自己用遍历查找
     * @param array
     * @param num
     * @return
     */
    public static boolean contains2(int[] array, int num){
        for(int i=0;i<array.length;i++){
            if(array[i] == num){
                return true;
            }
        }
        return false;

    }
}

//第一个使用排序会对每次循环中原数组下标发生重新洗牌,赋值出现错位,存在bug,使用contains2方法遍历

六、枚举

就上上面例子中的contains方法,只有两种返回结果,这时使用boolean返回类型很合适,但当返回结果有两种以上,且都是一枚一枚的可以列举出来的时候,boolean就不再满足了=====>枚举诞生。

1、枚举

一枚一枚可以列举出来的,建议使用枚举类型,枚举类型属于引用数据类型。枚举编译之后也是生成class文件,枚举中的每一个值可以看作是常量

//举个例子,先写两个结果的来举例

public enum Result {
    SUCCESS,FAIL
}
class TestEnum{
    public static void main(String[] args) {
        Result r = divide(10,0);
        System.out.println(r==Result.SUCCESS ? "计算成功" : "计算失败");
    }
	//注意这里返回类型是枚举类型
    public static Result divide(int a,int b){
        try{
            int c = a/b;
            return Result.SUCCESS;
        }catch(Exception e){
            return Result.FAIL;
        }
    }
}

2、枚举类型的定义

enum 枚举类型名{       //引用数据类型
  枚举值1,枚举值2,枚举值3    //常量
}

举例:

public enum Color{
	RED,BLUE,YELLOW,BLACK
}

3、switch+枚举

public enum Season {
    SPRING,SUMMER,AUTUMN,WINTER
}
switch(){
            case Season.SPRING:       //case中的枚举名必须省略
                System.out.println("春天");
                break;
            case Season.SUMMER:
                System.out.println("夏天");
                break;
            case Season.AUTUMN:
                System.out.println("秋天");
                break;
            case Season.WINTER:
                System.out.println("冬天");
                break;
        }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/146102.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!