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: i3i4? false
127: i1i5? false
128: i3i6? 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
}
}
字符串与"=="
- 字符串有两种情况,一种是字符串直接量,存储在常量池中,常量池也在堆内存中;一种是堆内存中的字符串对象,存储在堆内存中
- String的这个问题很复杂,慢慢来看,下面参考:http://www.cnblogs.com/kkgreen/archive/2011/08/24/2151450.html
代码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对象
0024 Java学习笔记-面向对象-包装类、对象的比较、String常量池问题的更多相关文章
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- 程序设计基础·Java学习笔记·面向对象(下)
Java程序设计基础之面向对象(下) (补充了上的一些遗漏的知识,同时加入了自己的笔记的ヾ(•ω•`)o) (至于为什么分P,啊大概是为了自己查笔记方便(?)应该是("` 3′") ...
- 3.1常用类(java学习笔记)包装类及日期类
一.包装类 java是一门面向对象的语言,秉承一切皆对象的思想. 可java中有一些基本数据类型并不是对象,有时可能需要将它们变为对象. 这时就需要用到我们的包装类了. 基本数据类型 包装类 int ...
- Java学习笔记--类和对象
1.介绍面向对象的编程 面向对象是现在主流的编程样例,它替代了以前C语言使用时的“结构体”,Java是一门面向对象的语言,所以需要熟悉面向对象的概念.面向对象的程序由很多对象组成,每 ...
- 【原】Java学习笔记024 - 包装类
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 之前对于基本数据类 ...
- Java 学习笔记(8)——匿名对象与内部类
一般在编写代码时可能会遇到这样的场景--在某些时候,我需要定义并某个类,但是只会使用这一次,或者是某个类对象只会使用一次,为它们专门取名可能会显的很麻烦.为了应对这种情况,Java中允许使用匿名对象和 ...
随机推荐
- 模拟QQ聊天系统-安卓源代码
利用课余时间随便写的一个小东西,都是一起学习. 先上图: package com.example.nanchen.listviewdemo.adapter; import android.conten ...
- AppCan学习笔记----关闭页面listview动态加载数据
AppCan页面关闭 AppCan 的页面是由两个HTML组成,如果要完全关闭的话需要在主HTML eg.index.html中关闭,关闭方法:appcan.window.close(-1); 管道 ...
- Redis数据类型,以及应用场合
Redis常用的数据类型为String,Hash,List,Set等,简介如下: String 1.String 常用命令: 除了get.set.incr.decr mget等操作外,Redis还提供 ...
- gradle中使用嵌入式(embedded) tomcat, debug 启动
在gradle项目中使用embedded tomcat. 最开始部署项目需要手动将web项目打成war包,然后手动上传到tomcat的webapp下,然后启动tomcat来部署项目.这种手动工作通常还 ...
- WebSocket in ASP.NET Core
一.WebSocket WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 首先HTTP有1.1和1.0 ...
- Angularjs学习笔记9_JSON和JSONP
说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?数据可以用自定义字符串或者用XML来描述,跨域可以通过服务器端代理来解决.最被推崇或者说首选的 ...
- JetBrains.DotMemory.Keygen.4.x
GoogleN久都没找到这一类的工具. 只好折腾一个了. CSDN 免积分 0积分 下载 http://download.csdn.net/detail/caizz520/7477865 全球首发-V ...
- using 的三种用法
using 有哪三种用法? 1)引入命名空间. 2)给命名空间或者类型起别名. 3)划定作用域.自动释放资源,使用该方法的类型必须实现了 System.IDisposable接口,当对象脱离作用域之后 ...
- "System.Security.Cryptography.CryptographicException: 拒绝访问" 问题的解决方法
.net web程序使用rsa算法进行加解密时,程序报告“System.Security.Cryptography.CryptographicException: 拒绝访问”错.按网上搜的解决方法做了 ...
- TableLayoutPanel导致的闪屏问题
界面Load的时候添加对tableLayoutPanel的处理即可,还可设置窗体的DoubleBuffered属性为True tableLayoutPanel1.GetType().GetProper ...