一、子类对象创建过程
1.1 概述
- 我们已知子类创建出来的对象可以获取到父类中的属性和方法,怎么就能获取到呢?
- 通过代码我们验证了:创建子类对象的时候,会先创建父类的对象
package com.qf.create;
public class Demo01 {
public static void main(String[] args) {
// 创建子类对象的时候,会默认调用父类的构造方法---会先创建父类的对象
Dog dog = new Dog();
}
}
/**
* 动物类,所有动物的父类
* @author Dushine2008
*
*/
class Animal{
// 属性
String type;
String name;
int age;
public Animal() {
super();
System.out.println("Animal中的空参构造方法被调用啦啦啦啦...");
}
public Animal(String type, String name, int age) {
super();
this.type = type;
this.name = name;
this.age = age;
System.out.println("Animal中的有参构造方法被调用啦啦啦啦...");
}
// 方法
public void eat() {
System.out.println("动物需要进食...");
}
public void sleep() {
System.out.println("很多动物晚上需要休息...");
}
}
/**
* 狗子类,继承Animal
* @author Dushine2008
*
*/
class Dog extends Animal{
// 属性
String color;
String gender;
public Dog() {
super();
}
public Dog(String color, String gender) {
super();
this.color = color;
this.gender = gender;
}
public Dog(String type, String name, int age,String color, String gender) {
super(type, name, age);
this.color = color;
this.gender = gender;
}
// 方法
public void lookHome() {
System.out.println("狗子可以看家护院...");
}
}
1.2 多级继承关系中对象创建过程
- 如果产生了很多层级的继承关系,创建最底层类的实例的时候会创建所有上一层父类的对象吗?
- 需要,最底层的子类需要他们的实例属性、方法,而且实例属性是带有默认值的,说明父类们进行了初始化的操作
- 代码也验证了这种说法
package com.qf.create;
public class Demo01 {
public static void main(String[] args) {
// 创建子类对象的时候,会默认调用父类的构造方法---会先创建父类的对象
Dog dog = new Dog();
System.out.println(dog);
System.out.println("=========================");
Husky husky = new Husky();
}
}
/**
* 动物类,所有动物的父类
* @author Dushine2008
*
*/
class Animal{
// 属性
String type;
String name;
int age;
public Animal() {
super();
System.out.println("Animal中的空参构造方法被调用啦啦啦啦...");
}
public Animal(String type, String name, int age) {
super();
this.type = type;
this.name = name;
this.age = age;
System.out.println("Animal中的有参构造方法被调用啦啦啦啦...");
}
// 方法
public void eat() {
System.out.println("动物需要进食...");
}
public void sleep() {
System.out.println("很多动物晚上需要休息...");
}
}
/**
* 狗子类,继承Animal
* @author Dushine2008
*
*/
class Dog extends Animal{
// 属性
String color;
String gender;
public Dog() {
super();
System.out.println("Dog的空参构造方法执行...");
}
public Dog(String color, String gender) {
super();
this.color = color;
this.gender = gender;
}
public Dog(String type, String name, int age,String color, String gender) {
super(type, name, age);
this.color = color;
this.gender = gender;
}
// 方法
public void lookHome() {
System.out.println("狗子可以看家护院...");
}
}
/**
* Husky类,直接继承Dog,间接继承Animal
* @author Dushine2008
*
*/
class Husky extends Dog{
String feature;
public Husky() {
super();
System.out.println("Husky的空参构造方法...");
}
public Husky(String feature) {
super();
this.feature = feature;
}
}
二、多态
2.1 定义
-
生活中的多态
- 一个事物的多种表现形态
- 一个人可以使学生、孩子、家长、职员、、、、
- 一个事物的多种表现形态
-
程序中的多态
Animal a = new Dog()
父类引用===>子类对象
-
父类引用指向子类对象时称为多态(要有父类引用指向子类对象)
-
要有继承关系(要有继承)
-
只能调用父类自己独有的方法,运行的是子类重写之后的效果(子类要重写父类的方法)
2.2 多态的使用01
- 声明父类类型的引用,创建子类类型的对象
package com.qf.poly;
import java.util.Arrays;
public class Demo01 {
public static void main(String[] args) {
// 声明Human类型的引用,引用指向Human的对象
Human human = new Human();
human.dance();
System.out.println("===============================");
// 声明Human类型的引用,引用指向Male
Human human2 = new Male();
human2.dance();
System.out.println("===============================");
Human human3 = new Female();
human3.dance();
System.out.println("===============================");
}
}
class Human{
public void dance() {
System.out.println("人开心的时候会手舞足蹈...");
}
}
/**
* 男人类
* 继承Human,重写dance方法
* @author Dushine2008
*
*/
class Male extends Human{
@Override
public void dance() {
super.dance();
System.out.println("男人开心的时候跳兔子舞...");
}
}
/**
* 女人类
* 继承Human,重写dance方法
* @author Dushine2008
*
*/
class Female extends Human{
@Override
public void dance() {
super.dance();
System.out.println("女人开心的时候跳广场舞...");
}
}
2.3 多态的使用02–当做形参
- 编写一个方法,形参声明为引用类型
- 调用方法的时候传入此类型或者其子类型对象
package com.qf.poly;
public class Demo02 {
public static void main(String[] args) {
// 编写方法,形参声明为一个引用类型,传入此类型或者其子类对象
Human human1 = new Human();
dance(human1);
System.out.println("=======================");
Human human2 = new Male();
dance(human2);
System.out.println("=======================");
Human human3 = new Female();
dance(human3);
System.out.println("=======================");
dance(new Human());
dance(new Male());
dance(new Female());
}
/**
* 调用human跳舞的方法
* 形参数Human类型
* human对象有dance方法,调用之
* @param human
*/
public static void dance(Human human) {
human.dance();
}
}
2.4 多态使用方法和属性的情况
- 调用方法
- 编译的时候看父类中有没有这个方法
- 运行的时候看子类是否重写过这个方法
- 编译时看父类,运行时看子类
- 编译看左边,运行看右边
- 调用属性
- 编译的时候看父类中是否有这个属性
- 运行的时候依旧是使用父类的属性值
- 编译时看父类,运行时看父类
- 编译看左边,运行看左边
package com.qf.poly;
public class Demo03 {
public static void main(String[] args) {
Employee employee1 = new Employee();
employee1.work();
employee1.bitCard();
employee1.name = "张三";
System.out.println(employee1.name);
System.out.println("==========================");
// 多态指向Programmer
Employee employee2 = new Programmer();
employee2.work();
employee2.bitCard();
// employee2.name = "李思思";
System.out.println(employee2.name);
// 多态调用方法的时候,编译的时候看父类中有没有,运行的时候看子类是否重写过
// employee2.playGame();
// 多态调用变量的时候,编译的时候看父类中有没有,运行的依旧是父类的属性值
// employee2.hobby = "穿格子衫";
System.out.println(employee2.name);
}
}
class Employee{
// 属性
String name = "张三";
String department;
// 方法
public void work() {
System.out.println("员工有具体的工作内容...");
}
public void bitCard() {
System.out.println("员工上下班需要考勤...");
}
}
/**
* 程序员类
* 继承了员工类
* 重写了work和bitCard方法
* 自己有独特的方法
* @author Dushine2008
*
*/
class Programmer extends Employee{
// 属性
String hobby;
String name = "IT男";
@Override
public void work() {
System.out.println("我们每天吃饭、编码、打产品...");
}
@Override
public void bitCard() {
System.out.println("我们使用指纹打开的方式考勤...");
}
public void playGame() {
System.out.println("我们喜欢玩游戏,还能找到游戏的BUG...");
}
}
/**
* HR类
* 继承员工类,重写work和bitCard方法
* @author Dushine2008
*
*/
class HR extends Employee{
// 属性
int faceValue;
// 方法
@Override
public void work() {
System.out.println("HR的工作内容和人息息相关...");
}
@Override
public void bitCard() {
System.out.println("HR出外勤的时候可以在线考勤...");
}
public void recruit() {
System.out.println("HR负责公司人员的招聘和新员工培训...");
}
}
2.5 多态使用03-当做返回值类型
package com.qf.poly;
import java.util.Scanner;
public class Demo04 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("你喜欢哪种动物:1==Dog* 2==Cat* 3==Pig* 其他==Animal:");
int num = in.nextInt();
Animal animal = getAnimal(num);
animal.eat();
animal.sleep();
}
/**
* 传入编号,获取编号对应的动物
* 1==Dog
* 2==Cat
* 3==Pig
* 其他==Animal
* @param num
* @return
*/
public static Animal getAnimal(int num) {
Animal animal;
switch (num) {
case 1:
animal = new Dog();
break;
case 2:
animal = new Cat();
break;
case 3:
animal = new Pig();
break;
default:
animal = new Animal();
break;
}
return animal;
}
}
class Animal{
// 属性
String name;
int age;
public void eat() {
System.out.println("动物需要吃东西...");
}
public void sleep() {
System.out.println("动物需要睡觉来休息...");
}
}
/**
* 狗子类
* 继承Animal,重写eat和到了sleep方法
* @author Dushine2008
*
*/
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗子喜欢吃的东西和人基本一样...");
}
@Override
public void sleep() {
System.out.println("羡慕狗子的睡觉时间...");
}
}
/**
* 猫咪类
* 继承Animal,重写了eat和sleep方法
* @author Dushine2008
*
*/
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫咪喜欢吃小鱼...");
}
public void sleep() {
System.out.println("猫咪喜欢白天睡觉...");
}
}
class Pig extends Animal{
@Override
public void eat() {
System.out.println("哼哼喜欢吃西瓜...");
}
public void sleep() {
System.out.println("天蓬吃饱了就睡...");
}
}
三、向上转型和向下转型
3.1 向上转型(装箱)
- 声明的引用是父类类型,返回比较大,引用指向了子类对象
- 子类对象自动提升为父类类型,不会报错
- 但是只能使用声明的父类类型中的属性和方法
- 多态的基本使用情况
package com.qf.poly;
public class Demo05 {
public static void main(String[] args) {
People people1 = new Man();
people1.dance();
}
}
class People{
public void dance() {
System.out.println("人开心的时候跳舞...");
}
}
/**
* Man继承People
* 重写dance方法
* 增加sing方法
* @author Dushine2008
*
*/
class Man extends People{
@Override
public void dance() {
System.out.println("男人开心的时候跳舞...");
}
public void sing() {
System.out.println("男人开心的时候唱伤心太平洋...");
}
}
class Woman extends People{
@Override
public void dance() {
System.out.println("女人开心的时候跳广场舞...");
}
}
3.2 向下转型(拆箱)
- 声明的类型是子类类型的引用
- 引用指向的父类类型的对象
- 如果父类类型引用指向的子类类型的本身,代码不会出现问题,因为转了回来
- 如果父类引用的不是子类的类型,会报错:ClassCastException
package com.qf.poly;
public class Demo05 {
public static void main(String[] args) {
People people1 = new Man();
// 向下转型,需要手动强转,正确的情况
Man man = (Man)people1;
man.sing();
// 手动强转,错误的情况
People people2 = new Woman();
Man man2 = (Man) people2;
man2.sing();
}
}
class People{
public void dance() {
System.out.println("人开心的时候跳舞...");
}
}
/**
* Man继承People
* 重写dance方法
* 增加sing方法
* @author Dushine2008
*
*/
class Man extends People{
@Override
public void dance() {
System.out.println("男人开心的时候跳舞...");
}
public void sing() {
System.out.println("男人开心的时候唱伤心太平洋...");
}
}
class Woman extends People{
@Override
public void dance() {
System.out.println("女人开心的时候跳广场舞...");
}
}
四、instanceof
4.1 定义
- 判断一个对象是否是指定类型的实例
4.2 案例
package com.qf.poly;
import java.util.Scanner;
public class Demo06 {
public static void main(String[] args) {
/**
* 传入一个对象,调用这个对象所有的方法
*/
System.out.println("" instanceof String);
/**
* 提示用书输入一个数字,调用getPerson方法,获取这个数字对应的对象
* 调用show方法,传入这个对象,展示这个对象的方法
*/
Scanner in = new Scanner(System.in);
System.out.println("请输入你希望看到的职业(1==SoftwareEngineer,,,2==DBA,,,3==ImplementationEngineer,,,其他数字==Person):");
int num = in.nextInt();
// 调用getPerson方法获取对象
Person person = getPerson(num);
// 调用show方法传入Person。展示这个职业的方法
show(person);
}
/**
* 传入数字,获取对应的Person或者其子类的对象
* @param num-
* @return
*/
public static Person getPerson(int num) {
Person person;
switch (num) {
case 1:
person = new SoftwareEngineer();
break;
case 2:
person = new DBA();
break;
case 3:
person = new ImplementationEngineer();
break;
default:
person = new Person();
break;
}
return person;
}
/**
* 展示Person或者其子类的所有方法
* @param person
*/
public static void show(Person person) {
if (person == null) {
System.out.println("Person为null,请重新执行代码传入正确的参数...");
return;
}
// person非null
if (person instanceof SoftwareEngineer) {
SoftwareEngineer engineer = (SoftwareEngineer) person;
engineer.eat();
engineer.sleep();
engineer.work();
} else if (person instanceof DBA) {
DBA dba = (DBA) person;
dba.eat();
dba.sleep();
dba.eatBraisedChicken();
} else if (person instanceof ImplementationEngineer) {
ImplementationEngineer engineer = (ImplementationEngineer) person;
engineer.eat();
engineer.sleep();
engineer.work();
} else if (person instanceof Person) {
person.eat();
person.sleep();
} else {
System.out.println("您选择的职业暂无相关信息...");
}
}
}
/** 父类
* 会有一些子类,子类是具体职业的人
*
*/
class Person{
public void eat() {
System.out.println("人类需要吃饭...");
}
public void sleep() {
System.out.println("人需要睡眠保持精力...");
}
}
/**
* 技术总监/经理
* 技术支持/维护 技术专员
* 助理 软件工程师
* 程序员
* 硬件工程师
* 质量工程师
* 测试工程师
* 系统架构师
* 数据库管理/DBA
* 游戏设计
* 开发
* 网页设计/制作
* 语音/视频/图形
* 项目经理/主管
* 产品经理/专员
* 网站运营
* 网站编辑
* 网站策划
* 网络管理员 网络与信息安全工程师 实施工程师 通信技术工程师
* */
/**
* 软件工程师类
* 继承Person
* 重写eat和sleep方法
* 自定义work方法
* @author Dushine2008
*
*/
class SoftwareEngineer extends Person{
@Override
public void eat() {
System.out.println("我们工作很忙,外卖解决吃饭的问题...");
}
public void sleep() {
System.out.println("我们每天坚持午睡,下午精力充沛...");
}
public void work() {
System.out.println("我们的工作白天不怎么忙,晚上经常加班...");
}
}
/**
* DBA类
* 继承Person
* 重写eat和work
* 自定义eatBraisedChicken方法
* @author Dushine2008
*
*/
class DBA extends Person {
@Override
public void eat() {
System.out.println("DBA数据库方面的造诣比较深厚,他们吃饭也是点外卖,靠入侵外卖平台的数据库,篡改订单信息吃饭.");
}
public void sleep() {
System.out.println("中午不睡下午崩溃,坚持在你午睡攻陷你家的数据库.");
}
public void eatBraisedChicken() {
System.out.println("靠技术吃黄焖鸡,吃了整整一年...");
}
}
/**
* 实施工程师
* 继承Person
* 重写eat和sleep方法
* 自定义work方法
* @author Dushine2008
*
*/
class ImplementationEngineer extends Person{
@Override
public void eat() {
System.out.println("经常出差,可以领略各地的美食...");
}
@Override
public void sleep() {
System.out.println("一年到头就处于开房和退房的路上...");
}
public void work() {
System.out.println("这是个根客户打交道比较多的工作...");
}
}