首页 > 编程语言 >#Java-对象补充及字符串详讲

#Java-对象补充及字符串详讲

时间:2024-11-04 22:50:52浏览次数:5  
标签:详讲 Java String 对象 System println 字符串 out

0.类和对象深入解释

在Java中,类(Class)和对象(Object 是两个核心概念,它们共同构成了面向对象编程(OOP)的基础。

类(Class)

  • 定义:类是一个模板或蓝图,它描述了具有相同属性和行为的一组对象的共同特征。在Java中,类通过关键字class来定义。

  • 组成:类通常由成员变量(也称为属性或字段)和方法(也称为函数或行为)组成。成员变量表示对象的状态,而方法则定义了对象的行为。

  • 特性:类具有封装性,可以将数据和操作数据的方法结合在一起,形成一个不可分割的单位。此外,类还支持继承和多态等面向对象特性。


对象(Object)

  • 定义:对象是类的实例化,是类的具体表示。每个对象都是类的一个实例,它拥有类定义的属性和方法。

  • 创建:在Java中,对象是通过使用new关键字和类的构造函数来创建的。例如,MyClass obj = new MyClass();这行代码创建了一个MyClass类的对象obj。

  • 状态和行为:对象的状态由它的成员变量(属性)表示,而对象的行为则由它的方法定义。通过调用对象的方法,可以改变对象的状态或执行某些操作。

  • 唯一性:每个对象在内存中都有一个唯一的地址,这使得每个对象都是独一无二的。即使两个对象属于同一个类,它们的状态也可能不同。

关系:

  • 类是对象的模板:类是创建对象的蓝图或原型。通过定义类,我们指定了对象将拥有的属性和方法。
  • 对象是类的实例:对象是类的具体实现。当我们创建一个对象时,我们实际上是在创建一个类的实例,该实例将拥有类定义的属性和方法。

示例:

// 定义一个类
class Person {
    // 成员变量(属性)
    String name;
    int age;
    // 方法(行为)
    void speak() {
        System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建对象
        Person person1 = new Person();
        Person person2 = new Person();
        // 设置对象的状态
        person1.name = "Alice";
        person1.age = 30;
        person2.name = "Bob";
        person2.age = 25;
        // 调用对象的方法
        person1.speak(); // 输出: Hello, my name is Alice and I am 30 years old.
        person2.speak(); // 输出: Hello, my name is Bob and I am 25 years old.
    }
}

在这个示例中,Person是一个类,它有两个属性(name和age)和一个方法(speak)。Main类中的main方法创建了两个Person类的对象(person1和person2),并设置了它们的状态,然后调用了它们的方法。

1.成员变量和局部变量的区别

局部变量:在方法中的变量
成员变量:类中方法外的变量
例:

public class student {
	String name;//成员变量
	public void learn {
		int i = 0;//局部变量
		System.out.println(i);
	}
}

区别:
在这里插入图片描述

2. System.out.printf( )的使用

我们在前面经常使用System.out.println(),自带换行,并且可进行字符串之间,字符串和变量的连接。
下面我们介绍剩下的两种:

  1. System.out.print()
  2. System.out.printf()
  • System.out.print()
    不进行换行,其他功能和System.out.println()一样
  • System.out.printf()
    用于对内容的格式化输出:
    //整型
    int num = 100;
    System.out.printf("%d",num);
    //字符串
    String name = "lshh";
    System.out.printf("%s",name);
    //字符型
    char ch = 'a';
    System.out.prinf("%c",ch);
    
    首先用%s/d/f/c...进行占位,在“”后用英文逗号隔开,跟上实际的变量
    prinf也支持多个变量,以及字符和变量混合
    //多个变量根据类型写上占位符,在后边用逗号跟上变量即可
    System.out.printf("%d %s %c", a, b, c);
    //和字符一起
    System.out.printf("在%s我的年龄是:%d", year, age);
    
    // 使用 %x 格式化整数为十六进制
    int hexValue = 255;
     System.out.printf("The integer value in hexadecimal is: %x%n", hexValue);
    
     // 使用 %o 格式化整数为八进制
     int octalValue = 255;
     System.out.printf("The integer value in octal is: %o%n", octalValue);
    
     // 使用 %e 格式化浮点数为科学计数法
     System.out.printf("The double value in scientific notation is: %e%n", doubleValue);
    
     // 使用 %% 输出百分号字符
     System.out.printf("This is a percent sign: %%%n");
    

常用的格式说明符:

符号功能
%s用于字符串
%d用于整型
%c用于字符型
%f用于浮点型
%t用于时间/日期的格式化
%x格式化整数为十六进制
%o格式化整数为八进制
%e格式化浮点数为科学计数法
%%输出百分号字符

需要我们注意的是:System.out.printf()不会进行自动换行
如果需要换行,可以使用如下符号:

  • \n
  • %n(无关平台,在不同的平台上自动转化为合适的换行符)
System.out.printf("-我想和你在一起\n");
System.out.printf("-我...%n我也喜欢你\n");

输入结果为:
在这里插入图片描述


printf还有一个重要的功能:控制输出精度
我们以浮点型为例:%m.nf

  • m :控制输出的宽度,超出在最左边补空格(小数点也算一位)
  • n:控制小数的位数,四舍五入
 // 使用 %f 格式化浮点数(默认保留6位小数)
 double doubleValue = 3.141592653589793;
 System.out.printf("The double value is: %f%n", doubleValue);

 // 使用 %5.2f 格式化浮点数(宽度为5,保留2位小数)
 System.out.printf("The double value rounded to 2 decimal places is: %.2f%n", doubleValue);

3.String类

我们学过对象之后,就可以很好的理解String被成为引用类型了

  • 因为String是Java定义好的一个类,定义在java.lang包中,是Java的核心包,所以在使用的时候不需要导包;

  • Java程序中所有的字符串文字(例如:“abcdef”),都被成为此类的对象。

  • 字符串的内容是不会发生改变的,它的对象在创建之后不可以再修改

      例如:
      String name = "lshhh";
      name = "lsh";
    

    实际上是创建了两个字符串,把后一个字符串的地址赋值给了name,前一个的字符串内容没有被改变


4.字符串的创建方法

  1. 直接赋值:

    String name = "lshh";
    
  2. 使用new关键字调用类的构造方法

    构造方法说明
    public String()创建空白字符串,不含任何内容
    public String(String original)根据传入的字符串,创建字符串对象
    public String(char[] chs)根据字符数组,创建字符串对象
    public String(byte[] chs)根据字节数组,创建字符串对象

    示例:

    //2.使用new的方式来获取一个字符串对象
    //空参构造:可以获取一个空白的字符串对象
    String s2 = new String();
    System.out.println("@" + s2 +"!");//s2是一个空的字符串""
    
    //传递一个字符串,根据传递的字符串内容再创建一个新的字符串对象
    String s3 = new String( original: "abc");//一般不适用,冗余
    System.out.println(s3);
    
    //传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
    //需求:我要修改字符串的内容。
    //abc -- > {'a', 'b', 'c'} -- > {'Q','b', 'c' } -- > "'Qbc"
    char[] chs = {'a', 'b', 'c', 'd'};
    String s4 = new String(chs);
    System.out.println(s4);//abcd
    
    //传递一个字节数组,根据字节数组的内容再创建一个新的字符串对象
    byte[] bytes = {97, 98, 99, 100};//根据ASSIC码输出对应的字符
    String s5 = new String(bytes);
    System.out.println(s5);//abcd
    

5.字符串两种创建方式的区别

我们再来看内存模型:
在这里插入图片描述
除此之外:存储直接赋值的字符串的地方叫串池(StringTable)

  • 串池从JDK7开始从方法区挪到了堆内存
  • 串池全名:字符串常量池
  1. 直接赋值
    在这里插入图片描述

    示例来自黑马程序员

    我们可以看到,在串池中,当存在''abc''的时候,就直接把地址又给了s2,这种操作称之为:复用
    总的来说:用双引号直接赋值的时候,系统会检查该字符串在串池中是否存在:

    • 不存在:创建新的
    • 存在:复用
  2. new 调用构造方法
    在这里插入图片描述
    可以看到,在堆内存中创建空间,同时每个字符串的地址都是不重复的

    这和我们前面说的对象的唯一性是符合的:

    • 唯一性:每个对象在内存中都有一个唯一的地址,这使得每个对象都是独一无二的。即使两个对象属于同一个类,它们的状态也可能不同。

这时我们可能产生疑问:直接赋值的字符串对象当使用复用的时候,地址是一样的呀,这还符合对象的唯一性吗?

这并不意味着字符串对象失去了唯一性,对象是字符串(例如:“abcdef”),它在内存中的地址是唯一的,但是这个地址可以被多个变量所引用。


6.字符串常用方法

6.1equals比较字符串

示例:

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

String s3 = new String("abc");
System.out.println("abc");
System.out.println(s1 == s3);//false

为什么同样的字符串,比较的结果却不同:

==比较的到底是什么?

  • 对于基本数据类型

      int a = 10;
      int b = 20;
      System.out.println(a == b);//false
    

    基本数据类型比较的是数据值

  • 引用数据类型

      String s1 = new String("abc");
      String s2 = new String("abc");
      System.out.println(s1 == s2);//false
    

    引用数据类型比较的是地址值

现在我们对前面的代码进行解释:

  1. 第一个
    String s1 = "abc";
    String s2 = "abc";
    System.out.println(s1 == s2);//true
    
    字符串字面量存储在字符串常量池中,会使用复用,地址一样
  2. 第二个
    String s3 = new String("abc");
    System.out.println("abc");
    System.out.println(s1 == s3);//false
    
    new关键字创建的对象是在堆内存中的,在堆中,不论字符串是不是已经存在,都会重新创建一个新的字符串,并分配内存。所以地址一定是不一样的

字符串内容比较:

  • boolean equals():完全一样为true
  • boolean equalslgnoreCase:不区分大小写(只适用于英文)

示例:

//1.创建两个字符串对象
String s1 = new String( original: "abc");
String s2 = "Abc";

//2 .== 号比较
//基本数据类型:比的是数据值
//引用数据类型:比的是地址值
System.out.println(s1 == s2);//false

//3.比较字符串对象中的内容是否相等
boolean result1 = s1.equals(s2);
System.out.println(result1);

//4.比较字符串对象中的内容是否相等,忽略大小写
//1一壹 这不行
//忽略大小写只能是英文状态下的a A
boolean result2 = s1.equalsIgnoreCase(s2);
System.out.println(result2);//true

使用Scanner键盘输入字符串比较:

//1.假设我现在键盘录入一个abc
Scanner sc = new Scanner(System. in);
System.out.println("请输入一个字符串”);
String str1 = sc.next();//abc
//2.代码中再定义一个字符串abc
String str2 = "abc";
//3.用 == 比较,这两者能一样吗?
System.out.println(str1 ==str2);//false

结果false,意味着Scanner键盘录入的abc,并不在字符串常量池中存储,是在堆中的;


6.2遍历字符串

  • public char charAt(int index):根据索引返回字符

  • public int length():返回此字符串的长度

  • 数组的长度:数组名.length

  • 字符串的长度:字符串对象.length()

1.public char charAt(int index)示例:

//1.键盘录入一个字符串
Scanner sc = new Scanner(System. in) ;
System.out.println("请输入一个字符串”);
String str = sc.next();
//2.进行遍历
for (int i = 0; i < str.length(); i++) {
	//i 依次表示字符串的每一个索引
	ghar c = str. charAt(i);
	System.out.println(c);
}

输出结果:
在这里插入图片描述

6.3 截取字符串

substring(int beginIndex, int endIndex):从beginIndex位置截取到endIndex位置;包头不包尾;

  • 包头不包尾:指的是截取的字符串包含beginIndex位置,但是不包含endIndex位置的字符
  • substring(int beginIndex):表示从beginIndex位置截取到字符串的末尾;
  • 它的返回值是String类型,返回的结果是截取的字符串,对原来的字符串不产生影响

示例:手机号屏蔽:

String phoneNumber = "13112349468";
//2.截取手机号码前面三位
String start = phoneNumber.substring(0, 3);
//3.截取手机号码后面四位
String end = phoneNumber.substring(7);
//4.拼接
String result = start + " **** " + end;
System.out.println(result);

6.4 字符串替换

replace(旧值,新值):返回值是String类型,返回的结果是一个新的字符串,对原有的字符串不产生影响
示例:敏感词替换:

String talk="你玩的真好,以后不要再玩了,TMD,CNM";
//2.定义一个敏感词库
String[] arr = {"TMD","CNM", "SB", "MLGB"};
//3.循环得到数组中的每一个敏感词,依次进行替换
for (int i = 0; i < arr.length; i++) {
	talk = talk.replace(arr[i],  " *** ");
}
//4.打印结果
System.out.println(talk):

6.5 StringBuilder类

我们在连接字符串的时候,基本的方法是使用+作连接符,但是在处理多个字符串连接的时候,这样效率偏低

String str = "abc";
for (int i = 0; i <= 10000; i++) {
	str += str;
}

运行效率是很低的;如何提高字符串的连接效率呢:
我们首先要知道字符串连接的逻辑:

//例如
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = "d";
String s = s1 + s2 + s3 + s4;

在运行的时候,我们说过字符串对象一旦创建就不能再修改;
所以步骤为:

  1. s1 + s2作为一个新的字符串再和剩下的字符串加下
  2. s1 + s2s3相加,又创建了一个新的字符串
  3. 这个新的字符串再加s4之后又创建一个新的字符串,把地址传给s

这样的步骤时间效率是很低的,并且浪费了大量的内存。

所以我们引入了StringBuilder
我们创建了StringBuilder类的对象后,这个对象就像一个缓存的中间容器,可以把字符串都暂时存储再这个容器中进行连接,而不会产生新的字符串。
在这里插入图片描述

a.StringBuider的构造方法

在对象的讲解中,我们知道,一个完整的对象是包含无参和有参的构造方法:
现在我们来看:

  • 无参:public StringBuider():创建一个空白可变字符串对象,不含有任何内容
  • 有参:public StringBuider(String str):根据传入的字符串的内容,创建一个可变的字符串
String str = "lshh";
StringBuider s = new StringBuider(str);
StringBuider c = new StringBuider();

值得注意的是:上面我们只是创建了StringBuilder类型的容器,并不是字符串

b.StringBuider成员方法
方法名说明
public StringBuilder append(任意类型)添加数据,并返回对象本身
public StringBuilder reverse()反转容器中的内容
public int length()返回长度(字符出现的个数)
public String toString()通过toString()就可以实现把StringBuilder转换为String

示例:

//1.创建对象
StringBuilder sb = new StringBuilder();
StringBuilder sa = new StringBuilder("abc");
//2.添加字符串(任意类型)
sb.append("aaa");
sb.append(1);
sb.append(2.3);
sb.append(true);
System.out.println(sb);//aaa12.3true
//3.反转
sa.reverse();
System.out.println(sa);//cba
//4.获取长度
System.out.println(sa.length());
//5..再把StringBuilder变回字符串
String str = sb.toString();
System.out.println(str);//就可以调用String的方法了

6.6 链式编程的理解

在我们上面的代码中使用了

s.append("aaa");
s.append(1);
s.append(2.3);
s.append(true);

去添加数据,但是这样写代码显得冗余,我们可以这样写:

s.append("aaa").append(1).append(2.3).append(true);

因为append()返回的类型依然是StringBuilder类型,所以我们可以直接使用s.append()调用StringBuilder的方法;

因为上面的代码是链形的,所以称之为链式编程

6.7 StringJoiner 类

StringJoiner概述

  • StringJoinerStringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。

  • 作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。因为它是JDK8出现的。

a.构造方法
方法名说明
public StringJoiner(间隔符号)创建一个StringJoiner对象,指定拼接时的间隔符号
public StringJoiner(间隔符号,开始符号,结束符号)创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号
StringJoiner s = new StringJoiner("---");
//1---2---3
StringJoiner s = new StringJoiner(",", "[","]");
//[1,2,3]
b.成员方法
方法名说明
public StringJoiner add(添加的内容)添加数据,并返回对象本身
public int length()返回长度(字符出现的个数)
public String toString()返回一个字符串(该字符串就是拼接之后的结果)
c.示例
//1.创建对象
StringJoiner sj = new StringJoiner( ", ", "[", "]");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");

int len = sj.length();
System.out.println(len);//15
//3.打印
System.out.println(sj);//[aaa, bbb, ccc]
//4.转换为字符串类型,方便调用String的方法
String str = sj.toString();
System.out.println(str);//[aaa, bbb, ccc]

7.字符串相关类的底层原理

7.1 字符串存储的内存原理

前面我们已经详细讲过,这里简略总结:

  • 直接赋值的字符串在字符串常量池中存储,会有复用
  • new出来的字符串对象,在堆中存储,每个字符串都会开辟空间分配地址

7.2 == 比较的是什么

  • 基本数据类型比较数据值
  • 引用数据类型比较地址值

7.3 字符串拼接的底层原理

a. 没有变量在"="右侧参与赋值
public class Test {
	public static void main(String[] args) {
		String s = "a" + "b" + "c";
		System.out.println(s);
	}
}//结果:"abc"

这是会触发字符串的优化机制,在.java文件编译为.class文件的时候就会自动连接起来"abc";实际上在串池中存储的就是"abc"

b. 有变量参与赋值
public class Test {
	public static void main(String[] args) {
		String s1 = "a";
		String s2 = s1 + "b";
		String s3 = s2 + "c";
		System.out.println(s3);
		}
}
  • String s1 = "a"在串池中存储"a"
  • String s2 = s1 + "b",在串池中存储“b”,调用StringBuilder类创建一个容器存储"ab",再使用ToString方法返回字符串类型,同时要创建一个String类的对象来接收字符串。(都是使用new创建,所以都在堆内存中)
  • String s3 = s2 + "c":重复上面的步骤

所以上面的代码在堆中创建了四个对象(两个StringBuilder,两个String),这是JDK8之前的版本的做法

在JDK8之后的版本中:

public class Test {
	public static void main(String[] args) {
		String s1 = "a";
		String s2 = "b";
		String s3 = "c";
		String s4 = s1 + s2 + s3;
		System.out.println(s3);
		}
}

采用的是预估长度的做法:

  • 首先预估字符串需要的长度,之后创建一个该长度的数组,把这些字符放在这个数组中,之后再返回字符串类型。
  • 但是当每行代码都是含有变量的赋值的时候,就会在每行进行预估,创建数组,返回字符串。时间和空间效率依然不是很高

所以为了提高效率,在进行字符串拼接的时候,推荐使用StringBuilder

7.4 StringBuider提高效率

简略说明:

  • 所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存
  • 容量:
    • 默认创建一个长度为16的字节数组
    • 添加的内容长度小于16,直接存储
    • 添加的内容大于16会扩容(原来的容量*2 + 2)
    • 如果扩容之后还不够,以实际长度为准

标签:详讲,Java,String,对象,System,println,字符串,out
From: https://blog.csdn.net/2302_80203877/article/details/143250537

相关文章

  • #Java-集合基础-ArrayList
    1.为什么使用集合集合是用来存储多个元素的,但是数组也同样可以实现多元素的存储为什么要用集合?数组的长度固定,当数组满之后无法再添加元素集合的长度跟随元素的数量自动变化,长度等于元素个数数组和集合还有存储数据类型方面的区别:数组可以存储基本数据类型和引用数据类......
  • java实现“数据平滑升级”
    @目录一、摘要二、前提场景说明:三、项目用到的脚本和代码1.项目目录长这样2.java代码、配置文件、部分脚本3.升级包中的部分文件一、摘要所谓的数据平滑升级:指的是比如旧的系统代码咱称之为V4.6版本,V4.6涉及的部分库表字段只有5个字段,而新版本V4.7部分表字段有10个字段,所谓的......
  • Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
    @目录一、业务背景二、实现思路二、准备工作1.准备data模板.xlsx2.引入poi相关依赖,用于操作excel3.针对WorkBook+ZIP压缩输入/输出流,相关方法知识点要有所了解三、完整的项目代码四、可能遇到的问题错误场景1:java.io.IOException:Streamclosed错误场景2:调用接口没有另存为弹窗,......
  • Java面试题中高级进阶(JVM篇)
    前言本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!什么是StopTheWorld?什么是OopMap?说一下JVM的主要组成部分及其作用?什么是指针碰撞?什么是空闲列表?什么是TLAB?似乎有点模糊了,那就大概看一下面试题吧。好记性不如烂键盘***12万字的java面试题整理***什么是StopT......
  • 计算机毕业设计java基于springboot的网上书店系统
    文章目录项目介绍技术介绍功能介绍核心代码数据库参考系统效果图项目介绍  本文致力于探讨基于SpringBoot框架的网上书店系统的全面设计与实现。随着网络技术的迅猛发展,网上书店作为一种便捷的购书方式受到了广泛关注。为了满足用户对于购书的需求,本文首先从用......
  • 2024/11/4日 日志 关于JavaScript 变量、数据类型、类型转换和流程控制语句的学习
    经过两天的休憩,状态更佳,后面的笔记和学习进度也会加快JavaScript变量、数据类型、类型转换和流程控制语句点击查看代码----变量--JavaScript中用var关键字(variable的缩写)来声明变量--vartest=20;--test="张三":--·JavaScript是一门弱类型语言变量可......
  • Java经典案例代码(持续更新中...)
        2024/11/4目录一、找素数①方法一②方法二二、打印九九乘法表三、打印三角形四、双色球系统一、找素数①方法一publicclassTest07{publicstaticvoidmain(String[]args){System.out.println(Find(101,200));}publicstat......
  • 初始JavaEE篇 —— 文件操作与IO
    找往期文章包括但不限于本期文章中不懂的知识点:个人主页:我要学编程程(ಥ_ಥ)-CSDN博客所属专栏:JavaEE目录文件介绍 Java标准库中提供操作文件的类文件系统操作File类的介绍File类的使用 文件内容操作二进制文件的读写操作文本文件的读写操作文件介绍 文件......
  • Java毕设项目案例实战II基于Java+Spring Boot+Mysql的果蔬作物疾病防治系统的设计与实
    目录一、前言二、技术介绍三、系统实现四、核心代码五、源码获取全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末一、前言随着现代农业的快速发展,果蔬作物的健康生长与高效管理......