Java面向对象(下)-1

AI摘要:

对应《疯狂Java讲义(第5版)》6.1-6.4 章节

包装类

即8个基本类型包装为对象。

基本类型在中直接存储的具体数值,而包装类型则存储的是中的引用。

相比较于基本类型而言,包装类型需要占用更多的内存空间,但基本类型不具备“对象”的特性。

基本数据类型(默认值)包装类(默认值)取值范围
byte (0)Byte (null)-128~127
short (0)Short (null)-32768~32767
int (0)Integer (null)-231 ~ 2(31-1)
long (0)Long (null)-263 ~ 2(63-1)
float (0.0)Float (null)1.4E-45~3.4028235E38
double (0.0)Double (null)4.9E-324~1.7976931348623157E308
boolean (false)Boolean (null)true或false
char (为空)Character (null)0~65535

自动装箱,自动拆箱(JDK 1.5)

定义:基本数据类型和包装类之间可以自动地相互转换

理解:装箱就是自动将基本数据类型转换为封装类型,拆箱就是自动将封装类型转换为基本数据类型

1
2
3
4
5
Integer b = 10;     // 自动装箱
int c = b; // 自动拆箱
//实际执行
Integer d = Integer.valueOf(10); // 自动装箱
int e = d.intValue(); // 自动拆箱

字符串和基本类型转换

类型方法
字符串转基本型使用包装类的 parseXXXvalueof 静态方法
基本型转字符串使用包装类的 toString 或 String类的valueof 静态方法
1
2
3
4
5
6
7
8
9
//基本型转字符串
int hh = 123;
String s1 = hh + "";
String s2 = String.valueOf(hh);
String s3 = Integer.toString(hh);
//字符串转基本型
String str = "123";
int str1 = Integer.parseInt(str);
int str2 = Integer.valueOf(str);

包装类和基本类型之间的比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1)基本类型和包装类型
int a = 100;
Integer b = 100;
System.out.println(a == b); // true

// 2)两个包装类型
Integer c = 100;
Integer d = 100;
System.out.println(c == d); // true

// 3)
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false
  • 第一段代码,基本类型和包装类型进行 == 比较,这时候 b 会自动拆箱,直接和 a 比较值,所以结果为 true;

  • 第二段代码,两个包装类型都被赋值为了100,这时候会自动装箱。-128 到 127 之间的整型对象是从 IntegerCache 中获取然后比较,所以结果为 true;

    TIPS:当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不用重新创建一个对象。

  • 第三段代码,两个包装类型重新被赋值为了200,这时候仍然会进行自动装箱,结果是 true,但两个包装类的对象不一致,结果为false。

    此时 == 操作符应用于两个引用类型的比较,比较的是两个引用类型的引用地址是否相同,即是否为同一个对象。

Java7为所有包装类提供compare静态方法

java.lang包的Integer类的compare()方法比较作为参数给出的两个整数值(x,y),如果(x == y)则返回零,如果(x < y)则返回小于零的值,如果(x > y),则返回大于零的值。

整形包装类无符号数运算

参考《 疯狂java讲义第五版》P171

打印对象 和 toString方法

toString()是一个“自我描述”方法,通常继承于Object类,其返回值类型为String类型,返回类名和它的引用地址,如Person@15db9742

对象打印自动调用toString方法

1
2
System.out.println(s1);//相当于下一行代码
System.out.println(s1.toString());

在进行String类与其他类型的连接操作时,自动调用toString()方法,demo如下:

1
2
3
Date now = new Date();
System.out.println("now = " + now);//相当于下一行代码
System.out.println("now = " + now.toString());

重写

1
2
3
public string toString(){
return {字符串值};
}

== 和 equals方法

“==”比较基本数据类型时比较数值是否相等(不要求数据类型严格相同),而比较两个对象时比较的是两个对象的内存地址值,即是否指向同一对象(对象必须同类型或有父子关系)

对于equals()方法(默认从Object继承),注意:equals方法不能作用于基本数据类型的变量

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

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

如何正确重写equals方法?

  1. 对称性:如果x.equals(y)返回true,那么y.equals(x)也应该返回true
  2. 传递性:如果x.equals(y)y.equals(z)都返回true,那么x.equals(z)也应该返回true
  3. 一致性:如果对象没有被修改,那么多次调用x.equals(y)应该始终返回truefalse
  4. 非空性x.equals(null)应该返回false
  5. 自反性x.equals(x)应该返回true

在重写equals方法时,我们应该考虑上述五个原则。此外,通常我们还需要重写hashCode方法,以确保满足散列合同的约定。

下面是一个Person类重写equals方法的示例:

obj.getClass() != Person.class 比 obj instanceof Person 好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Person {
private String name;
private int age;
// 构造方法、getter和setter方法省略
@Override
public boolean equals(Object obj) {
if (this == obj) { //同一对象
return true;
}
if (obj == null || obj.getClass() != Person.class) { //类型一致
return false;
}
Person other = (Person) obj; //类型转换
return age == other.age && name.equals(other.name); //自定义判断
}
}

类成员 static

static不能修饰构造器,

类成员属于整个类,不属于单个对象,但可通过对象(即使为null)访问类成员,实际仍通过类访问

类成员(static修饰)无法访问实例成员,因为类成员初始化完成时,实例成员不一定初始化完成

单例(Singleton)类

类构造器由private修饰,隐藏起来,提供一个Public方法(必须为static),用于创建和访问该类对象

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton
{
private static Singleton sin; //缓存已创建对象
private Singleton(){}
public static Singleton getInstance()
{
//保证只产生一个Singleton对象
if(sin == null)
sin = new Singleton();
return sin;
}
}

final修饰符

表示修饰的类、方法和变量不可改变

修饰变量时,表示获得初始值后不可被重新赋值

final成员变量

必须显示指定初始值

必须在初始化块、声明变量时或构造器(非静态变量)中指定初始值

final修饰引用变量时,只保证引用地址不发生改变,但引用的对象可能发生改变

final 宏变量

宏变量相当于一个直接量,程序会直接把宏变量替换成直接量,成为宏变量的条件如下:

  1. final修饰
  2. 定义变量时指定了初始值
  3. 该初始值在编译时就可以确定下来

其2中包括赋直接量,或者基本算数表达式或字符串连接运算,没有访问普通变量或调用方法即可

final方法和final类

final修饰public方法时,表示其不可被重写

final修饰private方法用处不大,因为private方法无法继承,更无法重写,如果*子类出现完全相同的方法,*也只是重新定义了一个新方法

final修饰的方法仍可重载

final修饰类,表示该类不可被继承

不可变(Immutable)类

不可变类(Immutable class)是指当一个对象被创建出来以后,它的值就不能被修改了,也就是说,一个对象一旦被创建出来,在其整个生命周期中,它的成员变量就不能被修改了。它有点类似于常量(const),只允许别的程序读,而不允许别的程序进行修改。如8个包装类以及java.lang.String类

在Java类库中,所有基本类型的包装类都是不可变类,例如Integer、Float等。此外,String也是不可变类。

原则

  1. 类中所有的成员变量被private和final所修饰
  2. 提供带参数的构造器或实例方法,根据参数初始化成员变量
  3. 仅提供成员变量的getter方法
  4. 如果某成员变量为引用变量,需通过new新建临时对象并克隆该成员变量值后返回
  5. 如果有必要,可以通过覆盖 Object 类的 equals()方法和hashCode()方法。在 equals()方法中,根据对象的属性值来比较两个对象是否相等,并且保证用 equals()方法判断为相等的两个对象的hashCode()方法的返回值也相等,这可以保证这些对象能正确地放到HashMap或HashSet集合中

缓存实例的不可变类

不可变类的实例状态不可变,可以方便的被多个对象共享。若程序经常使用相同的不可变类实例,则应考虑缓存改实例,从而避免反复创建该对象,降低系统开销。但是也不能盲目使用缓存,因为缓存对象会占用系统内存。

可借助数组实现缓存,例如Integer类

Lambda表达式

枚举类enum


Java面向对象(下)-1
https://blog.cngo.rr.nu/posts/ae84.html
作者
cngo
发布于
2024年7月18日
许可协议