包装类
为8种基本数据类型分别定义了相应的引用类型,称为基本数据类的包装类。开发者可以近似地把基本类型当成对象来使用(所有装箱,拆箱过程都由系统自动完成),反过来也可以把包装类当成基本数据类型来使用。
包装类还可以实现基本类和字符串之间的转换
public class Primitive2String
{
public static void main(String[] args)
{
String intStr = "123";
//把一个特定字符串转换成int变量
int it = Integer.parseInt(intStr);
System.out.println(it);
String floatStr = "4.56";
//把一个特定字符串转换成float变量
float ft = Float.parseFloat(floatStr);
System.out.println(ft);
//把一个float变量转换成String变量
String ftStr = String.valueOf(2.345f);
System.out.println(ftStr);
//把一个double变量转换成String变量
String dbStr = String.valueOf(3.344);
System.out.println(dbStr);
//把一个boolean变量转换成String变量
String boolStr = String.valueOf(true);
System.out.println(boolStr.toUpperCase());
}
}
当包装类与数值进行比较时会直接取出包装类所包装的数值进行比较。两个包装类的实例进行比较就比较复杂,因为包装类实际上是引用类型,只有两个包装里引用指向同一个对象才会返回true。
处理对象
输出对象实际上是输出对象的toString方法的返回值
toString是Object类中的一个实例方法,所有java类都是Object类的子类,所以所有类都具有toSting()方法
当对象和字符船进行连接的时候,系统也会调用java对象的toString方法的返回值和字符串进行连接。
== :不要求数值类型完全相同。对于引用型变量,只有指向同一个对象时才返回true,不能用于比较没有父子关系的两个对象。
public class StringCompareTest
{
public static void main(String[] args)
{
// s1直接引用常量池中的"疯狂Java"
String s1 = "疯狂Java";
String s2 = "疯狂";
String s3 = "Java";
// s4后面的字符串值可以在编译时就确定下来
// s4直接引用常量池中的"疯狂Java"
String s4 = "疯狂" + "Java";
// s5后面的字符串值可以在编译时就确定下来
// s5直接引用常量池中的"疯狂Java"
String s5 = "疯" + "狂" + "Java";
// s6后面的字符串值不能在编译时就确定下来,
// 不能引用常量池中的字符串
String s6 = s2 + s3;
// 使用new调用构造器将会创建一个新的String对象,
// s7引用堆内存中新创建的String对象
String s7 = new String("疯狂Java");
System.out.println(s1 == s4); // 输出true
System.out.println(s1 == s5); // 输出true
System.out.println(s1 == s6); // 输出false
System.out.println(s1 == s7); // 输出false
}
}
JVM常量池(constant pool)保证相同的字符串直接量只有一个。。例子中1,4,5所引用的字符串在编译的时候就确定下来了,因此他们引用变量池中的同一个字符串对象。
Object默认提供的equals()只是比较对象的地址,与==的比较结果相同。但可以对它进行重写
/**
* Description:
* 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>
* Copyright (C), 2001-2018, Yeeku.H.Lee<br>
* This program is protected by copyright laws.<br>
* Program Name:<br>
* Date:<br>
* @author Yeeku.H.Lee [email protected]
* @version 1.0
*/
class Person
{
private String name;
private String idStr;
public Person(){}
public Person(String name , String idStr)
{
this.name = name;
this.idStr = idStr;
}
// 此处省略name和idStr的setter和getter方法。
// name的setter和getter方法
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
// idStr的setter和getter方法
public void setIdStr(String idStr)
{
this.idStr = idStr;
}
public String getIdStr()
{
return this.idStr;
}
// 重写equals()方法,提供自定义的相等标准
public boolean equals(Object obj)
{
// 如果两个对象为同一个对象
if (this == obj)
return true;
// 只有当obj是Person对象
if (obj != null && obj.getClass() == Person.class)
{
Person personObj = (Person)obj;
// 并且当前对象的idStr与obj对象的idStr相等才可判断两个对象相等
if (this.getIdStr().equals(personObj.getIdStr()))
{
return true;
}
}
return false;
}
}
public class OverrideEqualsRight
{
public static void main(String[] args)
{
Person p1 = new Person("孙悟空" , "12343433433");
Person p2 = new Person("孙行者" , "12343433433");
Person p3 = new Person("孙悟饭" , "99933433");
// p1和p2的idStr相等,所以输出true
System.out.println("p1和p2是否相等?"
+ p1.equals(p2));
// p2和p3的idStr不相等,所以输出false
System.out.println("p2和p3是否相等?"
+ p2.equals(p3));
}
}
final
final修饰的成员变量必须由程序员显示指定初始值
类变量:必须在静态初始化块或者声明该类变量时指定初始值
成员变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值
final在初始化之前不能直接访问,但可以通过方法来访问
final修饰的引用型变量不能被重新赋值,但可以改变引用类型变量所引用对象的内容。
final变量可以相当于一个直接量“宏替换”,需要满足:
在定义final变量时指定了初始值
该初始值可以在编译时就被确认下来
/**
* Description:
* 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>
* Copyright (C), 2001-2018, Yeeku.H.Lee<br>
* This program is protected by copyright laws.<br>
* Program Name:<br>
* Date:<br>
* @author Yeeku.H.Lee [email protected]
* @version 1.0
*/
public class StringJoinTest
{
public static void main(String[] args)
{
String s1 = "疯狂Java";
// s2变量引用的字符串可以编译时就确定出来,
// 因此s2直接引用常量池中已有的"疯狂Java"字符串
String s2 = "疯狂" + "Java";
System.out.println(s1 == s2); // 输出true
// 定义2个字符串直接量
String str1 = "疯狂"; //①
String str2 = "Java"; //②
// 将str1和str2进行连接运算
String s3 = str1 + str2;
System.out.println(s1 == s3); // 输出false
}
}
由于str1 str2在编译时只是普通变量,不会执行宏替换,所以在编译阶段无法获得str3的值。只要将str1 str2用fianl修饰就行
final修饰的类不能有子类。当子类继承父类的时候,将可以访问到父类内部数据,并可通过重写来改变父类的方法的实现细节,所以不能有子类。
抽象类
抽象类不能用于创建实例,只要是用于被其子类调用。
当使用abstract修饰类时,表明这个类只能被继承,当修饰方法的时候,表明这个方法只能在子类中实现。
抽象类体现的是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造。
接口
接口定义的是多个类的共同行为规范,这些行为是与外界交流的通道,这就意味着接口里通常是定义一组公用的方法。因此接口里的常量、方法、内部类和内部枚举只能用public来修饰。
系统会自动为接口里定义的成员变量增加public static final修饰符。
接口里定义的方法只能是抽象方法、类方法、默认方法或私有方法,如果不是这几种方法,系统会自动地为普通方法加上abstract修饰符,所以接口里的普通方法总是以public abstract修饰