1、Object类
1.1、简介
- Object类是所有类的父类。
- 一个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)。(比如之前的Animal父类,默认继承Object类)
- Java中的每个类都可以使用Object中定义的方法。
- 在JDK1.8当中,是这么解释Object类的,见下图。
1.2、equals方法
下面我们会介绍在Object中经常被重写的两个方法:equals()和toString()方法 |
- 1.在
test
包下新建一个测试类TestThree
,首先注释一下父类Animal
的静态、构造代码块及构造(无参和带参)方法中的输出语句,修改Animal的带参构造方法为。
public Animal(String name, int month) {
this.name = name;
this.month = month;
//System.out.println("我是父类的带参构造方法");
}
- 2.然后在
TestThree
中实例化两个Animal对象,然后调用equals
方法进行判断。代码如下。
在不重写equals方法的情况下,默认调用的是顶级父类Object的equals方法,比较的是两个引用是否指向同一个对象( 即在内存当中是否指向同一块操作区域)。
public class TestThree {
public static void main(String[] args) {
Animal one = new Animal("花花", 2);
Animal two = new Animal("花花", 2);
System.out.println("one和two的引用比较" + one.equals(two));
System.out.println("one和two的引用比较" + (one == two));
}
}
- 3.运行代码,结果如图所示。
- 4.继续编写TestThree代码,实例化两个字符串对象,然后用形同的方法进行比较,代码如下:
由于String类对Object类中的equals方法进行了重写, 如下图所示对该方法的解释: 将此字符串与指定的对象进行比较。当且仅当参数不为null并且是表示与该对象相同字符序列的字符串对象时,结果才是真的。( 翻译的左侧方法描述)。
public class TestThree {
public static void main(String[] args) {
Animal one = new Animal("花花", 2);
Animal two = new Animal("花花", 2);
System.out.println("one和two的引用比较" + one.equals(two));
System.out.println("one和two的引用比较" + (one == two));
System.out.println("==================================");
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("one和two的引用比较" + str1.equals(str2));
System.out.println("one和two的引用比较" + (str1 == str2));
}
}
- 5.运行代码,结果如下。(对String类来说,equals比较的是字符串内容是否相同,而==仍然比较的是是否为同一个对象)
如果我们仅仅相比较实例化的两个Animal对象的属性是否相同应该怎么做呢?答案便是方法重写。 |
- 6.下面先来
Animal
类当中重写Object
类的equals
方法,代码如下。
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
// 这里需要进行类型转换
Animal temp = (Animal) obj;
if (this.getName().equals(temp.getName()) && (this.getMonth() == temp.getMonth()))
return true;
else
return false;
}
- 7.再次运行代码,结果如下所示。重写equals之后在比较实例化的Animal对象时,比较的则是属性是否相同。
- 8.我们再编写一个equals方法,直接传入一个Animal对象,此时则该方法变为上面方法的重载方法了。而作为重载方法则不能再加注解
@Override
了,否则会报错。
public boolean equals(Animal animal) {
if (animal == null)
return false;
if (this.getName().equals(animal.getName()) && (this.getMonth() == animal.getMonth()))
return true;
else
return false;
}
1.3、toString方法
- 在Object中toString输出结果为:
类名+哈希值
的形式。
- 1.继续在上面代码基础上进行演示操作,在TestThree最终增加以下代码。
System.out.println("==================================");
System.out.println(one.toString());
System.out.println(one);// 打印对象时默认调用toString方法
System.out.println(str1.toString());
System.out.println(str1);//由于String类对Object类进行了重写,所以打印的为字符串的内容(String也是一个对象)
- 2.运行代码结果如下。
- 3.下面我们在
Animal
中对toString方法进行重写。可以按照下图的操作方式进行快速构建重写代码。
- 4.这里对自动生成的代码稍作修改。
@Override
public String toString() {
return "Animal [昵称=" + name + ", 年龄=" + month + "]";
}
- 5.再次运行代码,结果如下图所示。
更多关于Object的属性和方法请参考官方的API文档(Object类位于java.lang包下):https://docs.oracle.com/javase/8/docs/api/index.html
2、final关键字
通过继承关系的实现,大大提高了代码的复用性和灵活性。但是在有些时候,我们并不希望这个类被继承,这个方法被重写亦或是这个变量的值被修改,此时就要用到final关键字了。 |
- 比如
public final class Animal{}
就表示Animal这个类没有子类,不允许被继承,也称为终极类。 - 同样地,方法也是这样,若不希望父类的方法被重写,则需要加上关键字final,但是该方法仍能被子类正常调用。
- final不能修饰构造方法
- 在方法中的局部变量若被final修饰,则该变量不能被重新赋值,即一旦赋值则不允许再被修改。
- 那么类中的成员属性呢?
- 若成员属性被final修饰,只能在定义时初始化、在构造代码块中初始化、在构造方法中初始化。若是在别处比如成员方法中初始化则会报错如下图:
- 并且被final修饰的成员属性必须被初始化,若不被初始化,则在构造方法处会报错,如下图所示:
- 若成员属性被final修饰,只能在定义时初始化、在构造代码块中初始化、在构造方法中初始化。若是在别处比如成员方法中初始化则会报错如下图:
在Java中像类、String、数组、接口等都是引用类型的数据,都是通过实例化的方式来构造对象的,像这些引用数据类型的变量一旦被final进行修饰之后,它的引用地址是否可以改变呢?属性值是否可以发生改变呢? |
- 引用类型的数据在实例化对象之后,引用的地址是不能改变的。
- 引用类型的数据在实例化之后,其属性值可以根据需要进行修改的,截图略。
- 基本数据类型的变量被final修饰,一旦被赋值则不允许被修改。
- 若我们希望一个变量既不能被修改,也可以作为全局变量,那就需要用static+final共同修饰,例如:
public static final String URL="www.baidu.com";
总结:使用final修饰可以提高性能,但会降低可扩展性。