0%

javaSE基础学习day12

Object类的使用

Object类是所有Java类的根父类。

如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类。

1
2
3
4
5
6
7
8
9
10
11
public class Person {
...
}
//等价于:
public class Person extends Object {
...
}

method(Object obj){…} //可以接收任何类作为其参数
Person o = new Person();
method(o);

Object类中的功能(属性、方法)就具通用性。

  • 属性:无
  • 构造器:Object类只声明了一个空参的构造器
  • 方法:clone()、equals(Object obj)、finalize()、getClass()、hashCode()、notify()、notifyAll()、toString()、wait()、wait(long timeout)、wait(long timeout, int nanos)

==操作符与equals()

== 运算符

  1. 可以使用在基本数据类型变量和引用数据类型变量中。
  2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等(不一定类型要相同)
  3. 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即引用是否指向同一个对象。

❗ 用==进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错

equals()方法

  1. 是一个方法,而非运算符。
  2. 只能比较引用类型,作用与“==”相同,比较是否指向同一个对象。
  3. Object类中equals()的定义:
1
2
3
public boolean equals(Object obj) {
return (this == obj);
}
  1. 类File、String、Date及包装类(Wrapper Class)等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的类型和内容是否相同。
  2. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同。那么,我们就需要对Object类中的equals()进行重写。

重写equals()方法的原则:

对称性:如果x.equals(y)返回是true,那么y.equals(x)也应该返回是true。
自反性:x.equals(x)必须返回是true。
传递性:如果x.equals(y)返回是true,y.equals(z)返回是true,那么z.equals(x)返回也是true。
一致性:如果x.equals(y)返回是true,只要x和y内容一直不变,不管重复多少次,返回都是true。
任何情况下,x.equals(null),永远返回是false;x.equals(和x不同类型的对象)永远返回是false。

==和equals的区别(面试题)

1)对于==,比较的是值是否相等
如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址

2)对于equals方法,比较的是是否是同一个对象
equals方法不能作用于基本数据类型的变量,equals继承Object类;
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date、file等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

练习

练习一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char ch1 = 'A'; 
char ch2 = 12;
boolean b = true;
int i = 65;
float f = 65.0f;
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(“6565.0f是否相等?” + (i == f)); //true
System.out.println("65和'A'是否相等?" + (i == ch1)); //true
System.out.println("12和ch2是否相等?" + (12 == ch2)); //true
System.out.println("str1和str2是否相等?"+ (str1 == str2)); //false
System.out.println("str1是否equals str2?"+(str1.equals(str2))); //true
System.out.println("hello" == new java.util.Date()); //编译不通过
System.out.println(b == i); //编译不通过

练习二

编写Order类,有int型的orderId,String型的orderName,相应的getter()和setter()方法,两个参数的构造器,重写父类的equals()方法:public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class OrderTest{
public static void main(String[] args){
Order order1 = new Order(12,"AA");
Order order2 = new Order(12,new String("BB"));
Order order3 = new Order(12,"BB");
System.out.println(order1.equals(order2));//false
System.out.println(order2.equals(order3));//true

String s1 = "BB";
String s2 = "BB";
String s3 = new String("BB");
System.out.println(s1 == s2);//true
System.out.println(s2 == s3);//false
}
}
class Order{
private int orderId;
private String orderName;
public Order(int orderId,String orderName){
this.orderId = orderId;
this.orderName = orderName;
}
public void setOrderId(int orderId){
this.orderId = orderId;
}
public int getOrderId(){
return orderId;
}
public void setOrderName(String orderName){
this.orderName = orderName;
}
public String getOrderName(){
return orderName;
}
@Override
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof Order){
Order other = (Order)obj;
return this.OrderId = other.OrderId && this.orderName.equals(other.OrderName);
}
return false;
}
}

直接创建String类型对象时,JVM首先会去字符串常量池中查找是否存在“BB” 这个对象。如果不存在,则在字符串常量池中创建“BB”这个对象,然后将池中“BB”对象的引用地址返回给对象s1,这样s1的地址就在常量池中。如果存在,则不创建任何对象,直接将存在的“BB”的地址返回给对象s2。这就是为什么s1等于s2的原因。

而通过new方法创建的String对象,其创建的字符串是放在堆当中的。将堆当中的字符串地址返回赋值给s3,s1和s3的存放地址不相同,一个在字符串常量池中,一个在堆当中,字符串常量池外,因此返回的值是false。

练习三

根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖equals方法,使其判断当两个MyDate类型对象的年月日都相同时,结果为true,否则为false。public boolean equals(Object o)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class EqualsTest {
public static void main(String[] args) {
MyDate m1 = new MyDate(14, 3, 1976);
MyDate m2 = new MyDate(14, 3, 1976);
if (m1 == m2) {
System.out.println("m1==m2");
} else {
System.out.println("m1!=m2"); // m1 != m2
}
if (m1.equals(m2)) {
System.out.println("m1 is equal to m2");// m1 is equal to m2
} else {
System.out.println("m1 is not equal to m2");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyDate{
private int year;
private int month;
private int day;
public MyDate(int year,int month,int day){
this.year = year;
this.month = month;
this.day = day;
}
@Override
public boolean equals(Object o){
if(this == o){
return true;
}
if(o instanceof MyDate){
MyDate other = (MyDate)o;
return this.year == other.year && this.month = other.month && this.day = other.day;
}
return false;
}
}

toString() 方法

toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。当我们输出一个对象的引用时,实际上就是调用当前对象的toString()。String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回“实体内容”信息。自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”。

  • Object类中toString()的定义:
1
2
3
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  • 如何重写toString(),举例:
1
2
3
4
5
//自动实现
@Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + "]";
}
  • 在进行String与其它类型数据的连接操作时,自动调用toString()方法;
1
2
3
Date now = new Date();
System.out.println("now = " + now); //相当于
System.out.println("now = " + now.toString());
  • 可以根据需要在用户自定义类型中重写toString()方法
    如String 类重写了toString()方法,返回字符串的值。
1
2
s1 = "hello";
System.out.println(s1);//相当于System.out.println(s1.toString());
  • 基本类型数据转换为String类型时,调用了对应包装类的toString()方法
1
2
int a = 10; 
System.out.println("a = " + a);

练习

1.输出以下结果:

1
2
3
4
5
6
char[] arr = new char[] { 'a', 'b', 'c' };
System.out.println(arr);//abc
int[] arr1 = new int[] { 1, 2, 3 };
System.out.println(arr1);//[I@4459eb14
double[] arr2 = new double[] { 1.1, 2.2, 3.3 };
System.out.println(arr2);//[D@5a2e4553

2.定义两个类,父类GeometricObject代表几何形状,子类Circle代表圆形。在测试类创建两个Circle对象,判断其颜色是否相等;利用equals方法判断其半径是否相等;利用toString()方法输出其半径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class GeometricObject {
protected String color;
protected double weight;
protected GeometricObject() {
color = "white";
weight = 1.0;
}
protected GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public double getWeight() {
return weight;
}
public void setColor(String color) {
this.color = color;
}
public void setWeight(double weight) {
this.weight = weight;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Circle extends GeometricObject {
private double radius;
public Circle() {
super();
radius = 1.0;
}
public Circle(double radius) {
super();
this.radius = radius;
}
public Circle(double radius, String color, double weight) {
super(color,weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea() {
return Math.PI * radius * radius;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Circle) {
Circle other = (Circle) obj;
return this.radius == other.radius;
}
return false;
}
@Override
public String toString() {
return "Circle [radius=" + radius + "]";
}
}
1
2
3
4
5
6
7
8
9
10
11
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle(2,"blue", 3);

System.out.println(c1.getColor().equals(c2.getColor()));
System.out.println(c1.equals(c2));
System.out.println(c1);//默认调用toString方法
System.out.println(c2.toString());
}
}

Java中的JUnit单元测试

  1. 选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步
  2. 创建Java类,进行单元测试。Java类要求:① 此类是public的 ②此类提供公共的无参的构造器
  3. 此类中声明单元测试方法。此时的单元测试方法:方法的权限是public,没有返回值,没有形参
  4. 此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
  5. 声明好单元测试方法以后,就可以在方法体内测试相关的代码。
  6. 写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test

📌 说明:如果执行结果没有任何异常:绿条;2.如果执行结果出现异常:红条。

包装类(Wrapper)的使用

针对八种基本数据类型定义相应的引用类型——包装类(封装类)。
有了类的特点,就可以调用类中的方法,Java才是真正的面向对象。

基本数据类型 包装类
byte Byte
short Short
int Interger
long Long
float Float
double Double
boolean Boolean
char Character

Byte、Short、Integer、Long、Float、Double的父类是Number。

  • 基本数据类型包装成包装类的实例 ——装箱
    通过包装类的构造器实现:
1
2
int i = 500;
Integer t = new Integer(i);

         还可以通过字符串参数构造包装类对象:

1
2
Float f = new Float("4.56");
Long l = new Long("asdf"); //NumberFormatException
  • 获得包装类对象中包装的基本类型变量 ——拆箱
    调用包装类的.xxxValue()方法:
1
boolean b = bObj.booleanValue();

JDK1.5之后,支持自动装箱、自动拆箱,但类型必须匹配。

1
2
3
4
5
6
7
8
int num1 = 10;
Integer i = num1;//自动装箱Integer in1 = new Integer(num2);

boolean b1 = true;
Boolean b2 = b1;//自动装箱

//自动拆箱:包装类——>基本数据类型
int num2 = i;//自动拆箱int num3 = in1.intValue();
  • 字符串转换成基本数据类型
    通过包装类的构造器实现:
1
int i = new Integer("12");

         通过包装类的parseXxx(String s)静态方法:

1
Float f = Float.parseFloat("12.1");
  • 基本数据类型转换成字符串
    调用字符串重载的valueOf()方法:
1
String s1 = String.valueOf(2.34f);

         更直接的方式:

1
String s2 = 5 + "";

包装类

简易版:
基本数据类型<—>包装类:JDK 5.0 新特性:自动装箱 与自动拆箱
基本数据类型、包装类—>String:调用String重载的valueOf(Xxx xxx)
String—>基本数据类型、包装类:调用包装类的parseXxx(String s)
注意:转换时,可能会报NumberFormatException

1
2
3
4
5
//包装类在实际开发中用的最多的在于字符串变为基本数据类型。
String str1 = "30" ;
String str2 = "30.3" ;
int x = Integer.parseInt(str1) ; // 将字符串变为int型
float f = Float.parseFloat(str2) ; // 将字符串变为int型

练习

利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
❗ 提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动态伸缩。
→ 创建Vector对象:Vector v=new Vector();
→ 给向量添加元素:v.addElement(Object obj); //obj必须是对象
→ 取出向量中的元素:Object obj=v.elementAt(0);
→ 注意第一个元素的下标是0,返回值是Object类型的。
→ 计算向量的长度:v.size();
→ 若与最高分相差10分内:A等;20分内:B等;30分内:C等;其它:D等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ScoreTest {
public static void main(String[] args) {
Vector v = new Vector();
Scanner scan = new Scanner(System.in);

System.out.print("请输入学生成绩:(以负数代表输入结束)");
int maxScore = 0;
for (;;) {
int score = scan.nextInt();
if (score < 0) {
break;
}
if(score > 100){
System.out.println("输入的数据非法,请重新输入");
continue;
}
v.addElement(score);
if (score > maxScore) {
maxScore = score;
}
}
System.out.println("最高分是:" + maxScore);
char grade;
for (int i = 0; i < v.size(); i++) {
int score = (Integer)v.elementAt(i); //int score = (int)v.elementAt(i);
if (maxScore - score < 10) {
grade = 'A';
} else if (maxScore - score < 20) {
grade = 'B';
} else if (maxScore - score < 30) {
grade = 'C';
} else {
grade = 'D';
}
System.out.println("学生" + (i + 1) + "成绩为:" + score + ",等级为 " + grade);
}
}
}

面试题

1.如下两个题目输出结果相同吗?各是什么:

1
2
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);//1.0 自动类型提升
1
2
3
4
5
6
Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);//1

2.输出以下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false

//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],
//保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在
//-128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true

Integer x = 128;//相当于new了一个Integer对象
Integer y = 128;//相当于new了一个Integer对象
System.out.println(x == y);//false

面试题:

final、finally、finalize的区别?

  • 本文作者: susin3x
  • 本文链接: https://susin3x.cn/posts/5ecc7b9b.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!