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()
== 运算符
- 可以使用在基本数据类型变量和引用数据类型变量中。
- 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等(不一定类型要相同)。
- 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即引用是否指向同一个对象。
❗ 用==进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错。
equals()方法
- 是一个方法,而非运算符。
- 只能比较引用类型,作用与“==”相同,比较是否指向同一个对象。
- Object类中equals()的定义:
1 2 3
| public boolean equals(Object obj) { return (this == obj); }
|
- 类File、String、Date及包装类(Wrapper Class)等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的类型和内容是否相同。
- 通常情况下,我们自定义的类如果使用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(“65和65.0f是否相等?” + (i == f)); System.out.println("65和'A'是否相等?" + (i == ch1)); System.out.println("12和ch2是否相等?" + (12 == ch2)); System.out.println("str1和str2是否相等?"+ (str1 == str2)); System.out.println("str1是否equals str2?"+(str1.equals(str2))); 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)); System.out.println(order2.equals(order3)); String s1 = "BB"; String s2 = "BB"; String s3 = new String("BB"); System.out.println(s1 == s2); System.out.println(s2 == s3); } } 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"); } if (m1.equals(m2)) { System.out.println("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()方法,当调用此方法时,返回对象的“实体内容”。
1 2 3
| public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
|
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);
|
- 基本类型数据转换为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); int[] arr1 = new int[] { 1, 2, 3 }; System.out.println(arr1); double[] arr2 = new double[] { 1.1, 2.2, 3.3 }; System.out.println(arr2);
|
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); System.out.println(c2.toString()); } }
|
Java中的JUnit单元测试
- 选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步
- 创建Java类,进行单元测试。Java类要求:① 此类是public的 ②此类提供公共的无参的构造器
- 此类中声明单元测试方法。此时的单元测试方法:方法的权限是public,没有返回值,没有形参
- 此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
- 声明好单元测试方法以后,就可以在方法体内测试相关的代码。
- 写完代码以后,左键双击单元测试方法名,右键: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");
|
- 获得包装类对象中包装的基本类型变量 ——拆箱
调用包装类的.xxxValue()方法:
1
| boolean b = bObj.booleanValue();
|
JDK1.5之后,支持自动装箱、自动拆箱,但类型必须匹配。
1 2 3 4 5 6 7 8
| int num1 = 10; Integer i = num1; boolean b1 = true; Boolean b2 = b1;
int num2 = i;
|
1
| int i = new Integer("12");
|
通过包装类的parseXxx(String s)静态方法:
1
| Float f = Float.parseFloat("12.1");
|
- 基本数据类型转换成字符串
调用字符串重载的valueOf()方法:
1
| String s1 = String.valueOf(2.34f);
|
更直接的方式:
简易版:
基本数据类型<—>包装类: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) ; float f = Float.parseFloat(str2) ;
|
练习
利用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); 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 2 3 4 5 6
| Object o2; if (true) o2 = new Integer(1); else o2 = new Double(2.0); System.out.println(o2);
|
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);
Integer m = 1; Integer n = 1; System.out.println(m == n);
Integer x = 128; Integer y = 128; System.out.println(x == y);
|
面试题:
final、finally、finalize的区别?