第三周
课前问题
1.为什么说Java中的所有类都is-a Object?
在 Java 中,所有类都隐式地继承自 java.lang.Object
类。因此,可以说 Java 中的所有类都是 Object
类的子类或子类型。
Object
类是 Java 默认的根类或基类,它提供了一些通用的方法和功能,可以在所有对象上使用。这些方法包括 toString()
、equals()
、hashCode()
等。
当你在 Java 中定义一个类时,如果没有显式地指定一个类去继承,那么该类会自动继承 Object
类。这意味着,你可以在任何类中使用 Object
类中定义的方法。
2.在JDK文档中查找Object的toString方法。说一说,该方法有什么用?使用Eclipse查看Object的toString方法的代码,结合代码说说该代码的用途。
Object类是Java中所有类的超类,所以所有的Java对象都继承了toString方法。toString方法的目的是返回一个表示该对象的文本字符串。
使用Eclipse查看Object的toString方法的代码,可以看到如下代码:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
该代码的主要用途是生成一个包含对象类名和哈希码的字符串。其中,getClass()方法返回对象的运行时类,getName()方法返回类的全名。hashCode()方法返回对象的哈希码。Integer.toHexString()方法将哈希码转换为十六进制字符串。
使用toString方法的主要目的是方便调试和打印对象时的可读性。通过重写toString方法,可以返回对象特定的描述信息,方便开发者阅读和理解对象的状态和内容。通常,在使用System.out.println或日志打印对象时,会隐式调用对象的toString方法来获取对象的字符串表示。因此,重写toString方法可以提高代码的可读性和调试的便捷性。
3.在Eclipse中查看Object的equals方法的代码,说说equals的用途。该方法被什么修饰符修饰,意味着什么?什么时候需要覆盖equals方法?结合String类的equals方法说说覆盖如何体现子类特有的特性?
在Eclipse中查看Object的equals方法的代码,可以通过在Eclipse中打开源代码视图,导航到Object类,然后找到equals方法。
Object的equals方法的代码如下:
public boolean equals(Object obj) {
return (this == obj);
}
equals方法被public修饰符修饰,意味着该方法可以被其他类访问。public修饰符表示该方法是公共的,可以被任何其他类使用。
equals方法的主要用途是比较对象的内容是否相等。默认的equals方法实现是通过比较对象的引用是否相等,即判断两个对象是否为同一个实例。
需要覆盖equals方法的情况通常是在需要比较对象内容的情况下。当我们想要判断两个对象是否具有相同的属性和状态时,需要重写equals方法。例如,我们自定义了一个类,并且希望根据该类的属性进行对象比较,就需要覆盖equals方法以实现自定义的比较逻辑。
以String类的equals方法为例,String类覆盖了Object类的equals方法来实现字符串内容的比较。String类的equals方法比较的是两个字符串对象的字符序列是否完全一致,而不仅仅是比较引用。这是因为字符串对象的内容是有意义的,所以在比较字符串时,需要考虑对象内容的一致性。
覆盖equals方法时,需要注意遵循一些规则,如:
- 对称性:如果a.equals(b)返回true,那么b.equals(a)也应该返回true。
- 自反性:a.equals(a)应该返回true。
- 传递性:如果a.equals(b)返回true,且b.equals©返回true,那么a.equals©也应该返回true。
- 一致性:对象的比较结果应该在对象状态没有变化时保持不变。
通过覆盖equals方法,子类可以根据自身特有的特性实现自定义的对象比较逻辑。这允许子类在比较对象时,考虑到其自身的属性和状态,从而更加准确地比较对象的相等性。
4.如果在子类中想要复用父类的代码,要怎么办?
如果在子类中想要复用父类的代码,可以通过继承和使用super关键字来实现。
继承是面向对象编程中的一个重要概念,它允许子类继承父类的属性和方法。在Java中,使用extends关键字来实现继承。子类可以继承父类的非私有属性和方法。
对于需要复用的父类代码,可以将其放在父类中的方法中。子类可以通过调用super关键字,来调用父类中的方法或构造函数。
具体步骤如下:
- 子类声明继承父类,使用
extends
关键字。例如,class ChildClass extends ParentClass {}
。 - 在子类中,使用
super
关键字调用父类的方法或构造函数。例如,super.methodName()
或super()
。
通过继承和super关键字,子类可以复用父类的代码,并且在此基础上扩展和定制自己特有的功能。这样可以避免重复编写相同的代码,提高代码的可重用性和扩展性。
需要注意的是,父类中的方法或构造函数必须具有适当的可见性(public或protected),以便子类可以访问和复用。私有(private)的方法或构造函数是不可继承和复用的。
5.继承是复用代码的唯一方式吗?
-
组合:通过将一个类的实例作为另一个类的成员变量,实现代码的复用。这样可以在新类中使用已有类的功能。
-
接口实现:通过实现接口,在新类中实现接口定义的方法,从而复用接口中的代码。多个类可以通过实现同一个接口来共享同一套方法逻辑。
-
委托:委托是指在一个类中调用另一个类的方法来完成一项功能。通过在新类中将调用委托给已有类,实现代码复用。
PTA作业
6-1 jmu-Java-03面向对象基础-覆盖与toString
有Person
类,Company
类,Employee
类。
其中Employee
类继承自Person
类,属性为:
private Company company;
private double salary;
现在要求编写Employee
类的toString
方法,返回的字符串格式为:父类的toString-company的toString-salary
public String toString()
{
return super.toString()+"-"+company.toString()+"-"+salary;
}
6-2 jmu-Java-03面向对象基础-Object
输入整数n,创建n个对象,放入同一个数组中。
如果输入c
,则new Computer()
; //注意:Computer是系统中已有的类,无需自己编写
如果输入d
,则根据随后的输入创建Double
类型对象。
如果输入i
,则根据随后的输入创建Integer
类型对象。
如果输入s
,则根据随后的输入创建String
类型对象。
如果不是以上这些输入,则不创建对象,而是将null
存入数组相应位置。
最后倒序输出数组中的所有对象,如果数组中相应位置的元素为null
则不输出。
int n=sc.nextInt();
Object[] a=new Object[n];
for(int i=0;i<n;i++)
{
String op=sc.next();
if(op.equals("c")) a[i]=new Computer();
else if(op.equals("d")) a[i]=new Double(sc.nextDouble());
else if(op.equals("i")) a[i]=new Integer(sc.nextInt());
else if(op.equals("s")) a[i]=new String(sc.next());
else a[i]=null;
}
for(int i=n-1;i>=0;i--)
{
if((a[i] instanceof String)||(a[i] instanceof Integer)||(a[i] instanceof Double)||(a[i] instanceof Computer))
{
System.out.println(a[i].toString());
}
}
6-3(选做) jmu-Java-03面向对象基础-覆盖与equals
有Person
类,Company
类,Employee
类。
其中Employee
类继承自Person
类,属性为:
private Company company;
private double salary;
现在要求覆盖Employee
类的equals
方法,判定两个Employee
对象是否相等,请见如下判断方法:
其继承自父类Person
的属性值都相等,其company
属性对象equals
返回true
,且其salary
也相等。
salary
是double
型,比较时,使用DecimalFormat df = new DecimalFormat("#.##")
;使salary
保留两位小数,然后再进行比较。
注意:要考虑company
为null
的情况。
public boolean equals(Object obj)
{
if(this==obj) return true;
if(!(obj instanceof Employee)) return false;
Employee other=(Employee) obj;
if(!super.equals(other)) return false;
if(this.company==null)
{
if(other.company!=null) return false;
}
else if(!this.company.equals(other.company))
{
return false;
}
DecimalFormat df=new DecimalFormat("#.##");
String thisSalary=df.format(this.salary);
String otherSalary=df.format(other.salary);
return thisSalary.equals(otherSalary);
}
6-4(选做) jmu-Java-03面向对象基础-clone方法、标识接口、深拷贝
class Car implements Cloneable
{
private String name;
private CarDriver driver;
private int[] scores;
public Car() {}
public void setName(String name)
{
this.name=name;
}
public void setDriver(CarDriver driver)
{
this.driver=driver;
}
public void setScores(int[] scores)
{
this.scores=scores;
}
public String getName()
{
return name;
}
public CarDriver getDriver()
{
return driver;
}
public int[] getScores()
{
return scores;
}
public String toString()
{
return "Car [name=" + name + ", driver=" + driver + ", scores=" + Arrays.toString(scores) + "]";
}
public Car clone() throws CloneNotSupportedException
{
Car car=new Car();
CarDriver cd=new CarDriver();
if(driver==null) {cd=null;}
else {cd.setName(driver.getName());}
car.setDriver(cd);
car.setName(name);
if(scores == null) car.setScores(null);
else
{
int[] arr=Arrays.copyOf(scores,scores.length);
car.setScores(arr);
}
return car;
}
}
7-1 jmu-Java-03面向对象基础-05-覆盖
Java每个对象都继承自Object
,都有equals
、toString
等方法。
现在需要定义PersonOverride
类并覆盖其toString
与equals
方法。
- 新建
PersonOverride
类
a. 属性:String name
、int age
、boolean gender
,所有的变量必须为私有(private
)。
b. 有参构造方法,参数为name
, age,
gender
c. 无参构造方法,使用this(name, age,gender)
调用有参构造方法。参数值分别为"default",1,true
d.toString()
方法返回格式为:name-age-gender
e. equals
方法需比较name
、age
、gender
,这三者内容都相同,才返回true
.
- main方法
2.1 输入n1,使用无参构造方法创建n1个对象,放入数组persons1
。
2.2 输入n2,然后指定name age gender
。每创建一个对象都使用equals方法比较该对象是否已经在数组中存在,如果不存在,才将该对象放入数组persons2。
2.3 输出persons1
数组中的所有对象
2.4 输出persons2
数组中的所有对象
2.5 输出persons2
中实际包含的对象的数量
2.5 使用System.out.println(Arrays.toString(PersonOverride.class.getConstructors()));
输出PersonOverride的所有构造方法。
import java.math.BigDecimal;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n1=cin.nextInt();
List<PersonOverride> PersonOverride1=new ArrayList<>();
List<PersonOverride> PersonOverride2=new ArrayList<>();
for(int i=0;i<n1;i++)
{
PersonOverride tmp=new PersonOverride();
PersonOverride1.add(tmp);
}
int n2=cin.nextInt();
for(int i=0;i<n2;i++)
{
PersonOverride tmp=new PersonOverride(cin.next(),cin.nextInt(),cin.nextBoolean());
boolean ok=true;
for(int j=0;j<PersonOverride2.size();j++)
{
PersonOverride PersonOverride=PersonOverride2.get(j);
if(PersonOverride.equals(tmp)==true) ok=false;
}
if(ok==true) PersonOverride2.add(tmp);
}
for(PersonOverride PersonOverride:PersonOverride1)
{
System.out.println(PersonOverride);
}
for(PersonOverride PersonOverride:PersonOverride2)
{
System.out.println(PersonOverride);
}
System.out.println(PersonOverride2.size());
System.out.println(Arrays.toString(PersonOverride.class.getConstructors()));
}
}
class PersonOverride
{
private String name;
private int age;
private boolean gender;
public PersonOverride()
{
this("default",1,true);
}
public PersonOverride(String name,int age,boolean gender)
{
this.name=name;
this.age=age;
this.gender=gender;
}
public String toString()
{
return this.name+"-"+this.age+"-"+this.gender;
}
public boolean equals(Object obj)
{
if(this==obj)
{
return true;
}
if(obj==null||getClass()!=obj.getClass())
{
return false;
}
PersonOverride other = (PersonOverride) obj;
boolean equalsName=Objects.equals(this.name,other.name);
boolean equalsAge=this.age==other.age;
boolean equalsGender=this.gender==other.gender;
return equalsName&&equalsAge&&equalsGender;
}
}
7-2 jmu-Java-03面向对象基础-04-形状-继承
1.定义抽象类Shape
属性:不可变静态常量double PI
,值为3.14
,
抽象方法:public double getPerimeter(),public double getArea()
2.Rectangle
与Circle
类均继承自Shape
类。
Rectangle
类(属性:int width,length
)、Circle
类(属性:int radius
)。
带参构造方法为Rectangle
(int width,int length
),Circle
(int radius
)。
toString
方法(Eclipse自动生成)
3.编写double sumAllArea
方法计算并返回传入的形状数组中所有对象的面积和与double sumAllPerimeter
方法计算并返回传入的形状数组中所有对象的周长和。
4.main方法
4.1 输入整型值n,然后建立n个不同的形状。如果输入rect,则依次输入宽、长。如果输入cir,则输入半径。
4.2 然后输出所有的形状的周长之和,面积之和。并将所有的形状信息以样例的格式输出。
4.3 最后输出每个形状的类型与父类型.使用类似shape.getClass()
//获得类型, shape.getClass().getSuperclass()
//获得父类型;
import java.math.BigDecimal;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin.nextInt();
List<Shape> shapes=new ArrayList<>();
for(int i=0;i<n;i++)
{
String op=cin.next();
if(op.equals("rect"))
{
Rectangle rect=new Rectangle(cin.nextInt(),cin.nextInt());
shapes.add(rect);
Shape.sumArea(rect);
Shape.sumPerimeter(rect);
}
else
{
Circle cir=new Circle(cin.nextInt());
shapes.add(cir);
Shape.sumArea(cir);
Shape.sumPerimeter(cir);
}
}
System.out.println(Shape.getAllPerimeter());
System.out.println(Shape.getAllArea());
System.out.println(shapes.toString());
for(Shape shape:shapes)
{
System.out.print(shape.getClass()+",");
System.out.println(shape.getClass().getSuperclass());
}
}
}
abstract class Shape
{
final double PI=3.14;
private static double area=0.0;
private static double perimeter=0.0;
static double getAllPerimeter()
{
return perimeter;
}
static double getAllArea()
{
return area;
}
static void sumArea(Rectangle rect)
{
area+=rect.getArea();
}
static void sumArea(Circle cir)
{
area+=cir.getArea();
}
static void sumPerimeter(Rectangle rect)
{
perimeter+=rect.getPerimeter();
}
static void sumPerimeter(Circle cir)
{
perimeter+=cir.getPerimeter();
}
}
class Rectangle extends Shape
{
private int width,length;
public Rectangle(int width,int length)
{
this.width=width;
this.length=length;
}
public String toString() {
return "Rectangle [width=" + width + ", length=" + length + "]";
}
public double getArea()
{
return this.width*this.length;
}
public double getPerimeter()
{
return 2.0*(this.width+this.length);
}
}
class Circle extends Shape
{
private int radius;
public Circle(int radius)
{
this.radius=radius;
}
public String toString() {
return "Circle [radius=" + radius + "]";
}
public double getArea()
{
return radius*radius*PI;
}
public double getPerimeter()
{
return radius*2.0*PI;
}
}