• 0024 Java学习笔记-面向对象-包装类、对象的比较、String常量池问题


    包装类

    • 基本类型-->包装类
      • byte-->Byte
      • short-->Short
      • int-->Integer
      • long-->Long
      • char-->Character
      • float-->Float
      • double-->Double
      • boolean-->Boolean
    • 基本类型转为包装类型:
      • 自动装箱Autoboxing:将基本类型直接赋值给包装类变量或者Object类变量
    • 包装类型转为包装类型:
      • 自动拆箱AutoUnboxing:把包装类对象直接赋值给基本类型变量
    • 示例:自动装箱与自动拆箱
    public class T1{  
        public static void main(String[] args) {  
        	Integer inObj=13;     //自动装箱
        	Object boolObj=true;  //自动装箱,基本类型赋值给Object类型变量
        	int i=inObj;          //自动拆箱
        	float f=inObj;        //自动拆箱,注意类型匹配
        	System.out.println(i);
        	System.out.println(f);
        	if (boolObj instanceof Boolean) {
        		boolean b=(Boolean)boolObj; //强制类型转换+自动拆箱
        		System.out.println(b);
        	}
        }
    }
    
    • 字符串型的值转为基本类型:
      • 用包装类的静态的parse...()方法。注意没有Character类,String的toCharArray()方法转为字符数组
      • 用包装类的构造器
    • 基本类型转为字符串
      • 静态方法String.valueOf();
      • 基本变量+"";
    • 示例:字符串转基本类型
    public class Test{  
        public static void main(String[] args) {  
        	String strByte="127";
        	String strShort="32767";
        	String strInt="2147483647";
        	String strLong="21474836478";     //加了L,用parse和new转,都会失败
        	String strFloat="3.1415F";        //加了F,用parse和new转,都能成功
        	String strDouble="3.5665956565";
        	String strBoolean="true";
        	
        	byte b1=Byte.parseByte(strByte);
        	byte b2=new Byte(strByte);
        	System.out.println(b1+"    "+b2);
        	short s1=Short.parseShort(strShort);
        	short s2=Short.parseShort(strShort);
        	System.out.println(s1+"    "+s2);
        	int i1=Integer.parseInt(strInt);
        	int i2=new Integer(strInt);
        	System.out.println(i1+"    "+i2);
        	long l1=Long.parseLong(strLong);
        	long l2=new Long(strLong);
        	System.out.println(l1+"    "+l2);
        	float f1=Float.parseFloat(strFloat);
        	float f2=new Float(strFloat);
        	System.out.println(f1+"    "+f2);
        	double d1=Double.parseDouble(strDouble);
        	double d2=new Double(strDouble);
        	System.out.println(d1+"    "+d2);
        	boolean boo1=Boolean.parseBoolean(strBoolean);
        	boolean boo2=new Boolean(strBoolean);
        	System.out.println(boo1+"    "+boo2);
        	
        }
    }
    
    

    输出

    127 127
    32767 32767
    2147483647 2147483647
    21474836478 21474836478
    3.1415 3.1415
    3.5665956565 3.5665956565
    true true

    • 示例:基本类型转字符串
    public class Test{  
        public static void main(String[] args) {  
        	System.out.println(String.valueOf(127));
        	System.out.println(String.valueOf(32767));
        	System.out.println(String.valueOf(2147483647));
        	System.out.println(String.valueOf(21474836478L));  //注意L
        	System.out.println(String.valueOf(3.1415F));       //注意F
        	System.out.println(String.valueOf(3.5665956565));
        	System.out.println(String.valueOf(true));
        }
    }
    

    输出如下:

    127
    32767
    2147483647
    21474836478 //注意没有L
    3.1415 //注意没有F
    3.5665956565
    true

    • 包装类型与基本类型的比较
      • 包装类是引用类型,但可以直接用"=="跟基本类型比较
    • 包装类与包装类的比较
      • 如果包装类对象都是通过构造方法创建的:遵循对象的比较规则,即用"=="比较的是地址,用equals()比较对象的内容
      • 如果包装类对象都是通过自动装箱创建,且属于[-128,127],可以用"=="比较他们的值是否相等;如果在[-128,127]之外,那么遵循对象的比较规则
      • 通过自动装箱和构造方法创建的对象,不论是不是属于[-128,127],都遵循对象的比较规则
    • 关于[-128,127]:
      • Integer类在初始化时,一个内部类的静态代码块将[-128,127]的每个整数都创建了Integer对象,并保存在一个数组中,今后在将[-128,127]中的一个整数自动装箱成Integer对象时,则直接指向这个数组中对应的对象,因此可以用"=="比较它们的值是否相等
    • 示例:包装类与包装类的比较
    public class Test{  
        public static void main(String[] args) {  
        	System.out.println(new Integer(2)==new Integer(2));
        	System.out.println(new Integer(2).equals(new Integer(2)));
        	
        	Integer i1=127;
        	Integer i2=127;
        	System.out.println("127: i1==i2?  "+(i1==i2));
        	Integer i3=128;
        	Integer i4=128;
        	System.out.println("128: i3==i4?  "+(i3==i4));
        	
        	Integer i5=new Integer(127);
        	System.out.println("127: i1==i5?  "+(i1==i5));
        	Integer i6=new Integer(128);
        	System.out.println("128: i3==i6?  "+(i3==i6));
        }
    }
    

    输出如下:

    false
    true
    127: i1i2? true
    128: i3
    i4? false
    127: i1i5? false
    128: i3
    i6? false

    • 包装类的compare()方法:compare(a,b)
      • a>b:返回1
      • a==b:返回0
      • a<b:返回-1
    • 示例代码:
    public class Test{  
        public static void main(String[] args) {  
        	System.out.println(Boolean.compare(true,false));
        	System.out.println(Boolean.compare(new Boolean(false),true));
        	System.out.println(Integer.compare(5,13));
        	System.out.println(Integer.compare(new Integer(19),new Integer(10)));
        }
    }
    
    

    toString()方法

    • Object类的toString()方法返回的是类名@十六进制hashCode()值
    • 自己定义一个类的时候,一般都得重写toString()方法,用以下格式:类名[主要变量1=值1,主要变量2=值2,...]

    对象与对象的相等比较equals()与"=="

    • "==":

      • 对引用变量而言,只有两个变量指向同一个对象时,才返回true
      • 两个对象如果没有继承关系,那么不能用"=="比较,会出现编译错误
    • equals():

      • Object的equals()方法跟"=="一样,指向同一个对象才返回true
      • equals()一般都要重写,重写应满足的条件:
        • 自反性:对任意x,x.equals(x)一定返回true
        • 对称性:对任意x、y,如果x.equals(y)返回true,那么y.equals(x)也要返回true
        • 传递性:对任意x、y、z,x.equals(y)返回true,y.equals(z)也返回true,那么x.equals(z)一定也返回true
        • 一致性:只要两个对象用于比较的信息没有发生改变,那么不论调用equals()多少次,返回的结构都应该相同
        • 对任意不是null的x,x.equals(null)一定返回false
    • equals()重写示例,固定写法

    class Person{
    	private String name;
    	private String id;
    	Person(){}
    	Person(String name,String id){
    		this.name=name;
    		this.id=id;
    	}
    	public boolean equals(Object obj){
    		if (this==obj){   //如果二者指向同一个对象,返回true
    			return true;
    		}
    		if (obj!=null && obj.getClass()==Person.class){ //obj不为null,且指向的对象是Person类
    			Person perObj=(Person)obj;          //类型转换
    			if(this.id.equals(perObj.id)){      //根据id是否相等判断两个Person对象是否相等
    				return true;
    			}
    		}
    		return false; //如果obj为null或者obj指向的对象不是Person,返回false
    	}
    }
    

    字符串与"=="

    代码1:

    String s1="AB";
    String s2="A"+"B";
    System.out.println(s1==s2);  //true。编译阶段即可确定s2="AB",运行时,s1和s2都指向常量池的"AB"
    

    代码2:

    String s1="AB";
    String s2="B";
    String s3="A"+s2;
    System.out.println(s1==s3);  //false。s2是变量,编译阶段不能确定s3的值
    

    代码3:

    String s1="AB";
    final String s2="B";   //注意多了个final
    String s3="A"+s2;
    System.out.println(s1==s3);  //true。s2的值不可变,编译阶段就确定了s3的值是"AB"
    

    代码4:

    public static void main(String[] args) {  
        	String s1="AB";
        	final String s2=getString();  //注意有final
        	String s3="A"+s2;
        	System.out.println(s1==s3);   //false。虽然s2值不可变,但是是通过方法返回的,编译阶段也不能确定其值
        }
        static String getString(){
        	return "B";
        }
    

    代码5:

    String s1="AB";
    String s2="A";
    String s3="B";
    String s4=s2+s3;
    System.out.println(s1==s4); //false.
    

    代码:6

    String s1="AB";
    final String s2="A";
    final String s3="B";
    String s4=s2+s3;
    System.out.println(s1==s4); //true.s4的值在编译期即可确定
    

    代码7:开始引入intern()方法

    String s1="A";
    String s2="B";
    String s3=s1+s2;                     //s3实际指向堆内存中的"AB"
    System.out.println(s3==s3.intern()); //true。s3.intern()将堆内存中"AB"对象的地址添加到常量池表中,而不是在常量池中再创建个对象,二者实际都指向堆内存中的对象,因此二者相等
    System.out.println(s3=="AB"); //true。s3指向堆内存中"AB"的地址;"AB"按理说应当位于常量池,但常量池中只保存了"AB"在堆内存中的地址,所有二者还是相当
    //intern()方法用于将该字符串追加到常量池中,如果已经有了,就返回其引用;如果没有就将地址添加到常量池表中,再返回其引用,实际指向的是堆内存中的对象
    

    代码8:将代码7最后两行代码换个顺序

    String s1="A";
    String s2="B";
    String s3=s1+s2;
    System.out.println(s3=="AB");         //false.s3指向堆内存中的对象,"AB"则在常量池中
    System.out.println(s3==s3.intern());  //false.s3还是指向堆内存中的对象,s3.intern()返回常量池中的"AB"的地址
    
    • 总结:
      • 代码7和8的结果十分诡异,以上所做的解释也只是一种猜测,关键在于intern()方法,在常量池中没有字符串的情况下,是新建个字符串对象,还是将字符串的地址添加在常量池表中
      • 凡是编译阶段能确定的字符串,在运行期就在常量池中创建一个运算后的对象,而不会再计算一遍,这点存疑,从Java1.7开始,常量池位于堆内存
      • 用""创建的字符串位于常量池
      • 用new String()构造方法创建的字符串位于堆内存中,运行期创建
      • 用"+"连接的字符串直接量,在编译器就可以确定连接后的值,因此属于常量池
      • 用"+"连接的是字符串和变量或者方法返回值,则要到运行期才能确定,属于堆内存对象
    • 其他:
      • String s1=new String("ABC");String s2=new String("ABC");这两个语句创建了3个String对象
  • 相关阅读:
    过滤器--起步阶段
    常用指令-起步阶段
    模型和控制器-起步阶段
    指令介绍-起步阶段
    AngularJS简介-起步阶段
    c++之helloworld与命名空间
    c++ 之重要性
    一个没曾摸透的程序
    linux中什么是文件结构体?
    很全的linux网络编程技巧
  • 原文地址:https://www.cnblogs.com/sonng/p/6076045.html
Copyright © 2020-2023  润新知