1.面向对象的三大特点
封装、继承、多态
1.1封装
private (关键字) 是一个权限修饰符
可以修饰成员(成员变量和成员方法)
-
作用:保护成员不被别的类使用
针对private所修饰的成员变量,如果需要被其他的类使用,提供相应的额外的操作方法:
提供get变量名()用户获取成员变量(被private)的值,方法的修饰符时public
提供set变量名(参数)方法,用户设置成员变量的值 方法也必须使用public进行修饰
/*
类 所包含的应该是与其相关的成员
*/
public class Student {
//成员变量
String name;
private int age =18;// 在声明成员变量的时候 可以给其赋予一个默认值
public int getAge(){
return age;
}
public void setAge(int a){
if(a < 0 || a > 120){
System.out.println("您输入的年龄不合法");
}else{
age = a;
}
}
}
测试类
/*
类 所包含的应该是与其相关的成员
*/
public class Student {
//成员变量
String name;
private int age =18;// 在声明成员变量的时候 可以给其赋予一个默认值
public int getAge(){
return age;
}
public void setAge(int a){
if(a < 0 || a > 120){
System.out.println("您输入的年龄不合法");
}else{
age = a;
}
}
}
1.2this关键字
public void setName(String name ){
System.out.println(name);
this.name = name;//将局部变量的name赋值给成员变量的name 可以使用this
}
this修饰成员变量;
可以区分成员变量和局部变量:如果方法的形参和成员变量同名,不带this修饰的变量指的是形参,而this修饰的是成员变量
什么时候使用this?解决局部变量隐藏(屏蔽)成员变量
this的内存原理:
this代表当前调用方法的对象。哪个对象调用当前的方法,this就代表那个对象
this代表本类的当前对象
标准的java类的写法
标准的java类 也称为java bean
/*
类 所包含的应该是与其相关的成员
*/
public class Student {
//成员变量
private String name;
private int age =18;// 在声明成员变量的时候 可以给其赋予一个默认值
public String getName(){
return name;
}
public void setName(String name ){
this.name = name;//将局部变量的name赋值给成员变量的name 可以使用this
}
public int getAge(){
return age;
}
public void setAge(int age){
if(age < 0 || age > 120){
System.out.println("您输入的年龄不合法");
}else{
this.age = age;
}
}
}
1.3 封装思想
封装是面向对象的三大特征之一。
是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的。
封装原则:
将类的某些信息隐藏在类的内部,不允许外部程序直接访问。而是通过该类提供的方法来实现对隐藏信息的操作和访问。
成员变量使用private修饰 提供对象的getXxx()和setXxx()方法
封装的好处:
通过方法来控制成员变量的操作,提高代码的安全性
把代码用方法进行封装,可以提高代码的复用性。
1.4 java中封装的体现
1 对于成员变量的封装 使用private
2 类体现的也是对一类事物的属性和行为的封装
3 方法体现了封装的思想:就是将某一个功能封装在其中。
2.构造方法
构造方法也成为构造器(constructor),用于对象的初始化。构造方法是一个创建对象时被自动调用的特殊方法。目的就是对对象进行初始化。
构造方法的名称要与类名完全一致。构造方法没有返回值(void也不写)
Java通过new关键字来调用构造方法,从而返回该类的一个实例对象,是一种特殊的方法
public Student(){
// System.out.println("student的无参构造被调用...");
}
2.1构造方法的注意事项
public static void main(String[] args) {
String s1 = "aaaa";//直接赋值
String s2 = new String();//创建一个空字符串
char[] c = {'a','b','c'};
String s3 = new String(c);//字符数组
byte[] b = {97,98,99};
String s4 = new String(b);//字节数组
System.out.println("s1=" + s1);
System.out.println("s2=" + s2);
System.out.println("s3=" + s3);
System.out.println("s4=" + s4);
}
4.3 创建字符串对象的两种方式的区别
4.3.1.通过构造方法创建
使用new创建字符串对象,每一次new都会申请一个内存空间,虽然内容都是相同的,但是所对应的内存地址是不同的。
char[] c = {'a','b','c'};
String s3 = new String(c);//字符数组
String ss3 = new String(c);
上面的代码。jvm会首先创建一个字符数组,然后每一次new 的时候 都会有一个新的地址,只不过s3 和ss3参考的字符串的内容是相同的
4.3.2 直接赋值的方式创建
使用“”方式给出的字符串,只要字符序列相同(顺序和大小写)。无论在程序代码中出现几次,jvm都只会建立一个String对象,并在字符串常量池(String pool)中维护
java中的三种常量池:
字符串常量池 class文件常量池 运行时常量池
1 字符串常量池(又称为全局字符串池)。
jvm所使用的内存中,字符串作为一种特殊的数据类型,占据了大量的内存,且字符串有着大量的重复,由于字符串本身具有不可变性,因此使用字符串常量池对于同样的字符串可以起到一个缓存的作用,防止多次内存分配,从而提供内存的利用率
2 运行时常量池
当程序运行到某个类的时候,class文件中的信息就会被解析到内存的方法区的运行时常量池中,每个类都有一个运行时常量池。
3 class文件常量池
class常量池是在编译后每个class文件都有的,class文件中除了包含类的版本 字段 方法 接口等描述信息,还有一项信息就是常量池,用于存放编译器生成的各种字面量和符号的引用。
5 JVM内存模型
jvm从大的方面分为:堆区 栈区 方法区
栈区: 细分为java虚拟机栈 和本地方法栈
堆内存可以划分为 新生代 老年代
新生代: Eden区 from区 to区
划分出来的各个区域 分别保存不同的数据 并且在一般情况下 期采取的内存回收策略也是不同。
5.1. 堆内存
堆内存是jvm内存模型中最大的一块区域,被所有线程共享。是在jvm启动的时候进行创建。几乎所有的对象的空间分配都是在堆区来进行分配。
考虑到jvm的内存回收机制,堆内存划分为新生代和老年代两个区域(默认的新生代和老年代的空间大小比例为1:2).新生代可以在划分为Eden区,From 区(s0) to区(s1),三者的比例(8:1:1) 几乎所有的新对象的创建都是在eden区 完成。在垃圾回收(GC)过程中,Eden区的活跃的对象会被迁移到Survior区,当在达到一定的年龄(经过一定的垃圾回收算法测处理),会被转移到老年代中。
堆内存在物理上可以使不连续,但是在逻辑上需要满足连续。在实现时。可以实现成固定大小的,也可以是可扩展的。
5.2.方法区
方法区又被称为永久代,我们所讲的模型是(Hotsport最常见的jvm的模型)。同样 也是被所有的线程所共享的,该区域主要保存类的信息,静态变量,常量和编译器编译后的代码等数据
jdk7中,将永久代中的字符串常量池移动到堆中。jdk8 撤销了永久代 ,引入了元空间
方法区不需要连续的内存,可以选择固定大小或者可扩展,并且还可以选择不实现垃圾回收,相对而言,垃圾收集行为在这个区域是比较少见的,但并非数据进入方法区就如永久代的名字一样永久存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,圾回收机制的条件是相当苛刻的。
这段程序,以指数级不断的生成新的字符串,这样可以比较快速的消耗内存。
可以通过异常信息看到出现堆内存的异常,在jdk1.8之后,字符串常量池由永久代(方法区)转移到堆中
jvm的内存参数的设置
6.字符串的比较
#
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);//true
// 使用字符数组构造一个字符串
char[] c = {'a','b','c'};
String s3 = new String(c);
String s4 = new String(c);
System.out.println(s3 == s4);//false
String s5 = new String("abc");
String s6 = new String ("abc");
System.out.println(s5==s6);// false
System.out.println(s1 == s3);//false
System.out.println(s4 == s5);//false
}
以上对于字符串的比较使用的是== 经过分析可以知道:==比较的是两个字符串对象的引用的地址是否相同。
比较字符串的内容相同:
如果要比较两个字符串的内容是否相同 则使用equals方法
System.out.println(s1.equals(s3));
System.out.println(s4.equals(s6));
System.out.println(s1.equals(s7));//false
System.out.println(s1.equals(s8));//false
System.out.println(s1.equalsIgnoreCase(s7));//true
System.out.println(s1.equalsIgnoreCase(s8));//true
需求:模拟完成用户登录
已知用户名和密码,请用程序来实现用户登录,总共有三次机会,登录之后要给出相应的提示。
import java.util.Scanner;
public class LoginTest {
public static void main(String[] args) {
// 假设用户名和密码是已知的 分别为
// String username = "lanqiao";
// String password = "123456";
//用户登录时 用户名和密码有用户从键盘输入 用户最多可尝试三次
for(int i = 0 ; i < 3 ;i++){
// 从键盘录入用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的用户名:");
String inName= sc.nextLine();
inName=null;
System.out.println("请输入您的密码:");
String inPassword = sc.nextLine();
inPassword=null;
//比较用户输入的用户名和密码是否与已知的用户名密码一致
// 当进行字符串和一个变量比较的时候 ,一定要将字符串常量放在equals的前边 这样可以有效的避免空指针异常的出现
if("lanqiao".equals(inName)&&"123456".equals(inPassword)){
System.out.println("登录成功");
break;
}else{
if(2 - i == 0){
System.out.println("您的账户已经被锁定,请联系管理员");
}else{
System.out.println("用户名或密码有误,登录失败,您还有"+(2-i)+"次机会!");
}
}
}
}
}
遍历字符串
从键盘录入一个字符串,使用程序实现在控制台遍历该字符串。
public static void main(String[] args) {
//从键盘输入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要遍历的字符串:");
String str = sc.nextLine();
// 获取数组的长度 使用数组的length属性 获取字符串的长度 使用的是String类的length方法
for(int i = 0 ; i < str.length();i++){
char c = str.charAt(i);
System.out.println(c);
}
}
统计字符的次数
键盘录入一个字符串,统计该字符串中大写字母 小写字母 数字出现的次数 (不考虑其他字符)
对于一个字符判断他是大写字母 小写字母 数字 直接判断:
大写字母: ch >= 'A' && ch<='Z'
小写字母:ch>='a'&& ch<='z'
数字:ch>='0'&&ch<='9'
public class CountCharNum {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要统计的字符串:");
String str = sc.nextLine();
// 定义字符统计的变量
int bigCount = 0;
int smallCount = 0 ;
int numberCount=0;
for(int i =0 ; i < str.length();i++){
char ch = str.charAt(i);
if(ch >='A'&& ch<='Z'){
bigCount++;
}else if(ch >='a'&& ch<='z'){
smallCount++;
}else if(ch >='0'&& ch<='9'){
numberCount++;
}
}
System.out.println("大写字母的个数为:" + bigCount);
System.out.println("小写字母的个数为:" + smallCount);
System.out.println("数字的个数为:" + numberCount);
}
}
字符串反转:
定义一个字符串,实现字符串的反转 从控制台输入abc 输出结果为cba
7 String类的常用方法
public static void main(String[] args) {
String str = "abdcdadcd";
System.out.println(str.indexOf("a"));//0
System.out.println(str.lastIndexOf("a"));//5
}
String s = String.valueOf(123);//将整数123 转换为字符串123
8 String的常见陷阱
String str1 = "abc";
String str2 = new String("abc");
字符串常量存储在字符串常量池中,并且是共享
字符串非常量对象 存储在堆中
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "hello" +"world";
String s4 = s1 +"world";
String s5 = s1 + s2;
String s6 = (s1 + s2).intern();
String s7 = "helloworld";
System.out.println(s3==s4);// false
System.out.println(s3 == s7);//true
System.out.println(s3==s5);//false
System.out.println(s4==s5);//false
System.out.println(s3==s6);//true
}
public static void main(String[] args) {
String str1 = new StringBuilder("计算机").append("软件开发").toString();
System.out.println(str1.intern()== str1);//true
String str2 = new StringBuilder("ja").append("va").toString();//java是一个特殊的字符串 在jdk的底层,存在很多“java”字符串
System.out.println(str2.intern()==str2);//false
}
面试题:
public static void main(String[] args) {
String str1 = new String("str") + new String("01");
str1.intern();
String str2 = "str01";
System.out.println(str1 == str2);//true
}
public static void main(String[] args) {
String s1 = new String("he") +new String("llo");
String s2 = new String("h") +new String("ello");
String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s1==s3);//true
System.out.println(s2 == s4);//false
System.out.println(s3 == s4);//true
}
-
构造方法
如果没有定义构造方法,系统将给出一个默认的无参构造方法
如果定义了构造方法,系统将不再提供默认的无参构造
-
构造方法的重载
如果自定义了带参的构造方法,还要使用无参构造,就必须手动写出无参构造
-
无论是否使用无参构造,在开发中,都推荐显示的将无参构造定义出来
-
重要功能:可以使用带参构造为成员变量进行初始化
public Student(){ // System.out.println("student的无参构造被调用..."); } public Student(String name){ this. name = name; } public Student(int age){ this.age =age; } public Student(String name , int age){ this.name = name; this.age = age; }
分别使用不同的构造方法来创建对象
可以使用this(参数列表)调用本类的其他构造方法。但是要注意一点:使用this调用本类其他构造方法 必须位于构造方法的第一条语句。因此也就是说对于构造方法的调用只能调用一次。
3 标准的java bean的写法
1 成员变量 使用private修饰
2 提供getter和seter方法 来访问成员变量
3 提供构造方法:
无参的 和带有多个参数的
public class Book { //成员变量 private String title; private double price; private String author; //构造方法 public Book(){ } public Book(String title,double price , String author){ this.title = title; this.price = price; this.author = author; } //getter 和 sertter public String getTitle(){ return title; } public void setTitle(String title){ this.title = title; } public double getPrice(){ return price; } public void setPrice(double price){ this.price = price; } public String getAuthor(){ return author; } public void setAuthor(String author){ this.author =author; } }
4.常用API-String
API- Application programming Interface 应用程序编程接口
java中的API:
指的就是jdk中提供的各种功能的java类,这些类底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可。
java.lang Class String
String类位于java.lang包下,凡是位于java.lang包下的类,在使用的时候,不需要导包。String类代表的是字符串。java中的所有的字符串都被实现为String类的实例。java程序中所有使用双引号引起来的字符串,都是String类的对象
4.1 String字符串的特点
1 字符串不可改变,他的值在创建之后就不能被更改
2 虽然String的值是不可变的,但是他们是可以被共享。
3 字符串效果上相当于字符数组(char[]),但是底层原理却是字节数组([byte[]])
4.2 String类的构造方法
-
String()
初始化新创建的String
对象,使其表示空字符序列。 -
String(char[] value)
分配一个新的String
,以便它表示当前包含在字符数组参数中的字符序列。 -
String(byte[] bytes)
通过使用平台的默认字符集解码指定的字节数组来构造新的String
。 -
String s = "abc" 直接复制的方式创建字符串abc
public static void main(String[] args) { String s1 = "aaaa";//直接赋值 String s2 = new String();//创建一个空字符串 char[] c = {'a','b','c'}; String s3 = new String(c);//字符数组 byte[] b = {97,98,99}; String s4 = new String(b);//字节数组 System.out.println("s1=" + s1); System.out.println("s2=" + s2); System.out.println("s3=" + s3); System.out.println("s4=" + s4); }
4.3 创建字符串对象的两种方式的区别
4.3.1.通过构造方法创建
使用new创建字符串对象,每一次new都会申请一个内存空间,虽然内容都是相同的,但是所对应的内存地址是不同的。
char[] c = {'a','b','c'}; String s3 = new String(c);//字符数组 String ss3 = new String(c);
上面的代码。jvm会首先创建一个字符数组,然后每一次new 的时候 都会有一个新的地址,只不过s3 和ss3参考的字符串的内容是相同的
4.3.2 直接赋值的方式创建
使用“”方式给出的字符串,只要字符序列相同(顺序和大小写)。无论在程序代码中出现几次,jvm都只会建立一个String对象,并在字符串常量池(String pool)中维护
java中的三种常量池:
字符串常量池 class文件常量池 运行时常量池
1 字符串常量池(又称为全局字符串池)。
jvm所使用的内存中,字符串作为一种特殊的数据类型,占据了大量的内存,且字符串有着大量的重复,由于字符串本身具有不可变性,因此使用字符串常量池对于同样的字符串可以起到一个缓存的作用,防止多次内存分配,从而提供内存的利用率
2 运行时常量池
当程序运行到某个类的时候,class文件中的信息就会被解析到内存的方法区的运行时常量池中,每个类都有一个运行时常量池。
3 class文件常量池
class常量池是在编译后每个class文件都有的,class文件中除了包含类的版本 字段 方法 接口等描述信息,还有一项信息就是常量池,用于存放编译器生成的各种字面量和符号的引用。
5 JVM内存模型
jvm从大的方面分为:堆区 栈区 方法区
栈区: 细分为java虚拟机栈 和本地方法栈
堆内存可以划分为 新生代 老年代
新生代: Eden区 from区 to区
划分出来的各个区域 分别保存不同的数据 并且在一般情况下 期采取的内存回收策略也是不同。
5.1. 堆内存
堆内存是jvm内存模型中最大的一块区域,被所有线程共享。是在jvm启动的时候进行创建。几乎所有的对象的空间分配都是在堆区来进行分配。
考虑到jvm的内存回收机制,堆内存划分为新生代和老年代两个区域(默认的新生代和老年代的空间大小比例为1:2).新生代可以在划分为Eden区,From 区(s0) to区(s1),三者的比例(8:1:1) 几乎所有的新对象的创建都是在eden区 完成。在垃圾回收(GC)过程中,Eden区的活跃的对象会被迁移到Survior区,当在达到一定的年龄(经过一定的垃圾回收算法测处理),会被转移到老年代中。
堆内存在物理上可以使不连续,但是在逻辑上需要满足连续。在实现时。可以实现成固定大小的,也可以是可扩展的。
5.2.方法区
方法区又被称为永久代,我们所讲的模型是(Hotsport最常见的jvm的模型)。同样 也是被所有的线程所共享的,该区域主要保存类的信息,静态变量,常量和编译器编译后的代码等数据
jdk7中,将永久代中的字符串常量池移动到堆中。jdk8 撤销了永久代 ,引入了元空间
方法区不需要连续的内存,可以选择固定大小或者可扩展,并且还可以选择不实现垃圾回收,相对而言,垃圾收集行为在这个区域是比较少见的,但并非数据进入方法区就如永久代的名字一样永久存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,圾回收机制的条件是相当苛刻的。
这段程序,以指数级不断的生成新的字符串,这样可以比较快速的消耗内存。
可以通过异常信息看到出现堆内存的异常,在jdk1.8之后,字符串常量池由永久代(方法区)转移到堆中
jvm的内存参数的设置
-
-Xms设置堆的最小空间大小。
-
-Xmx设置堆的最大空间大小。
-
-XX:NewSize设置新生代最小空间大小。
-
-XX:MaxNewSize设置新生代最大空间大小。
-
-XX:PermSize设置永久代最小空间大小。
-
-XX:MaxPermSize设置永久代最大空间大小。
-
-Xss设置每个线程的堆栈大小
public static void main(String[] args) { String s1 = "abc"; String s2 = "abc"; System.out.println(s1 == s2);//true // 使用字符数组构造一个字符串 char[] c = {'a','b','c'}; String s3 = new String(c); String s4 = new String(c); System.out.println(s3 == s4);//false String s5 = new String("abc"); String s6 = new String ("abc"); System.out.println(s5==s6);// false System.out.println(s1 == s3);//false System.out.println(s4 == s5);//false }
以上对于字符串的比较使用的是== 经过分析可以知道:==比较的是两个字符串对象的引用的地址是否相同。
比较字符串的内容相同:
-
-
boolean
equals(Object anObject)
将此字符串与指定对象进行比较。boolean
equalsIgnoreCase(String anotherString)
将此String
与其他String
比较,忽略案例注意事项。
-
-
如果要比较两个字符串的内容是否相同 则使用equals方法
System.out.println(s1.equals(s3)); System.out.println(s4.equals(s6));
System.out.println(s1.equals(s7));//false System.out.println(s1.equals(s8));//false System.out.println(s1.equalsIgnoreCase(s7));//true System.out.println(s1.equalsIgnoreCase(s8));//true
遍历字符串
从键盘录入一个字符串,使用程序实现在控制台遍历该字符串。
public static void main(String[] args) { //从键盘输入一个字符串 Scanner sc = new Scanner(System.in); System.out.println("请输入您要遍历的字符串:"); String str = sc.nextLine(); // 获取数组的长度 使用数组的length属性 获取字符串的长度 使用的是String类的length方法 for(int i = 0 ; i < str.length();i++){ char c = str.charAt(i); System.out.println(c); } }
统计字符的次数
键盘录入一个字符串,统计该字符串中大写字母 小写字母 数字出现的次数 (不考虑其他字符)
对于一个字符判断他是大写字母 小写字母 数字 直接判断:
大写字母: ch >= 'A' && ch<='Z'
小写字母:ch>='a'&& ch<='z'
数字:ch>='0'&&ch<='9'
public class CountCharNum { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入您要统计的字符串:"); String str = sc.nextLine(); // 定义字符统计的变量 int bigCount = 0; int smallCount = 0 ; int numberCount=0; for(int i =0 ; i < str.length();i++){ char ch = str.charAt(i); if(ch >='A'&& ch<='Z'){ bigCount++; }else if(ch >='a'&& ch<='z'){ smallCount++; }else if(ch >='0'&& ch<='9'){ numberCount++; } } System.out.println("大写字母的个数为:" + bigCount); System.out.println("小写字母的个数为:" + smallCount); System.out.println("数字的个数为:" + numberCount); } }
字符串反转:
定义一个字符串,实现字符串的反转 从控制台输入abc 输出结果为cba
7 String类的常用方法
-
-
-
-
-
boolean
equals(Object anObject)
将此字符串与指定对象进行比较。boolean
equalsIgnoreCase(String anotherString)
将此String
与其他String
比较,忽略案例注意事项。
-
-
-
-
-
-
-
-
-
-
int
lastIndexOf(int ch)
返回指定字符的最后一次出现的字符串中的索引。int
lastIndexOf(int ch, int fromIndex)
返回指定字符的最后一次出现的字符串中的索引,从指定的索引开始向后搜索。int
lastIndexOf(String str)
返回指定子字符串最后一次出现的字符串中的索引。int
lastIndexOf(String str, int fromIndex)
返回指定子字符串的最后一次出现的字符串中的索引,从指定索引开始向后搜索。int
length()
返回此字符串的长度。public static void main(String[] args) { String str = "abdcdadcd"; System.out.println(str.indexOf("a"));//0 System.out.println(str.lastIndexOf("a"));//5 }
-
-
-
-
char[]
toCharArray()
将此字符串转换为新的字符数组。String
toLowerCase()
将所有在此字符String
使用默认语言环境的规则,以小写。
-
-
-
-
-
static String
valueOf(boolean b)
返回boolean
参数的字符串boolean
形式。static String
valueOf(char c)
返回char
参数的字符串char
形式。static String
valueOf(char[] data)
返回char
数组参数的字符串char
形式。static String
valueOf(char[] data, int offset, int count)
返回char
数组参数的特定子阵列的字符串char
形式。static String
valueOf(double d)
返回double
参数的字符串double
形式。static String
valueOf(float f)
返回float
参数的字符串float
形式。static String
valueOf(int i)
返回int
参数的字符串int
形式。static String
valueOf(long l)
返回long
参数的字符串long
形式。static String
valueOf(Object obj)
返回Object
参数的字符串Object
形式。String s = String.valueOf(123);//将整数123 转换为字符串123
-
8 String的常见陷阱
String str1 = "abc";
String str2 = new String("abc");
字符串常量存储在字符串常量池中,并且是共享
字符串非常量对象 存储在堆中
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "hello" +"world";
String s4 = s1 +"world";
String s5 = s1 + s2;
String s6 = (s1 + s2).intern();
String s7 = "helloworld";
System.out.println(s3==s4);// false
System.out.println(s3 == s7);//true
System.out.println(s3==s5);//false
System.out.println(s4==s5);//false
System.out.println(s3==s6);//true
}
-
常量与常量的拼接,结果在常量池 且常量池中不会存在相同内容的常量
-
只要其中有一个是变量,结果就在堆中。
-
如果拼接的结果调用intern(),结果就在常量池中
public static void main(String[] args) { String str1 = new StringBuilder("计算机").append("软件开发").toString(); System.out.println(str1.intern()== str1);//true String str2 = new StringBuilder("ja").append("va").toString();//java是一个特殊的字符串 在jdk的底层,存在很多“java”字符串 System.out.println(str2.intern()==str2);//false }
面试题:
public static void main(String[] args) { String str1 = new String("str") + new String("01"); str1.intern(); String str2 = "str01"; System.out.println(str1 == str2);//true }
public static void main(String[] args) { String s1 = new String("he") +new String("llo"); String s2 = new String("h") +new String("ello"); String s3 = s1.intern(); String s4 = s2.intern(); System.out.println(s1==s3);//true System.out.println(s2 == s4);//false System.out.println(s3 == s4);//true }