1. 继承
1.1 继承的实现

继承的概念
- 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
实现继承的格式
- 继承通过extends实现
- 格式:class 子类 extends 父类 { }
- 举例:class Dog extends Animal { }
继承带来的好处
- 继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。
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 47 48 49 50
| public class Fu { private String name; private int age; public double money;
public Fu() { System.out.println("父类的空参数的构造方法执行了..."); }
public Fu(String name, int age, double money) { System.out.println("父类的带参数的构造方法执行了..."); this.name = name; this.age = age; this.money = money; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } ... }
public class Zi extends Fu{ public void show(){ System.out.println("访问父亲的姓名:"+getName()); System.out.println("访问父亲的钱:"+ money); } }
public class TestZi { public static void main(String[] args) { Zi zi = new Zi(); zi.setName("张三"); zi.setAge(18); zi.setMoney(100); zi.show();
System.out.println(zi.getAge()); } }
|
1.2 继承的好处和弊端
继承好处
- 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
- 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
继承弊端
- 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
继承的应用场景:
- is..a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类
1.3. Java中继承的特点(掌握)
Java中继承的特点
- Java中类只支持单继承,不支持多继承
- 错误范例:class A extends B, C { }
- Java中类支持多层继承

多层继承示例代码:
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
| public class Granddad {
public void drink() { System.out.println("爷爷爱喝酒"); } }
public class Father extends Granddad {
public void smoke() { System.out.println("爸爸爱抽烟"); } }
public class Mother {
public void dance() { System.out.println("妈妈爱跳舞"); } } public class Son extends Father { }
class A {} class B extends A{}
class D extends B{}
|
2. 继承中的成员访问特点
2.1 继承中变量的访问特点
在子类方法中访问一个变量,采用的是就近原则。
- 子类局部范围找
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑父亲的父亲…)
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Fu { int num = 10; }
class Zi { int num = 20; public void show(){ int num = 30; System.out.println(num); } }
public class Demo1 { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
|
2.2 super
this&super关键字:
- this:代表本类对象的引用
- super:代表父类存储空间的标识(可以理解为父类对象引用)
this和super的使用分别
- 成员变量:
- this.成员变量 - 访问本类成员变量
- super.成员变量 - 访问父类成员变量
- 成员方法:
- this.成员方法 - 访问本类成员方法
- super.成员方法 - 访问父类成员方法
构造方法:
- this(…) - 访问本类构造方法
- super(…) - 访问父类构造方法
2.3 继承中构造方法的访问特点
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()
问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
子类必须手动调用”可用的构造方法”,如果调自己的,需要使用 this(xxx),如果是调用父类的,需要使用 super(xxx);
1 2 3 4
| 1. 通过使用super关键字去显示的调用父类的带参构造方法 2. 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法
注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存
|
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 47 48 49 50 51 52 53
|
public class Fu06 { int num; public Fu06(){ System.out.println("父空参..."); } public Fu06(int num) { System.out.println("父有参"); this.num = num; } }
public class Zi06 extends Fu06{ public Zi06(){ super(); System.out.println("子空参..."); } public Zi06(int num) {
super(num); System.out.println("子有参..."); } }
public class Demo06Extends { public static void main(String[] args) { Zi06 zi = new Zi06();
Zi06 zi2 = new Zi06(100); System.out.println(zi2.num); } }
|

2.4 继承中成员方法的访问特点(掌握)
定义一个父类,代码如下
1 2 3 4 5 6 7
| public class F { String name = "父类名字";
public void print1(){ System.out.println("==父类的print1方法执行=="); } }
|
再定义一个子类,代码如下。有一个同名的name成员变量,有一个同名的print1成员方法;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Z extends F { String name = "子类名称"; public void showName(){ String name = "局部名称"; System.out.println(name); }
@Override public void print1(){ System.out.println("==子类的print1方法执行了="); }
public void showMethod(){ print1(); } }
|
接下来写一个测试类,观察运行结果,我们发现都是调用的子类变量、子类方法。
1 2 3 4 5 6 7 8
| public class Test { public static void main(String[] args) { Z z = new Z(); z.showName(); z.showMethod(); } }
|
- 如果子类和父类出现同名变量或者方法,优先使用子类的;
- 此时如果一定要在子类中使用父类的成员,可以加this或者super进行区分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Z extends F { String name = "子类名称";
public void showName(){ String name = "局部名称"; System.out.println(name); System.out.println(this.name); System.out.println(super.name); }
@Override public void print1(){ System.out.println("==子类的print1方法执行了="); }
public void showMethod(){ print1(); super.print1(); } }
|
2.5 super内存图

new子 会在子类内存中开辟一块super
不同对象new出来的super不影响 是在new子的堆里面
2.6 方法重写
当子类觉得父类方法不好用,或者无法满足父类需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
- 1、方法重写概念
- 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)
- 2、方法重写的应用场景
- 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
- 3、Override注解
- 用来检测当前的方法,是否是重写的方法,起到【校验】的作用
重写后,方法的访问遵循就近原则。
写一个A类作为父类,定义两个方法print1和print2
1 2 3 4 5 6 7 8
| public class A { public void print1(){ System.out.println("111"); } public void print2(int a, int b){ System.out.println("111111"); } }
|
再写一个B类作为A类的子类,重写print1和print2方法。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class B extends A{ @Override public void print1(){ System.out.println("666"); }
@Override public void print2(int a, int b){ System.out.println("666666"); } }
|
接下来,在测试类中创建B类对象,调用方法
1 2 3 4 5 6 7
| public class Test { public static void main(String[] args) { B b = new B(); b.print1(); b.print2(2, 3); } }
|
执行代码,我们发现真正执行的是B类中的print1和print2方法
2.7 方法重写的注意事项
- 私有方法不能被重写(父类私有成员子类是不能继承的)
- 子类方法访问权限不能更低(public > 默认 > 私有)
- 静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法
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
| public class Fu { private void show() { System.out.println("Fu中show()方法被调用"); }
void method() { System.out.println("Fu中method()方法被调用"); } }
public class Zi extends Fu {
@Override private void show() { System.out.println("Zi中show()方法被调用"); } @Override private void method() { System.out.println("Zi中method()方法被调用"); }
@Override public void method() { System.out.println("Zi中method()方法被调用"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| public class Zi extends Fu{ int a = 1; public void show(){ int a = 2; System.out.println(a); System.out.println(this.a); System.out.println(super.a); } }
|
总结一下
1 2 3 4 5 6 7 8 9 10 11 12 13
| 访问本类成员: this.成员变量 //访问本类成员变量 this.成员方法 //调用本类成员方法 this() //调用本类空参数构造器 this(参数) //调用本类有参数构造器
访问父类成员: super.成员变量 //访问父类成员变量 super.成员方法 //调用父类成员方法 super() //调用父类空参数构造器 super(参数) //调用父类有参数构造器
注意:this和super访问构造方法,只能用到构造方法的第一句,否则会报错。
|
2.8权限修饰符
在本类中可以访问到哪些权限修饰的方法。
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
| public class Fu { private void privateMethod(){ System.out.println("==private=="); }
void method(){ System.out.println("==缺省=="); }
protected void protectedMethod(){ System.out.println("==protected=="); }
public void publicMethod(){ System.out.println("==public=="); }
public void test(){ privateMethod(); method(); protectedMethod(); publicMethod(); } }
|
接下来,在和Fu类同一个包下,创建一个测试类Demo,演示同一个包下可以访问到哪些权限修饰的方法。
1 2 3 4 5 6 7 8 9
| public class Demo { public static void main(String[] args) { Fu f = new Fu(); f.method(); f.protectedMethod(); f.publicMethod(); } }
|
接下来,在另一个包下创建一个Fu类的子类,演示不同包下的子类中可以访问哪些权限修饰的方法。
1 2 3 4 5 6 7 8 9
| public class Zi extends Fu { public void test(){ protectedMethod(); publicMethod(); } }
|
接下来,在和Fu类不同的包下,创建一个测试类Demo2,演示一下不同包的无关类,能访问到哪些权限修饰的方法;
1 2 3 4 5 6 7 8 9 10 11 12
| public class Demo2 { public static void main(String[] args) { Fu f = new Fu(); f.publicMethod();
Zi zi = new Zi(); } }
|
一般情况下
//成员变量私有
//方法公开
2.8 继承综合案例
1 2 3 4
| 假如我们要定义如下类: 讲师类,班主任类和就业指导类,分析如下: 1. 讲师类 属性:姓名,年龄,工资 行为:展示信息,讲课 2. 班主任类 属性:姓名,年龄,工资 行为:展示信息,管理班级 3. 就业指导类 属性:姓名,年龄,工资 行为:吃饭,展示信息,辅导就业
|
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 47 48 49 50 51 52 53 54 55 56 57 58
|
public class Employee { private String name; private int age; private int salary;
public void showInfo() { System.out.println("姓名: " + name + ", 年龄: " + age + ", 薪资: " + salary); }
public void work() { System.out.println("员工: " + name + ", 正在努力的工作~"); }
public Employee() { }
public Employee(String name, int age, int salary) { this.name = name; this.age = age; this.salary = salary; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public int getSalary() { return salary; }
public void setSalary(int salary) { this.salary = salary; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class Teacher extends Employee { public Teacher() { }
public Teacher(String name, int age, int salary) { super(name, age, salary); } @Override public void work() { System.out.println("讲师: " + getName() + ", 正在努力的讲解面向对象(OOP)编程~"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public class Manager extends Employee { public Manager() { }
public Manager(String name, int age, int salary) { super(name, age, salary); }
@Override public void work() { System.out.println("班主任: " + getName() + ", 正在严格的管理班级~"); } }
|
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
|
public class Demo06ExtendsTest { public static void main(String[] args) { Teacher t = new Teacher(); t.setName("响哥哥"); t.setAge(18); t.setSalary(66666); t.showInfo(); t.work();
Manager m = new Manager("苗苗姐", 16, 88888); m.showInfo(); m.work(); } }
|
3.抽象类
3.1抽象类的概述
当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
3.2抽象类的特点(记忆)
抽象类和抽象方法必须使用 abstract 关键字修饰
1 2 3 4 5
| public abstract class 类名 {}
public abstract void eat();
|
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化*(抽象类不能直接创建对象,只能被继承使用)
你不能直接造出一个 “动物”,因为它没有具体形态、没有具体行为;
你只能造出猫、狗这种具体的动物。
这就是 抽象类不能实例化 的意思。
综上所述
1 2 3
| 1.用抽象类可以把父类中相同的代码,包括方法声明都抽取到父类,这样能更好的支持多态,一提高代码的灵活性。
2.不知道系统未来具体的业务实现时,我们可以先定义抽象类,将来让子类去实现,以方便系统的扩展。
|
3.3抽象类的案例(应用)
3.4 抽象类综合案例
案例需求
1 2 3 4 5 6 7 8 9 10
| 智晟科技有很多员工(Employee),按照工作内容不同分教研部员工(Teacher)和行政部员工(AdminStaff) 教研部根据教学的方式不同又分为讲师(Lecturer)和助教(Tutor) 行政部根据负责事项不同,有分为维护专员(Maintainer),采购专员(Buyer) 公司的每一个员工都编号,姓名和其负责的工作 工作内容: 讲师: 工号为 666 的讲师 乔峰 在讲课 助教: 工号为 668的助教 段誉 在帮助学生解决问题 维护专员: 工号为 686 的维护专员 柳岩 在解决不能共享屏幕问题 采购专员: 工号为 888 的采购专员 景甜 在采购音响设备 提示:赋值可以用set方法或者构造方法
|
实现步骤
1 2 3 4
| 1.抽取共有的id name work()方法,形成员工类父类 2.教研部类和行政部类继承员工类 3.定义讲师类和助教类继承教研部类,重写work方法 4.定义维护类和采购类,继承行政类,重写work方法
|
代码实现
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
| public abstract class Employee { private String id; private String name; public abstract void work();
public Employee() { super(); } public Employee(String id, String name) { super(); this.id = id; this.name = name; }
public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
|
1 2 3 4 5 6 7 8 9
| public abstract class Teacher extends Employee{ public Teacher() { }
public Teacher(String id, String name) { super(id, name); } }
|
1 2 3 4 5 6 7 8 9
| public abstract class AdminStaff extends Employee{ public AdminStaff() { }
public AdminStaff(String id, String name) { super(id, name); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Lecturer extends Teacher{ public Lecturer() { super(); } public Lecturer(String id, String name) { super(id, name); }
public void work() { System.out.println("工号为 "+getId()+" 的讲师 "+getName()+" 在讲课"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Tutor extends Teacher{ public Tutor() { super(); }
public Tutor(String id, String name) { super(id, name); } public void work() { System.out.println("工号为 "+getId()+"的助教 "+getName()+" 在帮助学生解决问题"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Maintainer extends AdminStaff{ public Maintainer() { super(); }
public Maintainer(String id, String name) { super(id, name); } public void work() { System.out.println("工号为 "+getId()+" 的维护专员 "+getName()+" 在解决不能共享屏幕问题"); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Buyer extends AdminStaff{ public Buyer() { super(); }
public Buyer(String id, String name) { super(id, name); } public void work() { System.out.println("工号为 "+getId()+" 的采购专员 "+getName()+" 在采购音响设备"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Test { public static void main(String[] args) {
Lecturer l = new Lecturer("666", "乔峰");
l.work();
Tutor t = new Tutor("668", "段誉");
t.work();
Maintainer m = new Maintainer("686", "柳岩");
m.work();
Buyer b = new Buyer("888", "景甜");
b.work(); } }
|
3.5 模板设计模式
学习一种利用抽象类实现的一种设计模式。先解释下一什么是设计模式?
设计模式是解决某一类问题的最优方案。
那模板方法设计模式解决什么问题呢?模板方法模式主要解决方法中存在重复代码的问题
比如A类和B类都有sing()方法,sing()方法的开头和结尾都是一样的,只是中间一段内容不一样。此时A类和B类的sing()方法中就存在一些相同的代码。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public abstract class MoBan { public final void WriteComposition(){ System.out.println("我的爸爸:"); this.context(); System.out.println("啊~~~这就是我的爸爸!"); }
public abstract void context(); }
|
1 2 3 4 5 6
| public class Tom extends MoBan{ @Override public void context() { System.out.println("记忆中,那是一个秋天,风儿那么缠绵~爸爸骑车接我放学,我的脚卡在了车链中,爸爸蹬不动,于是,他就站起来蹬......"); } }
|
1 2 3 4 5 6
| public class Test { public static void main(String[] args) { Tom tom = new Tom(); tom.WriteComposition(); } }
|
综上所述:模板方法模式解决了多个子类中有相同代码的问题。
1 2 3
| 第1步:定义一个抽象类,把子类中相同的代码写成一个模板方法。 第2步:把模板方法中不能确定的代码写成抽象方法,并在模板方法中调用。 第3步:子类继承抽象类,只需要父类抽象方法就可以了。
|
//接口和抽象类都不能创建对象
4. final关键字
4.1 final的概述
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
| final关键字: 代表最终的,不可改变 可以修饰的内容:
1.类: 不可以被继承,不能够有子类 看: MyString和MyArrayList 称之为太监类: 不能有子类,但是有父类 2.方法: 不能被子类覆盖重写 3: 变量 只能赋值一次,不可以进行第二次赋值,变量的值是不可以发生改变的 常量 - 基本数据类型 - 数据值不能改变 - 引用数据类型 - 地址值不能改变 内容可变 - 如果是局部变量,只需要保证在方法内只赋值1次即可 - 如果是成员变量,必须保证在对象创建成功之后,给所有的final变量完成一次赋值; 成员变量: 看MyClass03 认为默认值无效,要么显式赋值,要么构造方法中赋值 (1)定义未赋值: 所有构造方法中,必须完成对final修饰的变量的赋值 所有成员方法中,不能修改final修饰的变量的值
(2)定义并赋值: 所有构造方法/成员方法中,不能修改final修饰的变量的值
|
4.2 final修饰的类的特点
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
| final修饰的类的特点 该类不可以被继承,不能有子类
public final class Fu01 extends Object { public void method() { System.out.println("Fu01...method..."); } public void show() { System.out.println("Fu01...show..."); } }
public class Zi01 { }
public class MyString { }
public class MyArrayList extends ArrayList { public MyArrayList(int initialCapacity) { super(initialCapacity); }
public MyArrayList() { }
public MyArrayList(Collection c) { super(c); } }
|
4.3 final修饰的方法的特点
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
| 被final修饰的方法: 不能被子类覆盖重写
public class Fu02 { public final void method() { System.out.println("Fu02...method..."); }
public void show() { System.out.println("Fu02...show..."); } }
public class Zi02 extends Fu02 {
@Override public final void show() { System.out.println("Zi02...show..."); } }
public class Demo02FinalMethod { public static void main(String[] args) { Zi02 zi02 = new Zi02();
zi02.method(); zi02.show(); } }
|
4.4 final修饰的变量的特点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| final修饰变量: 1.特点: 只能赋值一次,不可以进行第二次赋值,变量的值是不可以发生改变的 常量 2.修饰局部变量(方法内部定义的变量): (1)基本类型: 基本类型变量中存储的具体的数字是不可以被改变的
(2)引用类型: 存储的对象的地址值,被final修饰后,说明变量存储的对象的地址值是不可以被改变的 但是该地址代表的内存空间中的`内容`是可以改变的 3.成员变量: 看MyClass03 认为默认值无效,要么显式赋值,要么构造方法中赋值 (1)定义未赋值: 所有构造方法中,必须完成对final修饰的变量的赋值 所有成员方法中,不能修改final修饰的变量的值
(2)定义并赋值: 所有构造方法/成员方法中,不能修改final修饰的变量的值
|
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| public class Demo03FinalVar { public static void main(String[] args) { final int num = 10; System.out.println(num);
final int num2; num2 = 100; System.out.println(num2);
final Student stu = new Student("张三", 18); stu.show();
stu.setName("李四"); stu.setAge(28);
stu.show();
final int[] arr = new int[]{10,20,30}; System.out.println(Arrays.toString(arr));
for (int i = 0; i < arr.length; i++) { arr[i] *= 10; } System.out.println(Arrays.toString(arr)); } }
public class Demo03FinalVar2 { String name; final int num; final int num2 = 20; public Demo03FinalVar2() { num = 10; } public Demo03FinalVar2(String name) { this.name = name; num = 10; } public void show() { } }
|
final可变地址中的内容

5. Object类
5.1 Object类介绍
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
| 1.java.lang.Object类的介绍: 是整个类的体系结构中的最顶层父类,是所有类的最终父类,它里面定义的方法,其它类都有. 类Object是类层次结构的根类。每个类都使用Object作为超类。 所有对象(包括数组)都实现这个类的方法。 2.常用方法: (1)public String toString(): 返回调用方法的对象的字符串表示形式 字符串形式: 理解位返回对象的地址值,类的全名称 + @ + 16进制的int数字 内部源代码分析: public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } getClass().getName(): 获取类的全名称 Integer.toHexString(hashCode()): 把对象的哈希值转换成16进制的int数字 (2)public boolean equals(Object obj): 比较调用方法的对象和方法参数对象是否相等 true: 说明相等 false: 说明不相等 默认比较对象的地址值,然而只要new对象的地址值就是不相同 内部源代码分析: public boolean equals(Object obj) { return (this == obj); } this代表: 调用方法的对象 obj代表: 调用方法时传递的参数对象 ==: 在比较两个对象的内存地址值是否相同 (3)重写toString方法 目的: 返回对象的内容,而不是地址值 快捷键: alt + insert --> toString --> 选择成员变量 --> ok (4)重写equals方法: 目的:比较对象的内容,而不是地址值 快捷键: alt + insert --> equals && hashCode() --> 选择成员变量 --> ok
|
5.2 Object类的代码演示
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
| public class Demo01Object { public static void main(String[] args) { Object obj1 = new Object(); String s1 = obj1.toString(); System.out.println(s1);
System.out.println(obj1.toString()); System.out.println(obj1);
Object obj2 = new Object();
System.out.println(obj1 == obj2);
System.out.println(obj1.equals(obj2)); } }
System.out.println(obj1.getClass().getName() + "@" + Integer.toHexString(obj1.hashCode()));
|
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
| public class Student extends Object { private String name; private int age; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; }
@Override public boolean equals(Object o) { if (this == o) return true;
if (o == null || !(o instanceof Student)) return false; Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name); } }
|
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
| public class Demo01ToStringAndEquals { public static void main(String[] args) { Student stu1 = new Student("张三", 18);
System.out.println(stu1.toString()); System.out.println(stu1); Student stu2 = new Student("李四", 38); Student stu3 = new Student("张三", 18);
System.out.println(stu1.equals(stu2)); System.out.println(stu1.equals(stu3)); System.out.println(stu2.equals(stu3)); } }
|
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o; if (age != student.age) return false; return Objects.equals(name, student.name); }
@Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; }
public class Test { public static void main(String[] args) { Student student = new Student("张三",18); System.out.println(student); System.out.println(student.toString()); Student student2 = new Student("李四",18); System.out.println(student2);
System.out.println("--------------------"); Student student3 = new Student("李四",18); System.out.println(student3); System.out.println(student2.equals(student3));
} }
public class TestA { public static void main(String[] args) { A a1 = new A("aaa",123); System.out.println(a1.hashCode()); System.out.println(a1.hashCode()); System.out.println(a1.hashCode()); A a2 = new A("aaa",123); System.out.println(a1.equals(a2)); System.out.println(a2.hashCode());
System.out.println("------------------------"); String s1 = "重地"; String s2 = "通话"; System.out.println(s1.equals(s2)); System.out.println(s1.hashCode()); System.out.println(s2.hashCode());
String s3 = new String("abc"); String s4 = "abc"; System.out.println("----------------------"); System.out.println(s3.equals(s4)); System.out.println(s3.hashCode()); System.out.println(s4.hashCode()); } }
|
5.3 输出语句是Object对象的原理分析
