首页 > 其他分享 >String

String

时间:2024-08-18 13:54:11浏览次数:11  
标签:String int println str 字符串 常量

递归

(菲波那切数列)

递归:方法自己调用自己的现象就称为递归。

递归的分类:

  • 递归分为两种,直接递归和间接递归。
  • 直接递归称为方法自身调用自己。
  • 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。

注意事项

  • 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。

  • 在递归中虽然有限定条件,但是递归深度不能太深,否则效率低下,或者也会发生栈内存溢出。

    • 能够使用循环代替的,尽量使用循环代替递归

字符串String

java.lang.String 类代表字符串。Java语言提供对象字符串的特殊支持:

  • Java程序中所有的字符串文字(例如"abc" )都可以被看作是实现此类的实例,即所有""引起来的内容都是字符串对象
  • Java语言提供对字符串串联符号("+"),即Java重载了+的功能。
  • Java语言提供了将任意类型对象转换为字符串的特殊支持(toString()方法)。

字符串的特点

1、字符串String类型本身是final声明的,意味着我们不能继承String。

2、String对象内部是用字符数组进行保存的

​ char[] value; 默认的长度 16
​ 扩容方式同 int newCapacity = (value.length << 1) + 2;

(1)JDK8的String内部是用字符数组进行保存的

private final char[] value;

"abc" 等效于 char[] data={ 'a' , 'b' , 'c' }

例如: 
String str = "abc";

相当于: 
char data[] = {'a', 'b', 'c'};     
String str = new String(data);
// String底层是靠字符数组实现的。

(2)JDK9之后String内部是用byte数组进行保存的

private final byte[] value;
private final byte coder;//新增加的字段,表示字符串采用的编码 1是UTF-16,0是LATIN1

定义的字符串中,如果没有汉字,每个字符将采用LATIN1编码表存储,如果字符串中包含汉字等非ASCII码表的字符,存储的编码就是UTF-16,相比JDK1.8节约内存

3、final class String 不能有子类

4、实现了Comparable接口 字符串对象是可以进行比较的

5、字符串数据存在字符串常量池内。。。如果存在相同的数据只会开辟一块空间

字符串的对象也是不可变对象,意味着一旦进行修改(不是重新赋值),就会产生新对象。

    @Test
    public void test01(){
        // 创建一个字符串对象
        String originalString = "Hello";
        System.out.println("Original String: " + originalString);

        // 修改字符串,实际上是创建了一个新的字符串对象
        String newString = originalString.concat(" World");
        System.out.println("New String after concatenation: " + newString);

        // 查看原始字符串是否改变
        System.out.println("Original String after modification: " + originalString);
    }

构造字符串对象

使用构造方法

  • public String() :初始化新创建的 String对象,以使其表示空字符序列。
  • String(String original): 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
  • public String(char[] value) :通过当前参数中的字符数组来构造新的String。
  • public String(char[] value,int offset, int count) :通过字符数组的一部分来构造新的String。
  • public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。
  • public String(byte[] bytes,String charsetName) :通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
//字符串常量对象,推荐
String str = "hello";

// 无参构造,不推荐
String str1 = new String();

//创建"hello"字符串常量的副本,不推荐
String str2 = new String("hello");

//通过字符数组构造
char chars[] = {'a', 'b', 'c','d','e'};     
String str3 = new String(chars);
String str4 = new String(chars,0,3);

// 通过字节数组构造
byte bytes[] = {97, 98, 99 };     
String str5 = new String(bytes);
String str6 = new String(bytes,"GBK");

使用"+"

任意数据类型与"字符串"进行拼接,结果都是字符串

	public static void main(String[] args) {
		int num = 123456;
		String s = num + "";
		System.out.println(s);
		
		Student stu = new Student();
		String s2 = stu + "";//自动调用对象的toString(),然后与""进行拼接
		System.out.println(s2);
	}

 	字符串常量+字符串常量:  字符串常量

    字符串变量+字符串变量:
    字符串常量+字符串变量:  new StringBuilder()
    字符串变量+字符串常量:

使用字面量的方式

str1 = 'Hello, World!'  
str2 = "Hello, World!"  
str3 = '''This is a  

可以使用方法

words = ['Hello', 'World']  
combined_str = ' '.join(words)  # 'Hello World'  

字符串的常用方法

基础操作

(1)boolean isEmpty():字符串是否为空

(2)int length():返回字符串的长度

(3)String concat(xx):拼接,等价于+

(4)boolean equals(Object obj):比较字符串是否相等,区分大小写

(5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写

(6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小

(7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写

(8)String toLowerCase():将字符串中大写字母转为小写

(9)String toUpperCase():将字符串中小写字母转为大写

(10)String trim():去掉字符串前后空白符

查找

(11)boolean contains(xx):是否包含xx

(12)int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1

(13)int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1

@Test
	public void test01(){
		String str = "尚硅谷是一家靠谱的培训机构,尚硅谷可以说是IT培训的小清华,JavaEE是尚硅谷的当家学科,尚硅谷的大数据培训是行业独角兽。尚硅谷的前端和UI专业一样独领风骚。";
		System.out.println("是否包含清华:" + str.contains("清华")); //true
		System.out.println("培训出现的第一次下标:" + str.indexOf("培训"));  //9
		System.out.println("培训出现的最后一次下标:" + str.lastIndexOf("培训"));
}

字符串截取

(14)String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。

(15)String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

@Test
	public void test01(){
		String str = "helloworldjavaatguigu";
		String sub1 = str.substring(5);
		String sub2 = str.substring(5,10);
		System.out.println(sub1);
		System.out.println(sub2);
	}

@Test
	public void test02(){
		String fileName = "快速学习Java的秘诀.dat";
		//截取文件名
		System.out.println("文件名:" + fileName.substring(0,fileName.lastIndexOf(".")));
		//截取后缀名
		System.out.println("后缀名:" + fileName.substring(fileName.lastIndexOf(".")));
	}

和字符相关

(16)char charAt(index):返回[index]位置的字符

(17)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回

(18)String(char[] value):返回指定数组中表示该字符序列的 String。

(19)String(char[] value, int offset, int count):返回指定数组中表示该字符序列的 String。

(20)static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String

(21)static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String

(22)static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String

(23)static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String

@Test
	public void test01(){
		//将字符串中的字符按照大小顺序排列
		String str = "helloworldjavaatguigu";
		char[] array = str.toCharArray();
		Arrays.sort(array);
		str = new String(array);
		System.out.println(str);
	}
	
	@Test
	public void test02(){
		//将首字母转为大写
		String str = "jack";
		str = Character.toUpperCase(str.charAt(0))+str.substring(1);
		System.out.println(str);
	}

编码与解码

(24)byte[] getBytes():编码,把字符串变为字节数组,按照平台默认的字符编码进行编码

​ byte[] getBytes(字符编码方式):按照指定的编码方式进行编码

(25)new String(byte[] ) 或 new String(byte[], int, int):解码,按照平台默认的字符编码进行解码

​ new String(byte[],字符编码方式 ) 或 new String(byte[], int, int,字符编码方式):解码,按照指定的编码方式进行解码

@Test
	public void test01(){
		//将字符串中的字符按照大小顺序排列
		String str = "helloworldjavaatguigu";
		char[] array = str.toCharArray();
		Arrays.sort(array);
		str = new String(array);
		System.out.println(str);
	}
	
	@Test
	public void test02(){
		//将首字母转为大写
		String str = "jack";
		str = Character.toUpperCase(str.charAt(0))+str.substring(1);
		System.out.println(str);
	}

开头与结尾

(26)boolean startsWith(xx):是否以xx开头

(27)boolean endsWith(xx):是否以xx结尾

	@Test
	public void test2(){
		String name = "张三";
		System.out.println(name.startsWith("张"));
	}
	
	@Test
	public void test(){
		String file = "Hello.txt";
		if(file.endsWith(".java")){
			System.out.println("Java源文件");
		}else if(file.endsWith(".class")){
			System.out.println("Java字节码文件");
		}else{
			System.out.println("其他文件");
		}
	}

替换

(29)String replace(xx,xx):不支持正则

(30)String replaceFirst(正则,value):替换第一个匹配部分

(31)String repalceAll(正则, value):替换所有匹配部分

	@Test
	public void test4(){
		String str = "hello244world.java;887";
		//把其中的非字母去掉
		str = str.replaceAll("[\\d]", "");
		System.out.println(str);
	}

拆分(分割)

(32)String[] split(正则):按照某种规则进行拆分

	@Test
	public void test4(){
		String str = "张三.23|李四.24|王五.25";
		//|在正则中是有特殊意义,我这里要把它当做普通的|
		String[] all = str.split("\\|");
		
		//转成一个一个学生对象
		Student[] students = new Student[all.length];
		for (int i = 0; i < students.length; i++) {
			//.在正则中是特殊意义,我这里想要表示普通的.
			String[] strings = all[i].split("\\.");//张三,  23
			String name = strings[0];
			int age = Integer.parseInt(strings[1]);
			students[i] = new Student(name,age);
		}
		
		for (int i = 0; i < students.length; i++) {
			System.out.println(students[i]);
		}
		
	}
	
	@Test
	public void test3(){
		String str = "1Hello2World3java4atguigu5";
		str = str.replaceAll("^\\d|\\d$", "");
		String[] all = str.split("\\d");
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
	}
	
	@Test
	public void test2(){
		String str = "1Hello2World3java4atguigu";
		str = str.replaceFirst("\\d", "");
		System.out.println(str);
		String[] all = str.split("\\d");
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
	}
	
	
	@Test
	public void test1(){
		String str = "Hello World java atguigu";
		String[] all = str.split(" ");
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
	}

字符串常量池

字符串常量对象可以共享的原因和好处

字符串常量对象可以共享的原因:字符串对象不可变

字符串常量对象共享的好处:节省内存

String s1 = "atguigu";
String s2 = "atguigu";
System.out.println(s1 == s2);//这里只创建了一个字符串对象"atguigu"。

s2 = s2.replace("a","o");
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);

这里s1指向的"atguigu"和s2指向的"atguigu"是同一个。
如果无法保证"atguigu"对象不可变,那么当s2将"a"替换为"o"之后,那么s1就会受到影响,这样是不安全的。
但是,现在我们发现s1并未受到影响,也就是说,s1指向的"atguigu"对象并未被修改,而是基于"atguigu"重新复制了一个新对象"atguigu",然后替换成"otguigu"。

hashCode方法

Object类有一个int hashCode()方法,该方法用于计算对象的哈希值。哈希值的作用就好比生活中的身份证号,用一串数字代表一个对象。哈希值的计算是有讲究的,按照常规协定hashCode方法和equals方法要一起重写,要求两个“相等”的对象hashCode必须相同,如果两个对象的哈希值不同,它俩调用equals方法也必须是false,但是如果两个对象的哈希值相同,它俩调用equals方法却不一定true。

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
在计算哈希码时选择31作为乘数,主要是基于以下几个原因:
1. 质数特性
减少哈希冲突:31是一个质数(素数),在哈希计算中选择质数作为乘数可以减少哈希冲突的可能性。质数在乘法运算中产生的结果更分散,使得不同的输入值更有可能产生不同的哈希码,从而减少相同值产生相同哈希码的概率。
2. 合适的范围
避免溢出和过小范围:如果选择一个较小的质数(如2),那么得出的乘积会在一个很小的范围,很容易造成哈希值的冲突。而如果选择一个100以上的质数,得出的哈希值可能会超出int的最大范围(在Java等语言中),导致溢出。31作为一个“不大不小”的质数,能够较好地平衡这两个问题。
3. JVM优化
位运算优化:JVM里最有效的计算方式就是进行位运算。31乘以一个整数i可以优化为(i << 5) - i,即先将i左移5位(相当于乘以32),然后再减去i本身。这种优化减少了乘法运算,提高了计算效率。
4. 实验验证
低冲突率:通过大量实验验证,使用31作为乘数,在处理大量数据时(如超过50,000个英文单词),哈希值的冲突数相对较低。这进一步证明了31作为乘数的有效性。

字符串常量池

字符串常量池是一个哈希表,它里面记录了可以共享使用的字符串常量对象的地址。采用哈希表结构的目的是为了提高性能,用空间换时间。字符串对象的地址散列存储在哈希表中,虽然是散列存储,但是因为可以使用字符串对象的hashCode值快速的计算存储位置的下标,所以效率还是很高的。

image-20240718113615995

String s1 = "hello";
String s2 = "hello";

当给s1赋值"hello"时,根据"hello"的hashCode()值,计算出来index=[2],如果table[2]=null,那就把"hello"对象的字符串的地址0x7534放到table[2]中。
    
当给s2赋值"hello"时,根据"hello"的hashCode()值,计算出来index=[2],此时table[2]!=null,那就直接把"hello"的内存地址0x7534赋值给s2。
    
String s3 = "Aa";
String s4 = "BB";
当给s3赋值"Aa"时,根据"Aa"的hashCode()值,计算出来index=[6],如果table[6]=null,那就把"Aa"对象的字符串的地址0x8989放到table[6]中。
    
当给s4赋值"BB"时,根据"BB"的hashCode()值,计算出来index=[6],此时table[index]=table[6]!=null,但是"BB"和"Aa"不一样,那就直接把"BB"的内存地址0x6666也放到table[6]中,相当于table[6]中记录了两个字符串对象的地址,它们使用链表连接起来。    

不同方法创建字符串的存储位置

直接赋值字符串:存储到字符串常量池中

//s指向常量池中的引用
String s ="lizhi";  //只会存储到字符串常量池中
//创建字符串时jvm会判断字符串常量池中是否有“该字符串”如果有直接返回对象的引用。否则会创建一个新的字符串常量

image-20240801100828288

使用new 关键字的字符串

//str指向内存中的对象引用
String str =new String("lizhi");
/*
通过new关键字创建的字符串引用,字符串常量池和堆内存都会有这个对象,没有就创建,最后返回的是堆内存中的对象引用(堆中地址)。
因为有1izhi这个字面量,先去检查《字符串常量池中》是否存在该字符串
如果不存在,就直接先在字符串常量池中创建一个字符串对象,然后再去堆内存中创建一个字符串对象1izi;
如果存在,就直接去堆内存创建一个字符串对象(在堆中开辟空间),内容为1izhi(指向常量池中对象);
最后将堆内存的字符串引用返回(堆中地址)。
*/

//<<这种方式会存在两个对象>>

image-20240801100718454

使用"+"连接字符串

//s指向常量池中的引用
String s="a"+"b"+"c"; //"abc"

字符串常量+字符串常量:  字符串常量
    
字符串变量+字符串变量:
字符串常量+字符串变量:  new StringBuilder()
字符串变量+字符串常量:

字符串的intern()方法:

  • 当调用 intern 方法时,首先会在字符串常量池中判断是否有该对象引用,如果有直接** **
  • 否则,将此 String 对象添加到字符串常量池中,并返回此 String 对象的引用
  • 注意:添加到字符串常量池中,是指把堆中对象的引用添加到常量池中。
String s1 = new String("lizhi");   
s1.intern();
String s3 = "s";
System.out.println(s3 == s1); //false

image-20240801100944322

String s1 = new String("li");   
String s2 = s1 +"zhi"
String s3 = s2.intern();
System.out.println(s2 == s3); //true

image-20240801102635985

String s1 = "s".intern(); //首先将s添加到字符串常量池中,并返回引用
String s="s";
System.out.println(s==s1);  //true 

String s1 = new String("s")+new String("b"); //
s1.intern();
String s3 = "sb";
System.out.println(s3==s1); //true 

public class TestStringIntern {
    @Test
    public void test1(){
        String s1 = new String("hello");
        String s2 = s1.intern();
        System.out.println(s1 == s2);
        /*
        JDK8:false
         */
    }

    @Test
    public void test2(){
        String s1 = "he".concat("llo");
        String s2 = s1.intern();
        System.out.println(s1 == s2);
        /*
        JDK8:true
         */
    }
}

哪些字符串对象地址放入字符串常量池?

需要共享的字符串地址记录到字符串常量池的table表中

需要共享的字符串地址记录到字符串常量池的table表中,不需要共享的字符串对象其地址值不需要记录到字符串常量池的table表中。除了以下2种,其他的都不放入字符串常量池:
(1)""直接的字符串 (备注:两个""的字符串直接+,编译器处理成一个""字符串)
(2)字符串对象.intern()结果
 
其他:
(1)直接new
(2)valueOf,copyValueOf等
(3)字符串对象拼接:concat拼接 以及 字符串变量 + 拼接
(4)toUpperCase,toLowerCase,substring,repalce等各种String方法得到的字符串
这些方式,本质都是新new的。

字符串对象和字符串常量池在哪里?

字符串常量池表:

  • JDK1.6:在方法区的永久代
  • JDK1.7之后:

字符串对象:

  • JDK1.7之前:需要共享的字符串对象存储在方法区的永久代,然后把对象地址记录到字符串常量池的table表中,不需要共享的字符串对象存储在堆中,其地址值不需要记录到字符串常量池的table表中。
  • JDK1.7之后:所有字符串对象都存储在堆中。同样需要共享的字符串地址记录到字符串常量池的table表中,不需要共享的字符串对象其地址值不需要记录到字符串常量池的table表中。

StringBuilder&StringBuffer

因为String对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低。因此,JDK又在java.lang包提供了可变字符序列StringBuilder和StringBuffer类型。

StringBuilder,StringBuffer区别

StringBuffer:老的,线程安全的(因为它的方法有synchronized修饰),效率低

StringBuilder:线程不安全的,效率高

相同点: 可变的字符串对象 char[] value; 默认的长度 16

扩容方式同 int newCapacity = (value.length << 1) + 2;

常用API

常用的API,StringBuilder、StringBuffer的API是完全一致的

(1)StringBuffer append(xx):拼接,追加

(2)StringBuffer insert(int index, xx):在[index]位置插入xx

(3)StringBuffer delete(int start, int end):删除[start,end)之间字符

​ StringBuffer deleteCharAt(int index):删除[index]位置字符

(4)void setCharAt(int index, 值):替换[index]位置字符值;

(5)StringBuffer reverse():反转

(6)void setLength(int newLength) :设置当前字符序列长度为newLength

(7)StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str

(8)int indexOf(String str):在当前字符序列中查询str的第一次出现下标

​ int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标

​ int lastIndexOf(String str):在当前字符序列中查询str的最后一次出现下标

​ int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标

(9)String substring(int start):截取当前字符序列[start,最后]

(10)String substring(int start, int end):截取当前字符序列[start,end)

(11)String toString():返回此序列中数据的字符串表示形式

String 和 StringBuffer的区别

​ 1.可变与不可变
​ String
​ StringBuffer
​ 2.内存区域
​ String 堆中 堆中的常量池
​ StringBffer 堆中
​ 3.拼接效率
​ String 低
​ StringBuffer 高

标签:String,int,println,str,字符串,常量
From: https://www.cnblogs.com/21CHS/p/18365562

相关文章

  • java String 去掉特殊字符之前的内容
    哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者......
  • 题解:AT_arc181_b [ARC181B] Annoying String Problem
    思路首先我们可以根据两个字符串算出另外一个字符串\(T\)的长度。算出来之后,因为我们要满足等式两边完全相等,所以很容易得出这两个字符串应该都是由一些公共的字串拼接而成的。设\(S\)串中最小的周期为\(P\)。所以应该满足\(|P|\Large{\mid}\normalsize\gcd(|S|,|T|)\)......
  • Java String 去掉特殊字符之前的内容方法
    为了去除字符串中某个特殊字符之前(包括该特殊字符本身)的所有内容,我们可以使用Java中的String类的substring和indexOf方法。这里,我将给出一个完整的代码示例,该示例会找到字符串中第一次出现的特定特殊字符(例如#),并删除该字符及其之前的所有内容。1.使用Java中的String类的substring......
  • Balanced String
    这道题目真的不知道怎么总结了,这技巧太新了见这篇题解为什么最开始要引入这个子问题呢?实际上,我们假设我们已经得到了最终的交换后的答案,设为\(t\),\(s\)就是题目给的原串,从\(s\)到\(t\)的最小交换次数当然就是从\(t\)到\(s\)的最小交换次数,于是考虑从\(t\)到\(s\)的最小交换次数,......
  • JDK源码——String相关
    StringJDK源码中的String类是Java中最常用的类之一,它提供了许多用于处理字符串的方法。以下是一些常用的String类方法:构造方法:String():创建一个空字符串。String(char[]value):根据字符数组创建一个新的字符串。String(byte[]bytes,intoffset,intlength):根据字节数......
  • C++ string类型常用操作
    string类型操作字符串切割str.substr(索引,切割的个数) -> 返回字符串注意:第二个参数为切割的个数stringbuf="abcdefg";buf.substr(0,2);//结果为"ab"buf.substr(1,3);//结果为"bcd"字符串输入使用getline读入字符串可以保留字符串中的空格 getline(cin......
  • SOMEIP_ETS_042: echoUTF16DYNAMIC_length_too_short_for_String
    测试目的:验证设备(DUT)能否正确拒绝一个长度小于实际字符串长度的echoUTF16DYNAMIC字符串。描述本测试用例旨在检查当发送的SOME/IP消息中的echoUTF16DYNAMIC字符串长度小于实际字符串长度时,DUT是否能够返回格式错误(MALFORMED_MESSAGE)的错误消息。测试拓扑:具体步骤:TEST......
  • TypeError: add_code_sample_docstrings() got an unexpected keyword argument ‘tok
    可能是transformers的版本太高,可以考虑降版本。更推荐的解决方案:processor_class替换tokenizer_class注意:需要CTRLShiftF tokenizer_class,全部替换掉。参考链接:ALBEF(AlignbeforeFuse:VisionandLanguageRepresentationLearningwithMomentumDistillati)算法阅......
  • Python编程中不可忽视的docstring使用详解
    概要在Python编程中,代码的可读性和可维护性至关重要。除了清晰的命名和结构良好的代码外,良好的文档字符串(docstring)也是确保代码易于理解和使用的关键工具。docstring是Python中用于记录模块、类、方法和函数行为的字符串,帮助开发者和用户快速了解代码的功能和用法。本文将......
  • Spark MLlib 特征工程系列—特征转换StringIndexer和IndexToString
    SparkMLlib特征工程系列—特征转换StringIndexer和IndexToStringStringIndexer是SparkMLlib中的一个特征转换器,用于将类别型(即字符串)特征转换为数值型索引。这个转换器对于处理包含类别型数据的机器学习任务非常有用,因为大多数机器学习算法要求输入的特征是数值型的......