2018年4月2日JAVA

一.object类

1.equals方法

equals() 方法用于将字符串与指定的对象比较。

package Demo1;

public class Person {
private String name;
private int age;
public Person(String name,int age){
    this.name=name;
    this.age=age;
}
public boolean equals(Object obj){
    if(obj==null){
        return false;
    }
    if(this==obj){
        return true;
    }
    if (obj instanceof Person){
    Person p=(Person)obj;
    return(this.age==p.age);
    }
    return false;
}
public String toString(){
    return "姓名为:"+name+",年龄为:"+age;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}
}

测试类:

package Demo1;
import java.util.ArrayList;
public class Testperson {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
Person p1=new Person("张三",20);
Person p2=new Person("李四",30);
//ArrayList arr=new ArrayList ();
/*boolean b=p1.equals(p2);
if(b){
    System.out.println("两个人年龄相同");
}else{
    System.out.println("两个人年龄不相同");
}*/
String s=p1.toString();
System.out.println(s);
String s2=p2.toString();
System.out.println(s2);
    }


}

总结:

equals():   比较的是引用数据类型,比较的是引用数据类型,不同类型有不同的equals方法,根据不同的数据类型调用不同的equals方法。也可以在特殊情况下重写equals方法。

跟==的区别:

  1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

    如果作用于引用类型的变量,则比较的是所指向的对象的地址

  2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量

    如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

    诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

2.tostring方法

因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”。

 它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不是String类型的话,就自动调用xx的toString()方法

 总而言之,它只是sun公司开发java的时候为了方便所有类的字符串操作而特意加入的一个方法

 回答补充:

 写这个方法的用途就是为了方便操作,所以在文件操作里面可用可不用

 例子1:

复制代码
 
public class Orc

{

public static class A

{

public String toString()

{

return "this is A";

}

}

public static void main(String[] args)

{

A obj = new A();

System.out.println(obj);

}

}
 
复制代码

 如果某个方法里面有如下句子: 

 A obj=new A();

 System.out.println(obj);

会得到输出:this is A

例子2:

复制代码
 
public class Orc

{

public static class A

{

public String getString()

{

return "this is A";

}

}

public static void main(String[] args)

{

A obj = new A();

System.out.println(obj);

System.out.println(obj.getString());

}

}
 
复制代码

 得到输出:xxxx@xxxxxxx的类名加地址形式 

System.out.println(obj.getString());

 得到输出:this is A

toString的好处是在碰到“println”之类的输出方法时会自动调用,不用显式打出来。

复制代码
 
 1 public class Zhang
2
3 {
4
5 public static void main(String[] args)
6
7 {
8
9 StringBuffer MyStrBuff1 = new StringBuffer();
10
11 MyStrBuff1.append("Hello, Guys!");
12
13 System.out.println(MyStrBuff1.toString());
14
15 MyStrBuff1.insert(6, 30);
16
17 System.out.println(MyStrBuff1.toString());
18
19 }
20
21 }
 
复制代码

值得注意的是, 若希望将StringBuffer在屏幕上显示出来, 则必须首先调用toString方法把它变成字符串常量,因为PrintStream的方法println()不接受StringBuffer类型的参数.

复制代码
 
1 public class Zhang
2 {
3 public static void main(String[] args)
4 {
5 String MyStr = new StringBuffer();
6 MyStr = new StringBuffer().append(MyStr).append(" Guys!").toString();
7 System.out.println(MyStr);
8 }
9 }
 
复制代码

toString()方法在此的作用是将StringBuffer类型转换为String类型.

复制代码
 
1 public class Zhang
2 {
3 public static void main(String[] args)
4 {
5 String MyStr = new StringBuffer().append("hello").toString();
6 MyStr = new StringBuffer().append(MyStr).append(" Guys!").toString();
7 System.out.println(MyStr);
8 }
9 }
 
复制代码

二.string类

1.String是不可变对象

      java.lang.String类使用了final修饰,不能被继承。Java程序中的所有字面值,即双引号括起的字符串,如"abc",都是作为String类的实例实现的。String是常量,其对象一旦构造就不能再被改变。换句话说,String对象是不可变的,每一个看起来会修改String值的方法,实际上都是创造了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。String对象具有只读特性,指向它的任何引用都不可能改变它的值,因此,也不会对其他的引用有什么影响。但是字符串引用可以重新赋值。java字符串在内存中采用unicode编码方式,任何一个字符对应两个字节的定长编码,即任何一个字符(无论中文还是英文)都算一个字符长度,占用两个字节。

例1:

复制代码
public class Immutable {
      public static String upcase(String s) {
           return s.toUpperCase();
      }
      public static void main(String[ ] args) {
           String str1= "Hello World";
           System.out.println(str1);  //Hello World
           String str2 = upcase(str1);
           System.out.println(str2);  //HELLO WORLD
           System.out.println(str1);  //Hello World
     }
}
复制代码

   当把str1传递给upcase()方法时,实际传递的是引用的一个拷贝。其实,每当把String对象作为方法的参数时,都会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置上,从未动过。

2、String常量池

     常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。Java为了提高性能,静态字符串(字面量/常量/常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串。对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果常量池中存在即返回该对象。

例2:


复制代码
public class test1 {
    public static void main(String[] args){
        String str1 = "Hello";
        //不会创建新的String对象,而是使用常量池中已有的"Hello",
        String str2 = "Hello";
        System.out.println(str1 == str2); //true
        //使用new关键字会创建新的String对象
        String str3 = new String("Hello");
        System.out.println(str1 == str3); //false 
    }
}
复制代码

3、String、StringBuffer和StringBuilder的区别

1.对象的可变与不可变

  String类中使用字符数组来保存数据,因为有“final”修饰符,所以string对象是不可变的。如下:

    private final char value[];

  StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存数据,这两种对象都是可变的。如下:

    char[] value;

2.是否是线程安全

  String中的对象是不可变的,也就可以理解为常量,所以是线程安全

  AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。看如下源码:

复制代码
1  public synchronized StringBuffer reverse() {
2      super.reverse();
3      return this;
4  }
5
6  public int indexOf(String str) {
7      return indexOf(str, 0);        //存在 public synchronized int indexOf(String str, int fromIndex) 方法
8  }
复制代码

  StringBuilder并没有对方法进行加同步锁,所以是非线程安全的

 3.StringBuilder与StringBuffer共同点

  StringBuilder与StringBuffer有公共的抽象父类AbstractStringBuilder。

  抽象类与接口的一个区别是:抽象类中可以定义一些子类的公共方法,子类只需要增加新的功能,不需要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。

  StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer会在方法上加synchronized关键字,进行同步。

如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。

4、创建了几个对象的问题

1 String str1 = "abc";
2 String str2 = new String("abc");

      对于1中的 String str1 = "abc",首先会检查字符串常量池中是否含有字符串abc,如果有则直接指向,如果没有则在字符串常量池中添加abc字符串并指向它.所以这种方法最多创建一个对象,有可能不创建对象。

      对于2中的String str2 = new String("abc"),首先会在堆内存中申请一块内存存储字符串abc,str2指向其内存块对象。同时还会检查字符串常量池中是否含有abc字符串,若没有则添加abc到字符串常量池中。所以 new String()可能会创建两个对象。

      所以如果以上两行代码在同一个程序中,则1中创建了1个对象,2中创建了1个对象。如果将这两行代码的顺序调换一下,则1 String str2 = new String("abc")创建了两个对象,而2 String str1 = "abc"没有创建对象。

看看下面的代码创建了多少个对象:

1     String temp="apple";  
2     for(int i=0;i<1000;i++) {  
3           temp=temp+i;  
4     }  

答案:1001个对象。

下面的代码创建了多少个对象:

1     String temp=new String("apple")  
2     for(int i=0;i<1000;i++) {  
3            temp=temp+i;  
4     }  

答案:1002个对象。

5、String的匹配相等问题

      使用String类经常需要对两个字符串进行对比,看是否相等。有==和equals两种选择,这两者方法区别很大:

             比对象的内容是否相等使用equals(),比较两个引用是否指向同一个对象时用==;equals()是看内容是否相等,比较好理解。而==是看是否属于同一个对象。
首先还要明白这个概念:常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。主要看编译期字符串能否确定。
看看下面几个例子:
test1:
1 String ok="ok";  
2 String ok1=new String("ok");  
3 System.out.println(ok==ok1);//fasle 

ok指向字符串常量池,ok1指向new出来的堆内存块,new的字符串在编译期是无法确定的。所以输出false。

test2:

1 String ok="apple1";  
2 String ok1="apple"+1;  
3 System.out.println(ok==ok1);//true 

编译期ok和ok1都是确定的,字符串都为apple1,所以ok和ok1都指向字符串常量池里的字符串apple1。指向同一个对象,所以为true。

test3:

1 String ok="apple1";  
2 int temp=1;  
3 String ok1="apple"+temp;  
4 System.out.println(ok==ok1);//false

主要看ok和ok1能否在编译期确定,ok是确定的,放进并指向常量池,而ok1含有变量导致不确定,所以不是同一个对象.输出false。

test4:

1 String ok="apple1";  
2 final int temp=1;  
3 String ok1="apple"+temp;  
4 System.out.println(ok==ok1);//true 

ok确定,加上final后使得ok1也在编译期能确定,所以输出true。

test5:

复制代码
 1 public static void main(String[] args) {    
 2     String ok="apple1";  
 3     final int temp=getTemp();  
 4     String ok1="apple"+temp;  
 5     System.out.println(ok==ok1);//false       
 6 }  
 7   
 8 public static int getTemp(){  
 9     return 1;  
10 }  
复制代码

ok一样是确定的。而ok1不能确定,需要运行代码获得temp,所以不是同一个对象,输出false。

String的intern()方法

当调用 intern()方法时,如果常量池中已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回常量池中的字符串;否则,将此 String 对象添加到常量池中,并且返回此 String 对象的引用。

看以下几个例子:

test6:

复制代码
public class test6 {

    private static String a = "ab";
    public static void main(String[] args){
        String s1 = "a";
        String s2 = "b";
        String s = s1 + s2;//+的用法
        System.out.println(s == a); //flase
        System.out.println(s.intern() == a);// true (intern的含义)
    }

}
复制代码

test7:

复制代码
复制代码
 1 public class test6 {
 2     private static String a = new String("ab");
 3     public static void main(String[] args){
 4         String s1 = "a";
 5         String s2 = "b";
 6         String s = s1 + s2;
 7         System.out.println(s == a); //flase
 8         System.out.println(s.intern() == a);//false
 9         System.out.println(s.intern() == a.intern()); //true
10     } 
11 }
原文地址:https://www.cnblogs.com/jason111/p/8708885.html