• 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 }
  • 相关阅读:
    AcRxClass::addX
    string.format("%s",name)
    strcmp 与 _tcscmp
    acedinitget
    判断实体的类型 相关操作
    accmcolor
    CAD类型转换
    图的存储结构及遍历
    并查集(Union/Find)
    设计模式--缺醒适配器模式
  • 原文地址:https://www.cnblogs.com/jason111/p/8708885.html
Copyright © 2020-2023  润新知