1. 子类对象实例化的全过程(了解)
- 从结果上来看
从结果上来看:就体现为类的继承性
- 创建子类对象以后,子类的对象就获取了其父类,以及父类的父类,。。。。中的结构:属性、方法。
- 在权限允许的情况下,通过子类对象就可以调用父类中继承过来的结构。
- 从过程上来看
从过程上来看:
- 当我们创建子类对象时,调用子类的构造器。子类的构造器一定会直接或间接的调用其父类的构造器,其父类的
- 构造器也同样的直接或间接的调用它的父类的构造器,以此类推,一定会调用到java.lang.Object类的Object()
- 的构造器为止。正因为调用了这些类的构造器,则会在内存中加载这些类,并提供给子类对象必要的结构来使用。
- 注意点:
注意:虽然调用了父类的构造器,但是内存中自始至终,只创建了当前子类的对象。
2. oop的特征三:多态性
2.1多态性(向上转型)
面向对象的特征之三:多态性
- 1.多态的理解:一种事物的多种形态
- 2. 子类对象的多态性:子类的对象赋给父类的引用 (或父类的引用指向子类的对象)
- 3.在多态的前提下,通过父类的引用调用方法只能是父类中声明的方法;(编译期)
其次,真正运行时,执行的是子类重写父类的方法。(运行期)
总结:编译看左边,运行看右边 (虚方法调用)
- 4. 多态的使用前提:① 类的继承关系 ② 子类重写父类的方法
- 5. 类的多态性指的“编译看左边,运行看右边”不适用于属性
- 储备代码
public class Person {
String name;
int age;
int id = 1001;
public void eat(){
System.out.println("人吃饭");
}
public void walk(){
System.out.println("人走路");
}
}
public class Man extends Person {
boolean isSmoking;
int id = 1002;
public void eat(){
System.out.println("男人应该多吃肉,长肌肉");
}
public void walk(){
System.out.println("男人西装笔挺的走路");
}
public void earnMoney(){
System.out.println("男人赚钱养家");
}
}
public class Woman extends Person {
boolean isBeauty;
public void eat(){
System.out.println("女人选择少吃,减肥~");
}
public void walk(){
System.out.println("女人选择穿高跟鞋窈窕的走路");
}
public void goShopping(){
System.out.println("女人选择逛街购物");
}
}
- 测试多态性
public class PersonTest {
public static void main(String[] args) {
//我们熟悉的场景:不属于多态性
Person p1 = new Person();
p1.eat();
Man m1 = new Man();
m1.eat();
m1.earnMoney();
int m = 10;
int n = m;
//基本数据类型中存在数据类型提升规则
long l = m;
System.out.println("##########多态的核心内容:###########");
//子类对象的多态性:子类的对象赋给父类的引用 (或父类的引用指向子类的对象)
Person p2 = new Man();
Person p3 = new Woman();
//多态的应用:虚方法调用:在多态的前提下,通过父类的引用调用方法只能是父类中声明的方法;(编译期)
// 其次,真正运行时,执行的是子类重写父类的方法。(运行期)
p2.eat();
p2.walk();
// p2.earnMoney();//编译不通过
//属性不存在多态性
System.out.println(p2.id);//1001
}
}
- 多态性的好处,即多态的应用举例
- 举例1:
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
Dog dog = new Dog();
test.func(dog);
test.func(new Cat());
}
public void func(Animal animal){ // Animal animal = new Dog();
animal.eat();
animal.jump();
//编译不通过
// animal.shout();
if(animal instanceof Dog){
Dog dog = (Dog)animal;
dog.shout();
}else if(animal instanceof Cat){
Cat cat = (Cat)animal;
cat.catchFish();
}
}
//由于多态性的出现,就不需要定义如下的方法了
// public void func(Dog dog){
// dog.eat();
// dog.jump();
// }
//
// public void func(Cat cat){
// cat.eat();
// cat.jump();
// }
//
// //....
}
class Animal{
public void eat(){
System.out.println("动物进食");
}
public void jump(){
System.out.println("动物跳");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void jump(){
System.out.println("狗急跳墙");
}
public void shout(){
System.out.println("狗吠");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃老鼠");
}
public void jump(){
System.out.println("猫跳");
}
public void catchFish(){
System.out.println("猫抓鱼");
}
}
- 举例2:
public boolean equals(Object obj){}
- 举例3:
class Account{
}
class CheckingAccount extends Account{}//信用卡账户
class SavingAccount extends Account{}//储蓄卡账户
//...
class Customer{
Account acct;
public void setAccount(Account acct){ //Account acct = new SavingAccount();
this.acct = acct;
}
}
2.2 向下转型
Person p4 = new Man();
// p4.earnMoney();//编译不通过
// System.out.println(p4.isSmoking);//编译不通过
//先明确:创建的子类Man的实例,在内存中是存在其特有的属性和方法的。
//那如何调用?需要使用强转符:()
Man m2 = (Man)p4;
System.out.println(m2.isSmoking);
m2.earnMoney();
/*
进行强转时,可能出现ClassCastException异常。
建议在强转前,判断是否可以是指定的子类的类型。使用instanceof实现
*/
// Woman w1 = (Woman)p4;
// w1.goShopping();
/*
* 格式: a instanceof A :判断对象a是否是类A的实例
* 如果是,则返回true;如果不是,返回false。
*
* 推论:如果a instanceof A返回true,则 a instanceof SuperA也返回true。其中SuperA是类A的父类
*
* */
if(p4 instanceof Woman){
Woman w1 = (Woman)p4;
w1.goShopping();
}else{
System.out.println("不好意思,认错了!");
}
if(p4 instanceof Man){
System.out.println("我是一个男人");
}
if(p4 instanceof Person){
System.out.println("我是一个人");
}
if(p4 instanceof Object){
System.out.println("我是一个Object");
}
- 小结
2.3 练习
- 练习1
/**
*
* 建立InstanceTest 类,在类中定义方法method(Person e);
* 在method中:
* (1)根据e的类型调用相应类的getInfo()方法。
* (2)根据e的类型执行:
* 如果e为Person类的对象,输出:
* “a person”;
* 如果e为Student类的对象,输出:
* “a student”
* “a person ”
* 如果e为Graduate类的对象,输出:
* “a graduated student”
* “a student”
* “a person”
*
*/
public class InstanceTest {
public static void main(String[] args) {
InstanceTest test = new InstanceTest();
test.method(new Student());
System.out.println();
test.method(new Person());
}
public void method(Person e){
System.out.println(e.getInfo());
if(e instanceof Graduate){
System.out.println("a graduated student");
}
if(e instanceof Student){
System.out.println("a student");
}
if(e instanceof Person){
System.out.println("a person");
}
}
}
class Person {
protected String name = "person";
protected int age = 50;
public String getInfo() {
return "Name: " + name + "\n" + "age: " + age;
}
}
class Student extends Person {
protected String school = "pku";
public String getInfo() {
return "Name: " + name + "\nage: " + age
+ "\nschool: " + school;
}
}
class Graduate extends Student {
public String major = "IT";
public String getInfo() {
return "Name: " + name + "\nage: " + age
+ "\nschool: " + school + "\nmajor:" + major;
}
}
- 练习2
/**
* 几何图形类
*
*/
public class GeometricObject {
protected String color;//颜色
protected double weight;//权重
// protected GeometricObject(){}
protected GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double findArea(){
return 0;
}
}
public class Circle extends GeometricObject {
private double 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 3.14 * radius * radius;
}
}
public class MyRectangle extends GeometricObject {
private double width;//宽
private double height;//高
public MyRectangle(double width, double height,String color, double weight) {
super(color, weight);
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double findArea(){
return width * height;
}
}
/**
* 定义一个测试类GeometricObjectTest,
* 编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),
* 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
*
*/
public class GeometricObjectTest {
public static void main(String[] args) {
GeometricObjectTest test = new GeometricObjectTest();
Circle circle = new Circle(2.3, "red", 1.0);
test.displayGeometricObject(circle);
MyRectangle myRectangle = new MyRectangle(3.4, 2.3, "blue", 2.0);
test.displayGeometricObject(myRectangle);
test.equalsArea(circle,myRectangle);
}
public void equalsArea(GeometricObject o1,GeometricObject o2){
boolean isEqual = o1.findArea() == o2.findArea();
if(isEqual){
System.out.println("面积相等");
}else{
System.out.println("面积不相等");
}
}
public void displayGeometricObject(GeometricObject o ){
System.out.println("几何图形的面积为:" + o.findArea());
}
}
3. Object类及内部的常用方法
3.1 Object的认识
* 1. Object类是所有Java类的根父类
* 2. 如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
* 3. 重点讲解equals()和toString()
* * 面试题: 区分 finalize \ final \ finally
3.2 equals()的使用
- 基本内容
* 1. == 的使用
* ① 使用范围:基本数据类型、引用数据类型
* ② 使用在基本数据类型上,判断两个变量存储的数据值是否相等
* 使用在引用数据类型上,判断两个引用的地址值是否相等。(判断两个引用是否指向内存中的同一个对象)
* * 对比:equals()只能使用在引用数据类型的变量上。
* * 2. equals()的使用
* 2.1 java.lang.Object类中equals()的定义:
* public boolean equals(Object obj) {
* return (this == obj);
* }
* 2.2 当自定义类没有重写equals()时,调用的就是Object类中定义的equals(),比较两个引用的地址值是否相等
* * 2.3 像String\日期类 Date \ File\包装类等已经重写了Object类中定义的equals(),用于判断两个对象
* 的“实体内容”是否相等。
* * 2.4 开发中,对应自定义类,常常也需要重写equals(),用于判断两个对象的“实体内容”是否相等。
* * * 面试题: 区分 == 和 equals()
- 如何重写equals()
public class User {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
//手写的:
// @Override
// public boolean equals(Object obj) {
// if(this == obj){
// return true;
// }
// if(obj instanceof User){
// User u = (User)obj;
// //比较两个对象的属性是否都相等
if(this.age == u.age && this.name.equals(u.name)){
return true;
}
return false;
//
// //简化为:
// return this.age == u.age && this.name.equals(u.name);
// }
//
// return false;
// }
//自动生成:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (age != user.age) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
}
3.3 toString()的使用
- 基本知识
* 0. 当我们print(对象名)时,实际上与print(对象名.toString())是一样的。
*
* 1. Object类中toString()的定义:
* public String toString() {
* return getClass().getName() + "@" + Integer.toHexString(hashCode());
* }
* 2. 自定义类在没有重写toString()时,就是默认调用Object类中的toString(),返回当前对象的类型和内存中的地址值。
*
* 3.像String\日期类 Date \ File\包装类等已经重写了Object类中定义的toString(),返回当前对象中
* 实体内容的信息
*
* 4. 对于自定义类,如果希望调用toString()时,显示对象的实体内容的信息,则可以考虑重写toString()
- 重写toString()
public class User {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
// @Override
// public String toString() {
// return "User{ name : " + name + ",age : " + age +"}";
// }
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 测试
public class ToStringTest {
public static void main(String[] args) {
User u1 = new User("Tom",12);
System.out.println(u1.toString());//com.atguigu.java2.User@1540e19d --> User{ name : Tom,age : 12}
System.out.println(u1);//com.atguigu.java2.User@1540e19d --> User{ name : Tom,age : 12}
String str1 = new String("hello");
String str2 = "abc";
System.out.println(str1.toString());
System.out.println(str2);
}
}
4. 课后练习