写在前面
Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!!
如果小哥哥小姐姐们对我的文章感兴趣,请不要吝啬你们的小手,多多点赞加关注呀!❤❤❤ 爱你们!!!
目录
【往期回顾】
【习题总结】
1. 子类对象实例化过程
1.1 流程
1.2 子类对象实例化的全过程
1. 从结果上来看:(继承性)
- 子类继承父类以后,就获取了父类中声明的属性或方法。
- 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
2. 从过程上来看:
- 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,...
- 直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有
- 父类中的结构,子类对象才可以考虑进行调用。
- 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
/* * 子类对象实例化的全过程 * * 1. 从结果上来看:(继承性) * 子类继承父类以后,就获取了父类中声明的属性或方法。 * 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。 * * 2. 从过程上来看: * 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,... * 直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有 * 父类中的结构,子类对象才可以考虑进行调用。 * * * 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。 * */ class Creature { public Creature() { System.out.println("Creature无参数的构造器"); } } class Animal extends Creature { public Animal(String name) { System.out.println("Animal带一个参数的构造器,该动物的name为" + name); } public Animal(String name, int age) { this(name); System.out.println("Animal带两个参数的构造器,其age为" + age); } } public class Wolf extends Animal { public Wolf() { super("灰太狼", 3); System.out.println("Wolf无参数的构造器"); } public static void main(String[] args) { new Wolf(); } } //Creature无参数的构造器 //Animal带一个参数的构造器,该动物的name为灰太狼 //Animal带两个参数的构造器,其age为3 //Wolf无参数的构造器
2. 面向对象特征之三:多态性
2.1 多态性的概念
多态性,是面向对象中最重要的概念,在 Java 中的体现:对象的多态性:父类的引用指向子类的对象
- 可以直接应用在抽象类和接口上
Java 引用变量有两个类型: 编译时类型 和 运行时类型 。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称: 编译 时,看左边;运行时,看右边。若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism) 多态情况下,“看左边”: 看的是父类的引用(父类中不具备子类特有的方法)“看右边”: 看的是子类的对象(实际运行的是子类重写父类的方法)对象的多态 — 在 Java 中 , 子类 的对象可以替代 父类 的对象使用
- 一个变量只能有一种确定的数据类型
- 一个引用类型变量可能指向(引用)多种不同类型的对象
Person p = new Student(); Object o = new Person();//Object类型的变量o,指向Person类型的对象 o = new Student(); //Object类型的变量o,指向Student类型的对象
- 子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。
- 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
Student m = new Student(); m.school = “pku”; //合法,Student类有school成员变量 Person e = new Student(); e.school = “pku”; //非法,Person类没有school成员变量
属性是在编译时确定的,编译时 e 为 Person 类型,没有 school 成员变量,因而编 译错误。
2.2 多态性应用举例
方法声明的形参类型为 父类 类型,可以使用 子类的对象 作为实参调用该方法public class Test { public void method(Person e) { // …… e.getInfo(); } public static void main(Stirng args[]) { Test t = new Test(); Student m = new Student(); t.method(m); // 子类的对象m传送给父类类型的参数e } }
2.3 虚拟方法调用
正常的方法调用:Person e = new Person(); e.getInfo(); Student e = new Student(); e.getInfo();
虚拟方法调用 ( 多态情况下 ) :子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父 类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法 确定的。Person e = new Student(); e.getInfo(); //调用Student类的getInfo()方法
编译时类型和运行时类型:编译时 e 为 Person 类型,而方法的调用是在运行时确定的,所以调用的是 Student 类 的 getInfo() 方法。 —— 动态绑定虚拟方法调用举例:
2.4 方法的重载和重写
1. 二者的定义细节: 略2. 从编译和运行的角度看:重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。 它们的调用地址在编译期就绑定了。 Java 的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为 “早绑定”或“静态绑定” ;而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为 “晚绑定”或“动态绑定” 。引用一句 Bruce Eckel 的话: “不要犯傻,如果它不是晚绑定,它就不是多态。”
2.5 多态小结
多态作用:
- 提高了代码的通用性,常称作接口重用
前提:
- 需要存在继承或者实现关系
- 有方法的重写
成员方法:
- 编译时:要查看引用变量所声明的类中是否有所调用的方法。
- 运行时:调用实际new的对象所属的类中的重写方法。
成员变量:
- 不具备多态性,只看引用变量所声明的类。
2.6 instanceof操作符
x instanceof A :检验 x 是否为类 A 的对象,返回值为 boolean 型。
- 要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
- 如果x属于类A的子类B,x instanceof A值也为true。
public class Person extends Object {…} public class Student extends Person {…} public class Graduate extends Person {…} ------------------------------------------------------------------- public void method1(Person e) { if (e instanceof Person) // 处理Person类及其子类对象 if (e instanceof Student) //处理Student类及其子类对象 if (e instanceof Graduate) //处理Graduate类及其子类对象 }
2.7 对象类型转换(Casting)
基本数据类型的 Casting :
- 自动类型转换:小的数据类型可以自动转换成大的数据类型
- 如long g=20;
- double d=12.0f
- 强制类型转换:可以把大的数据类型强制转换(casting)成小的数据类型
- 如 float f=(float)12.0; int a=(int)1200L
对 Java 对象的强制类型转换称为造型
- 从子类到父类的类型转换可以自动进行
- 从父类到子类的类型转换必须通过造型(强制类型转换)实现
- 无继承关系的引用类型间的转换是非法的
- 在造型前可以使用instanceof操作符测试一个对象的类型
public class ConversionTest { public static void main(String[] args) { double d = 13.4; long l = (long) d; System.out.println(l); int in = 5; // boolean b = (boolean)in; Object obj = "Hello"; String objStr = (String) obj; System.out.println(objStr); Object objPri = new Integer(5); // 所以下面代码运行时引发ClassCastException异常 String str = (String) objPri; } }
public class Test { public void method(Person e) { // 设Person类中没有getschool() 方法 // System.out.pritnln(e.getschool()); //非法,编译时错误 if (e instanceof Student) { Student me = (Student) e; // 将e强制转换为Student类型 System.out.pritnln(me.getschool()); } } public static void main(String[] args){ Test t = new Test(); Student m = new Student(); t.method(m); } }
子类继承父类
- 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。
- 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量
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); } } public class FieldMethodTest { 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 } }
2.8 多态性代码演示
/* * 面向对象特征之三:多态性 * * 1.理解多态性:可以理解为一个事物的多种形态。 * 2.何为多态性: * 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用) * * 3. 多态的使用:虚拟方法调用 * 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。 * 总结:编译,看左边;运行,看右边。 * * 4.多态性的使用前提: ① 类的继承关系 ② 方法的重写 * * 5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边) */ public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); p1.eat();// 人:吃饭 Man man = new Man(); man.eat();// 男人多吃肉,长肌肉 man.age = 25; man.earnMoney();// 男人负责挣钱养家 // ************************************************* System.out.println("*******************"); // 对象的多态性:父类的引用指向子类的对象 Person p2 = new Man(); Person p3 = new Woman(); // 多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用 p2.eat();// 男人多吃肉,长肌肉 p2.walk();// 男人霸气的走路 p3.eat();// 女人少吃,为了减肥 p3.walk();// 女人窈窕的走路 // p2.earnMoney();Person类中没有定义earnMoney方法,无法调用 System.out.println(p2.id);// 1001 } } 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 earnMoney() { System.out.println("男人负责挣钱养家"); } public void eat() { System.out.println("男人多吃肉,长肌肉"); } public void walk() { System.out.println("男人霸气的走路"); } } public class Woman extends Person { boolean isBeauty; public void goShopping() { System.out.println("女人喜欢购物"); } public void eat() { System.out.println("女人少吃,为了减肥"); } public void walk() { System.out.println("女人窈窕的走路"); } }
//多态性的使用举例一: public class AnimalTest { public static void main(String[] args) { AnimalTest test = new AnimalTest(); test.func(new Dog()); test.func(new Cat()); } public void func(Animal animal) {// Animal animal = new Dog(); animal.eat(); animal.shout(); if (animal instanceof Dog) { Dog d = (Dog) animal; d.watchDoor(); } } // public void func(Dog dog){ // dog.eat(); // dog.shout(); // } // public void func(Cat cat){ // cat.eat(); // cat.shout(); // } } class Animal { public void eat() { System.out.println("动物:进食"); } public void shout() { System.out.println("动物:叫"); } } class Dog extends Animal { public void eat() { System.out.println("狗吃骨头"); } public void shout() { System.out.println("汪!汪!汪!"); } public void watchDoor() { System.out.println("看门"); } } class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } public void shout() { System.out.println("喵!喵!喵!"); } }
//面试题:多态是编译时行为还是运行时行为? //答:运行时行为。在运行之前无法得知运行的结果 //证明如下: class Animal { protected void eat() { System.out.println("animal eat food"); } } class Cat extends Animal { protected void eat() { System.out.println("cat eat fish"); } } class Dog extends Animal { public void eat() { System.out.println("Dog eat bone"); } } class Sheep extends Animal { public void eat() { System.out.println("Sheep eat grass"); } } public class InterviewTest { public static Animal getInstance(int key) { switch (key) { case 0: return new Cat(); case 1: return new Dog(); default: return new Sheep(); } } public static void main(String[] args) { int key = new Random().nextInt(3); System.out.println(key); Animal animal = getInstance(key); animal.eat(); } }
2.9 多态的理解
/* * 面向对象特征之三:多态性 * * 1.理解多态性:可以理解为一个事物的多种形态。 * 2.何为多态性: * 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用) * * 3. 多态的使用:虚拟方法调用 * 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。 * 总结:编译,看左边;运行,看右边。 * * 4.多态性的使用前提: ① 类的继承关系 ② 方法的重写 * * 5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边) * * ************************************************************* * * */ public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); p1.eat(); Man man = new Man(); man.eat(); man.age = 25; man.earnMoney(); // ************************************************* System.out.println("*******************"); // 对象的多态性:父类的引用指向子类的对象 Person p2 = new Man(); // Person p3 = new Woman(); // 多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用 p2.eat(); p2.walk(); // p2.earnMoney(); System.out.println(p2.id);// 1001 System.out.println("****************************"); // 不能调用子类所特有的方法、属性:编译时,p2是Person类型。 p2.name = "Tom"; // p2.earnMoney(); // p2.isSmoking = true; // 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致 // 编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。 // 如何才能调用子类特有的属性和方法? // 向下转型:使用强制类型转换符。 Man m1 = (Man) p2; m1.earnMoney(); m1.isSmoking = true; // 使用强转时,可能出现ClassCastException的异常。 // Woman w1 = (Woman)p2; // w1.goShopping(); /* * instanceof关键字的使用 * * a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。 * * * 使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先 * 进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。 * * 如果 a instanceof A返回true,则 a instanceof B也返回true. 其中,类B是类A的父类。 */ if (p2 instanceof Woman) { Woman w1 = (Woman) p2; w1.goShopping(); System.out.println("******Woman******"); } if (p2 instanceof Man) { Man m2 = (Man) p2; m2.earnMoney(); System.out.println("******Man******"); } if (p2 instanceof Person) { System.out.println("******Person******"); } if (p2 instanceof Object) { System.out.println("******Object******"); } // if(p2 instanceof String){ // // } // 练习: // 问题一:编译时通过,运行时不通过 // 举例一: // Person p3 = new Woman(); // Man m3 = (Man)p3; // 举例二: // Person p4 = new Person(); // Man m4 = (Man)p4; // 问题二:编译通过,运行时也通过 // Object obj = new Woman(); // Person p = (Person)obj; // 问题三:编译不通过 // Man m5 = new Woman(); // String str = new Date(); // Object o = new Date(); // String str1 = (String)o; } } 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 earnMoney() { System.out.println("男人负责挣钱养家"); } public void eat() { System.out.println("男人多吃肉,长肌肉"); } public void walk() { System.out.println("男人霸气的走路"); } } public class Woman extends Person { boolean isBeauty; public void goShopping() { System.out.println("女人喜欢购物"); } public void eat() { System.out.println("女人少吃,为了减肥"); } public void walk() { System.out.println("女人窈窕的走路"); } }
instanceof的理解:
/* * 建立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()); } public void method(Person e) { // 虚拟方法调用 String info = e.getInfo(); System.out.println(info); // 方式一 // if(e instanceof Graduate) { // System.out.println("a graduated student"); // System.out.println("a student"); // System.out.println("a person"); // } else if (e instanceof Student) { // System.out.println("a student"); // System.out.println("a person"); // } else { // System.out.println("a person"); // } // 方式二 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; } }
多态的考察:
//考查多态的笔试题目: public class InterviewTest1 { public static void main(String[] args) { Base1 base = new Sub1(); base.add(1, 2, 3);// sub_1 Sub1 s = (Sub1) base; s.add(1, 2, 3);// sub_2 } } class Base1 { public void add(int a, int... arr) { System.out.println("base1"); } } class Sub1 extends Base1 { public void add(int a, int[] arr) { System.out.println("sub_1"); } public void add(int a, int b, int c) { System.out.println("sub_2"); } }
结语
本人会持续更新文章的哦!希望大家一键三连,你们的鼓励就是作者不断更新的动力