6. 多态
6.1 例子引出多态话题
Animal 类
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Dog 类(继承Animal 类)
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
Cat 类(继承Animal 类)
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
Food 类
public class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Bone 类(继承 Food 类)
public class Bone extends Food {
public Bone(String name) {
super(name);
}
}
Fish 类(继承 Food 类)
public class Fish extends Food {
public Fish(String name) {
super(name);
}
}
Master 类
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//主人给小狗 喂食 骨头
public void feed(Dog dog, Bone bone) {
System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
}
//主人给小猫 喂食 鱼
public void feed(Cat cat, Fish fish) {
System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.getName());
}
}
Poly 类(main)
public class Poly {
public static void main(String[] args) {
Master tom = new Master("汤姆");
Dog dog = new Dog("中华田园犬");
Bone bone = new Bone("骨头");
tom.feed(dog, bone);
System.out.println("===== 0_0 =====");
Cat cat = new Cat("小花猫");
Fish fish = new Fish("鱼");
tom.feed(cat, fish);
}
}
如果动物很多,食物很多
feed方法很多,不利于管理和维护
问题: 代码的复用性不高,而且不利于代码维护
解决: 利用多态
6.2 多[多种]态[状态]基本介绍
方法或对象具有多种形态
是面向对象的第三大特征,多态是建立在封装和继承基础之上的
方法的多态
public class PloyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//传入不同的参数,会调用不同的 sum 方法,体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sum(10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
}
}
class B { //父类
public void say() {
System.out.println("B say() 方法被调用");
}
}
class A extends B { //子类
public int sum(int n1, int n2) { //和下面的 sum 构成重载
return n1 + n2;
}
public int sum(int n1, int n2, int n3) {
return n1 + n2;
}
public void say() {
System.out.println("A say() 方法被调用");
}
}
对象的多态
(面向对象的核心)
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型是可以变化的
- 编译类型看定义时 = 号的左边,运行类型看 = 号的右边
Animal animal = new Dog(); //【 animal 编译类型时Animal,运行类型时 Dog 】
animal = new Cat(); //【 animal 运行类型变成了 Cat,编译类型仍然时 Animal 】
public class Animal {
public void cry() {
System.out.println("Animal cry() 动物在叫...");
}
}
public class Dog extends Animal {
public void cry() {
System.out.println("Dog cry() 小狗汪汪叫...");
}
}
public class Cat extends Animal {
public void cry() {
System.out.println("Cat cry() 小猫喵喵叫...");
}
}
public class PolyObject {
public static void main(String[] args) {
//体验对象多态特点
Animal animal = new Dog(); //animal 编译类型时Animal,运行类型时 Dog
animal.cry(); //小狗汪汪叫
//运行时,执行该行时,animal运行类型时Dog,所以 cry 就是 Dog 的 cry
//animal 运行类型变成了 Cat,编译类型仍然时 Animal
animal = new Cat();
animal.cry(); //小猫喵喵叫
}
}
多态基本学习
在 6.1 的例子进行改进,添加 Pig 类 和 Rice 类
并在 Master 类改进,利用多态使得用一个方法将所有的 动物类 和 食物类 的行为统一实现
Pig 类(继承 Animal 类)
public class Pig extends Animal {
public Pig(String name) {
super(name);
}
}
Rice 类(继承 Food 类)
public class Rice extends Food {
public Rice(String name) {
super(name);
}
}
Master 类
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//使用多态机制,可以同意的管理主人喂食的问题
//animal 编译类型是Animal,可以指向(接收)Animal子类的对象
//food 编译类型是 Food,可以指向(接收) Food子类对象
public void feed(Animal animal, Food food) {
System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
}
//主人给小狗 喂食 骨头
//public void feed(Dog dog, Bone bone) {
// System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
//}
//主人给小猫 喂食 鱼
//public void feed(Cat cat, Fish fish) {
// System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.getName());
//}
}
Poly 类
public class Poly {
public static void main(String[] args) {
Master tom = new Master("汤姆");
Dog dog = new Dog("中华田园犬");
Bone bone = new Bone("骨头");
tom.feed(dog, bone);
System.out.println("===== 0_0 =====");
Cat cat = new Cat("小花猫");
Fish fish = new Fish("鱼");
tom.feed(cat, fish);
System.out.println("===== 0_0 =====");
//添加 给小猪喂米饭
Pig pig = new Pig("小花猪");
Rice rice = new Rice("米饭");
tom.feed(pig, rice);
}
}
只用一个方法就可以实现多种 动物类 和 食物类 的动作
6.3 向上转型
多态的前提是:两个对象(类)存在继承关系
多态的向上转型
- 本质:父类的引用指向了子类的对象
- 语法:父类类型 引用名 = new 子类类型();
- 特点:编译类型看左边,运行类型看右边。
- 可以调用父类中的所有成员(需遵守访问权限),
- 不能调用子类中特有成员;
- 最终运行效果看子类的具体实现
Animal 类
public class Animal {
String name = "动物";
int age = 10;
public void sleep() {
System.out.println("睡觉");
}
public void run() {
System.out.println("跑步");
}
public void eat() {
System.out.println("吃饭");
}
public void show() {
System.out.println("hello,你好");
}
}
Cat 继承 Animal 类
public class Cat extends Animal {
public void eat() { //方法重写
System.out.println("猫吃鱼");
}
public void catchMouse() { //Cat 特有方法
System.out.println("猫抓老鼠");
}
}
public class Poly {
public static void main(String[] args) {
//向上转型:父类的引用指向了子类的对象
//语法:引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat(); //可以,Object 也是 Cat 的父类
//向上转型调用方法的规则如下:
//1.可以调用父类中的所有成员(需遵守访问权限)
//2.但是不能调用子类的特有的成员
//2.因为在编译阶段,能调用哪些成员,是山编译类型来决定的
//animal.catchMouse();错误
//4.最终运行效果看子类的具体实现,最终运行效果看子类的具体实现,即调用方法时,按照从子类开始查找方法
//然后调用,规则和方法调用规则一致
animal.eat(); //猫吃鱼
animal.run(); //跑步
animal.show(); //hello,你好
animal.sleep(); //睡觉
System.out.println("ok~");
}
}
6.4 向下转型
多态的向下转型
- 语法:子类类型 引用名 = (子类类型)父类引用;
- 只能强转父类的引用,不能强转父类的对象
- 要求父类的引用必须指向的是当前目标类型的对象
- 当向下转型后,可以调用子类类型中所有的成员
public class Dog extends Animal { //Dog类 继承 Animal 类
}
public class Poly {
public static void main(String[] args) {
//向上转型:父类的引用指向了子类的对象
//语法:引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat(); //可以,Object 也是 Cat 的父类
//父类 Animal 可以调用子类 Cat 的 catchMouse 方法
//利用多态的向下转型
//
//1.语法:子类类型 引用名 = (子类类型)父类引用;
//
//cat 的编译类型时 Cat,运行类型时 Cat
Cat cat = (Cat)animal;
cat.catchMouse(); //猫抓老鼠
//2.要求父类的引用必须指向的是当前目标类型的对象
//
//Dog dog = (Dog)animal; //问题:可以这样写吗?
//不可以,因为 Dog 类 和 Cat类 不相关,不可以将猫强制转换成一只狗
//编译不报错,运行代码,会报错
System.out.println("ok~");
}
}
6.5 属性重写问题
属性没有重写之说!属性的值看编译类型
public class Poly {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Base base = new Sub();
System.out.println(base.count); //输出的是?看编译类型,输出10
Sub sub = new Sub();
System.out.println(sub.count); //输出的是?看编译类型,输出20
}
}
class Base { //父类
int count = 10; //属性
}
class Sub extends Base { //子类
int count = 20; //属性
}
instanceOf 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型
public class Poly02 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB); //输出的时真还是假?
//true
System.out.println(bb instanceof AA); //输出的时真还是假?
//true
AA aa = new BB();
System.out.println(aa instanceof AA); //输出的时真还是假?
//true
System.out.println(aa instanceof BB); //输出的时真还是假?
//true
Object obj = new Object();
System.out.println(obj instanceof AA); //false
String str = "hello";
//System.out.println(str instanceof AA); //直接编译报错
System.out.println(str instanceof Object); //true
}
}
class AA {} //父类
class BB extends AA {} //子类
6.6 练习
- 查看代码是否正确?
public class PolyExercise01 {
public static void main(String[] args) {
double d = 3.14;
long l = (long)d; //正确
System.out.println(l); //13
int in = 5; //正确
//boolean b = (boolean)in; //不对, booolean -> int
Object obj = "hello"; //可以,向上转型
String objStr = (String)obj; //可以,向下转型
System.out.println(objStr); //hello
Object objPri = new Integer(5); //可以,向上转型
//String str = (String)objPro; //错误ClassCastException,指向Integer的父类引用,转成String
Integer str1 = (Integer)objPri; //可以,向下转型
}
}
- 查看代码运行输出的是什么?
public class PolyExercise02 {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count); //20
s.display(); //20
Base b = s;
System.out.println(b == s); //true
System.out.println(b.count); //10
b.display(); //20
}
}
class Base { //父类
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base { //子类
int count = 20;
public void display() {
System.out.println(this.count);
}
}
6.7 Java 的动态绑定机制
Java重要特性:动态绑定机制
java 的动态绑定机制
- 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
public class DynamicBinding {
public static void main(String[] args) {
A a = new B(); //向上转型
System.out.println(a.sum()); //没注释前的输出的是? 40
//把子类的 sum() 方法注释后,输出的是?
//a 调用 sum() 方法,发现子类没有,
//因为继承机制,去父类找
//所以去子类 B找 sum() 方法
//但是子类的 sum() 方法被注释了
//因此到父类找到 sum() 方法
//但是 sum() 方法调用了 getI() 方法
//问题是 父类 和 子类 都有 getI() 方法
//现在该调用什么 父类 还是 子类的 getI() 方法
//
//动态绑定机制解决这个问题
//注意点:当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
//
//因为 a 的编译类型是 A,运行类型是 B
//所以到 父类 的 sum() 方法时,因为动态绑定机制,父类的sum() 方法去调用 子类 的 getI() 方法
//
//所以注释后的输出应该是 20 + 10 = 30
System.out.println(a.sum1()); //没注释前的输出的是? 30
//把子类的 sum1() 方法注释后,输出的是?
//
//注意点:当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
//
//所以子类没有sum1()
//去调用父类的 sum1()
//因为对象属性 i 时没有动态绑定机制,
//所以调用的时 父类的 i
//
//所以注释后的输出应该时 10 + 10 = 20
}
}
class A { //父类
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum1() {
return i + 10;
}
public int getI() {
return i;
}
}
class B extends A { //子类
public int i = 20;
//public int sum() {
// return i + 20;
//}
public int getI() {
return i;
}
//public int sum1(){
// return i + 10;
//}
}
6.8 多态的应用
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
应用实例:
现有一个继承结构如下:要求创建1个Person对象、2个Student对象和2个 Teacher 对象,统一放在数组中,并调用每个对象say方法
Person 父类
public class Person { //父类
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 String say() { //返回名字和年龄
return name + "\t" + age;
}
}
Student 子类
public class Student extends Person {
private double score;
public Student(String name, int age, double score) {
super(name,age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//重写父类 say()
public String say() {
return "老师 " + super.say() + " score = " + score;
}
}
Teacher 子类
public class Teacher extends Person {
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//重写父类的方法
public String say() {
return "学生 " + super.say() + " salary = " + salary;
}
}
PolyArry
public class PolyArry {
public static void main(String[] args) {
//应用实例:
//
//现有一个继承结构如下:要求创建1个Person对象、2个Student对象和2个 Teacher 对象,统一放在数组中,并调用每个对象say方法
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("jack", 18, 100);
persons[2] = new Student("smith", 19, 30.1);
persons[3] = new Teacher("scott", 30, 20000);
persons[4] = new Teacher("king", 50, 25000);
//循环遍历多态数组,调用 say()
for (int i = 0; i < persons.length; i++) {
//person[i]编译类型是 Person ,运行类型是是根据实际情况有JVM来判断
System.out.println(persons[i].say()); //动态绑定机制,会根据绑定的 运行类型 而调用 相关的 say() 方法
}
}
}
应用实例升级:
如何调用子类特有的方法,比如Teacher有一个 teach , Student有一个study 怎么调用?
Teacher 类
public class Teacher extends Person {
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//重写父类的方法
public String say() {
return "老师 " + super.say() + " salary = " + salary;
}
//特有方法
public void teach() {
System.out.println("老师 " + getName() + " 正在讲java课程...");
}
}
Student 类
public class Student extends Person {
private double score;
public Student(String name, int age, double score) {
super(name,age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//重写父类 say()
public String say() {
return "学生 " + super.say() + " score = " + score;
}
//特有方法
public void study() {
System.out.println("学生 " + getName() + " 正在学习...");
}
}
PolyArry 类
public class PolyArry {
public static void main(String[] args) {
//应用实例:
//
//现有一个继承结构如下:要求创建1个Person对象、2个Student对象和2个 Teacher 对象,统一放在数组中,并调用每个对象say方法
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("mary", 18, 100);
persons[2] = new Student("smith", 19, 30.1);
persons[3] = new Teacher("scott", 30, 20000);
persons[4] = new Teacher("king", 50, 25000);
//循环遍历多态数组,调用 say()
for (int i = 0; i < persons.length; i++) {
//person[i]编译类型是 Person ,运行类型是是根据实际情况有JVM来判断
System.out.println(persons[i].say()); //动态绑定机制,会根据绑定的 运行类型 而调用 相关的 say() 方法
//使用 类型判断 + 向下转型
if (persons[i] instanceof Student) { //判断person[i] 的运行类型是不是Student
Student student = (Student)persons[i]; //向下转型
student.study();
//
//也可以直接使用一条语句
//(Student)persons[i].study();
} else if (persons[i] instanceof Teacher) {
Teacher teacher = (Teacher)persons[i];
teacher.teach();
} else if (persons[i] instanceof Person) {
//不做任何操作
} else {
System.out.println("你的类型有误,请检查...");
}
}
}
}
代码的维护性更强
6.9 多态参数
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型
应用实例
定义员工类 Employee,包含姓名和月工资 [ private ] ,以及计算年工资 getAnnual 的方法。
普通员工 和 经理 继承了 员工,经理类多了奖金 bonus 属性 和 管理 manage 方法,普通员工类多了work方法,普通员工 和 经理类 要求分别重写 getAnnual 方法
测试类 中添加一个方法 showEmpAnnal(Employee e),实现获取任何员工对象的年工资,并在main方法中调用该方法[e.getAnnual()]
测试类 中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用 manage 方法
Employee 员工类
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
//得到年工资的方法
public double getAnnual() {
return 12 * salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
Worker 普通员工类
public class Worker extends Employee {
public Worker(String name, double salary) {
super(name, salary);
}
public void work() {
System.out.println("普通员工 " + getName() + " is working");
}
//重写方法
public double getAnnual() { //因为普通员工没有其他收入,则直接调用父类方法
return super.getAnnual();
}
}
Manager 经理类
public class Manager extends Employee {
private double bonus;
public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public void manage() {
System.out.println("经理 " + getName() + " is managing");
}
//重写获取年薪的方法
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
PolyParameter 测试类
public class PolyParameter {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manager milan = new Manager("milan", 5000, 200000);
PolyParameter polyParameter = new PolyParameter();
polyParameter.showEmpAnnual(tom);
polyParameter.showEmpAnnual(milan);
polyParameter.testWork(tom);
polyParameter.testWork(milan);
}
//测试类 中添加一个方法 showEmpAnnal(Employee e)
//实现获取任何员工对象的年工资,并在main方法中调用该方法[e.getAnnual()]
public void showEmpAnnual(Employee e) {
System.out.println(e.getAnnual()); //动态绑定机制
}
//测试类 中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用 manage 方法
public void testWork(Employee e) {
if (e instanceof Worker) {
((Worker) e).work(); //向下转型
} else if (e instanceof Manager) {
((Manager) e).manage(); //向下转型
} else {
System.out.println("不做操作...");
}
}
}
7. Object 类详解
7.1 equals 方法
== 运算符
- ==:既可以判断基本类型,又可以判断引用类型
- ==:如果判断基本类型,判断的是值是否相等
- ==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
public class Equals01 {
public static void main(String[] args) {
A a = new A();
A b = a;
A c = b;
System.out.println(a == c); //true
System.out.println(b == c); //true
B bObj = a;
System.out.println(bObj == c); //true
}
}
class B {}
class A extends B {}
equals 方法
-
equals:是Object类中的方法,只能判断引用类型
-
默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。
比如 lnteger,String
public class Equals02 {
public static void main(String[] args) {
Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 == integer2); //false,地址不一样
System.out.println(integer1.equals(integer2)); //true,内容相同
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); //false,地址>不一样,内容相同
System.out.println(str1.equals(str2)); //true
}
}
重写 equals 方法
应用实例:判断两个 Person 对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之false。
public class EqualsExercise01 {
public static void main(String[] args) {
Person person1 = new Person("jack", 10, '男');
Person person2 = new Person("jack", 10, '男');
//未进行 equals 方法重写
//System.out.println(person1.equals(person2)); //输出为假,因为子类没有进行重写 equals 方法
//所以要重写 Object 的 equals 方法
//重写 equals 方法后
System.out.println(person1.equals(person2)); //输出为真
}
}
class Person {
private String name;
private int age;
private char gender;
//重写 Object 的 equals 方法
public boolean equals(Object obj) {
//判断如果比较的两个对象是同一个对象,则直接返回true
if (this == obj) {
return true;
}
//类型判断
if (obj instanceof Person) { //是 Person,才比较
//进行 向下转型,因为需要得到 obj 的各个属性
Person p = (Person)obj;
return this.name.equals(p.name) && this.age ==p.age && this.gender == p.gender;
}
//如果不是 Person,则直接返回false
return false;
}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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 char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
查看输出的答案
public class EqualsExercise02 {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "hello";
Person p2 = new Person();
p2.name = "hello";
System.out.println(p1 == p2); //false
System.out.println(p1.name.equals(p2.name)); //true
System.out.println(p1.equals(p2)); //false
String s1 = new String("world");
String s2 = new String("world");
System.out.println(s1.equals(s2)); //true
System.out.println(s1 == s2); //false
}
}
class Person { //Person 类
public String name;
}
查看为真为假
public class EqualsExercise03 {
public static void main(String[] args) {
int it = 65;
float f1 = 65.0f;
System.out.println("65 和 65.0f 是否相等? " + (it == f1)); //T
char ch1 ='A' ;
char ch2 = 12;
System.out.println("65 和 ‘A’ 是否相等? " + (it == ch1)); //T
System.out.println("12 和 ch2 是否相等? " + (12 == ch2)); //T
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("str1 和 str2是否相等? " + (str1 == str2)); //F
System.out.println("str1 是否 equals str2? " + (str1.equals(str2))); //T
//System.out.println("hello" == new java.sql.Date()); //编译器直接报错。类型不同
}
}
7.2 hashCode 方法
小结:
- 提高具有哈希结构的容器的效率
- 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的
- 两个引用,如果指向的是不同对象,则哈希值是不一样的
- 哈希值主要根据地址号来的!,不能完全将哈希值等价于地址。
- 后面在集合,中hashCode如果需要的话,也会重写
public class HashCode {
public static void main(String[] args) {
AA aa = new AA();
AA aa2 = new AA();
AA aa3 = aa;
System.out.println("aa.hashCode() = " + aa.hashCode());
System.out.println("aa2.hashCode() = " + aa2.hashCode());
System.out.println("aa3.hashCode() = " + aa3.hashCode());
}
}
class AA {}
7.3 toString 方法
基本介绍
默认返回:全类名 + @ + 哈希值的十六进制,子类往往重写toString方法,用于返回对象的属性信息
public String toString() {
return getClass().getName() + "@" +Integer.toHexString(hashCode());
}
重写toString方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式
当直接输出一个对象时,toString方法会被默认的调用
public class ToString {
public static void main(String[] args) {
/**
*
* object的toString()源码
* (1)getClass().getName()类的全类名(包名+类名)
* (2)Integer.toHexString(hashCode())将对象的hashCode值转成16进制字符串
* public String toString() {
* return getClass().getName() + "@" +Integer.toHexString(hashCode());
* }
*
* */
Monster monster = new Monster("小妖怪", "巡山的", 1000);
System.out.println(monster.toString());
System.out.println("== 重写toString方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式 ==");
System.out.println(monster); //等价于 monster.toString()
}
}
class Monster {
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
//重写 toString 方法,输出对象的属性
@Override
public String toString() { //重写后,一般把对象的属性输出,也可以定制 toString 方法
return "Monster{" +
"name="+ name + '\n' +
", job=" + job + '\n' +
", sal=" + sal +
'}';
}
}
7.4 finalize 方法
- 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作
- 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
- 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法),也可以通过 System.gc() 主动触发垃圾回收机制
public class Finalize {
public static void main(String[] args) {
Car bnw = new Car("宝马");
bnw = null;
//这是 car 对象就是一个垃圾,垃圾回收器就会回收(销毁)对象,
//在销毁对象前,会调用该对象的 finalize 方法
//可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
//如果不重写 finalize,那么就会调用0bject类的 finalize,即默认处理
//如果重写了finalize,就可以实现自己的逻辑
//
//代码运行并没有打印重写 finalize 的信息
//垃圾回收器不是随时随地工作的
//
//垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法),也可以通过 System.gc() 主动触发垃圾回收机制
System.gc(); //主动调用垃圾回收器
System.out.println("程序退出...");
}
}
class Car {
private String name;
public Car(String name) {
this.name = name;
}
//重写 finalize
@Override
protected void finalize() throws Throwable {
System.out.println("销毁 汽车 ");
System.out.println("释放了某些资源");
}
}