关键字"/>
Java学习day10:多态、向下转型、instanceof关键字
声明:该专栏本人重新过一遍java知识点时候的笔记汇总,主要是每天的知识点+题解,算是让自己巩固复习,也希望能给初学的朋友们一点帮助,大佬们不喜勿喷(抱拳了老铁!)
Java学习day10:多态、向下转型、instanceof关键字
一、多态
多态是建立在封装和继承之上的
1.1方法的多态
要知道,方法的重写和重载就是方法多态的体现
class Person {public void eat () {System.out.println("吃饭");}public void eat (String food) {System.out.println("吃" + food);}
}
class Man extends Person {@Overridepublic void eat() {System.out.println("吃枸杞");}@Overridepublic void eat(String food) {System.out.println("吃"+ food);}
}
public class Demo1 {public static void main(String[] args) {}}
1.2对象的多态
首先区分一个基础知识点:
1.2.1对象的编译类型和运行类型
1.一个对象 的编译类型和运行类型是不一样
2.编译类型是在定义对象的时候,就已经确定好的
3.运行类型是可以改变的
4.编译类型看=的左边 运行类型看 =的右边
Person person = new Person();
比如这里,Person person就是编译类型,而new Person();就是运行类型
ok说了这么多,到底什么是多态?下面具体介绍多态
1.2.2什么是多态
一句话:父类引用指向子类的对象
创建对象的时候,等号左边是父类引用,等号右边就是子类对象
Animal animal = new Dog();
这里的Animal animal 就是父类引用,而new Dog()就是子类对象
1.2.3示例
class Animal {public void cry () {System.out.println("动物在叫......");}
}
class Dog extends Animal {@Overridepublic void cry() {System.out.println("汪汪汪......");}//自己独有的方法public void eat () {System.out.println("狗吃shit");}
}
class Cat extends Animal {@Overridepublic void cry() {System.out.println("喵喵喵.....");}public void sleep () {System.out.println("睡觉打呼噜");}
}
public class Demo1 {public static void main(String[] args) {//多态 父类的引用指向子类的对象Animal animal = new Dog();animal.cry();//父类的引用是指向不了子类独有的方法的,就意味着//父类的引用不能调用子类独有的方法//animal.eat();Animal animal2 = new Cat();animal2.cry();//animal2.sleep();}}
1.2.4多态必须满足的几个条件
1.必须有继承 |
2.必须有重写 |
3.=左边是父类引用 =右边是子类的对象 |
注意:父类的引用是指向不了子类独有的方法的,就意味着父类的引用不能调用子类独有的方法
1.3多态在开发中的使用
在开发中,一个方法的参数往往是父类的引用。但是真正传的值是子类的对象
不知道大家是否能理解这句话,其实就是说,方法形参是父类引用,而传入的实参是子类对象,这样就也是间接使用了多态。
1.3.1示例
用几个示例+代码给大家说明,大家认真看代码感受多态
(1) 人喂狗,狗吃饭。 人喂猫,猫吃饭
class Person {
// public void feed (Dog dog) {
// dog.eat();
// }
// public void feed (Cat cat) {
// cat.eat();
// }//在开发中,一个方法的参数是父类的引用。但是真正传的值是子类的对象public void feed (Animal animal) {animal.eat();}
}
interface Animal {public void eat ();
}
class Dog implements Animal{@Overridepublic void eat () {System.out.println("狗在吃骨头......");}
}
class Cat implements Animal{@Overridepublic void eat () {System.out.println("猫吃鱼......");}
}
public class Demo1 {public static void main(String[] args) {Person person = new Person();/*** Animal animal = new Cat();* public void feed (Animal animal) {animal.eat();}*/person.feed(new Cat());/*** Animal animal = new Dog();* public void feed (Animal animal) {animal.eat();}*/person.feed(new Dog());}}
(2)Person类
Student类 千锋学员
方法 执行学生手册
Teacher类 千锋讲师
方法 执行讲师手册
Employee 千锋的员工
方法 执行员工手册
Manager 管理层
管理学生 讲师 员工
manage();
class Manager {//管理层 去管理学员 讲师 员工public void manage (Person1 person1) {person1.excute();}
// public void manage (Teacher tea) {
// tea.excute();
// }
// public void manage (Employee emp) {
// emp.excute();
// }
}
interface Person1 {void excute();
}
class Student implements Person1{public void excute () {System.out.println("执行学员手册。。。。");}
}
class Teacher implements Person1{public void excute () {System.out.println("执行讲师手册。。。。。");}
}
class Employee implements Person1{public void excute () {System.out.println("执行员工手册。。。。。");}
}
public class Demo2 {public static void main(String[] args) {Person1 person1 = new Student();Manager manager = new Manager();manager.manage(person1);}}
(3)编写程序实现比萨制作。需求说明编写程序,可供选择的比萨有:培根比萨和海鲜比萨。
实现思路及关键代码
1) 分析培根比萨和海鲜比萨
2) 定义比萨类
3) 属性:名称、价格、大小
4) 方法:展示
5) 定义培根比萨和海鲜比萨继承自比萨类
6) 定义比萨工厂类,根据输入信息产生具体的比萨对象
PizzaFactory {
createPizza(Pizza);//如果传的参数培根披萨就是生产培根披萨 如果传的是海鲜披萨就是生产的海鲜披萨
}
class Pizza {private String name;//名字private double price;//价格private double size;//尺寸public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public double getSize() {return size;}public void setSize(double size) {this.size = size;}//展示方法public void getInfo () {}
}
class BaconPizza extends Pizza{@Overridepublic void getInfo() {System.out.println("披萨的名字为:" + getName() + ",披萨的价格:" + getPrice() + ",披萨的尺寸:" + getSize());}
}
class SeaPizza extends Pizza {@Overridepublic void getInfo() {System.out.println("披萨的名字为:" + getName() + ",披萨的价格:" + getPrice() + ",披萨的尺寸:" + getSize());}
}
//披萨的生产工厂
class PizzaFactory {//生产披萨的方法public void createPizza (Pizza pizza) {pizza.getInfo();}}
public class Demo3 {public static void main(String[] args) {Pizza pizza = new SeaPizza();pizza.setName("海鲜披萨");pizza.setPrice(78.9);pizza.setSize(6.7);PizzaFactory pizzaFactory = new PizzaFactory();pizzaFactory.createPizza(pizza);//生产培根披萨Pizza pizza2 = new BaconPizza();pizza2.setName("培根披萨");pizza2.setPrice(45.9);pizza2.setSize(7.2);pizzaFactory.createPizza(pizza2);}}
1.4多态的转型
1.4.1多态的向上转型
本质就是:父类的引用指向子类对象,也就是我们上面所说的多态的概念
将子类的对象赋值给了父类的引用。小范围(子类) 转为大范围(父类)自动转
父类的引用可以调用父类的所有成员方法,可以调用子类的重写父类的方法,但是不能调用子类独有的方法。(所以我们之前说,多态必须要有重写)
语法格式:
父类 父类引用 = new 子类();
1.4.1.1示例
class Person {public void eat () {}
}
class Student extends Person {@Overridepublic void eat() {System.out.println("学生吃饭,吃披萨");}public void sleep () {System.out.println("中午不谁下午崩溃!!!");}
}
public class Demo1 {public static void main(String[] args) {Person person = new Student();//向上转型person.eat();//person.sleep();}}
1.4.2多态向下转型
语法格式:
父类类型 父类引用 = new 子类();
子类类型 子类引用 = (子类类型)父类的引用;向下转型
可以看到将父类的引用赋值给了子类的对象。大范围(父类) 转为小范围(子类),所以需要强转(强调,需要强转)
而且可以看到我们转了两次,先是向上转型,再向下转型,这是固定的语法格式
先将父类引用指向了子类的对象,再将父类的引用赋值给子类 ,从而完成强转
1.4.2.1示例
class TestA {//Object 是所有类的父类public void test (Object obj ) {//必须给我打印一个String类型的狗蛋,我不要Object类型的狗蛋
// String str = (String) obj;
// System.out.println(str);int i1 = (int)obj;System.out.println(i1);}
}
public class Demo4 {public static void main(String[] args) {TestA testA = new TestA();//testA.test("狗蛋");Object object = "狗蛋";testA.test(98);testA.test('狗');}}
二、instanceof 关键字
2.1基本介绍
本质是比较操作符,返回值是布尔类型的数据
语法格式:
对象引用 instanceof 运行类型
用来判断对象的运行类型(=右边), 是否是xx类型或者xx类型的子类(目的是为了在强转的时候不出现问题)
这个点很简单,大家记住就行,看代码写的非常清楚。
2.2示例
示例1:
class AA {}
class BB extends AA {}
public class Demo1 {public static void main(String[] args) {BB bb = new BB();BB bb1 = new BB();AA aa = new AA();//instanceof 的左边放的对象的引用,右边是类System.out.println(bb instanceof BB);//trueSystem.out.println(bb1 instanceof BB);//true//判断对象bb是否是AA的对象或者子类的对象System.out.println(bb instanceof AA);//trueSystem.out.println(aa instanceof AA);//trueSystem.out.println(aa instanceof BB);//false//总结: 左边 的辈分小(对象的引用) 右边辈分大(类) 屡试不爽AA aa2 = new BB();System.out.println(aa2 instanceof AA);//trueSystem.out.println(aa2 instanceof BB);//true//Object object = new Object();System.out.println(object instanceof AA);//falseSystem.out.println(object instanceof Object);//trueString string = "qwer";System.out.println(string instanceof Object);//true}
就记住这句话
左边 的辈分小(对象的引用) 右边辈分大(类)
此时返回结果才是true,也就是说,满足这个情况下才对其进行强转
示例2:
class Employee {}
class Monkey {//这个方法的返回值是一个字符串public String xixi(Object obj) {//Object obj = new String("狗蛋");//obj instanceof Stringif (obj instanceof String) {String string = (String)obj;return "传给我的 参数是字符串类型的数据";} else if (obj instanceof Integer) {Integer i1 = (Integer)obj;return "传给我的 参数是int类型的数据";} else if (obj instanceof Employee) {Employee employee = (Employee)obj;return "传给我的参数是一个Employee对象";}else {return "参数不合法";}}
}
public class Demo3 {public static void main(String[] args) {Monkey monkey = new Monkey();//System.out.println(monkey.xixi("狗蛋"));//System.out.println(monkey.xixi(89));Employee employee = new Employee();System.out.println(monkey.xixi(employee));String string = new String();}}
这里注意,如果两个类继承了同一个父类,那么他们是平辈关系,但是呢,由于这两个类没什么关系,所以instanceof关键字下依然是false
以上就是今天所有的知识点,下面做题。
三、习题
3.1题目
1.//利用接口做参数,写个计算器,能完成+-*/运算
//(1)定义一个接口Compute含有一个方法int calc(int one,int two);
//(2)设计四个类分别实现此接口,完成+-*/运算
//(3)设计一个类UseCompute,含有方法:public void useCom(Compute com, int one, int two)
//此方法要求能够:1.用传递过来的对象调用computer方法完成运算
//2.输出运算的结果
//(4)设计一个测试类,调用UseCompute中的方法useCom来完成+-*/运算2、按要求编写一个Java应用程序程序:
(1)定义一个接口CanFly,描述会飞的方法public void fly();
(2)分别定义类飞机和鸟,实现CanFly接口。
(3)定义一个测试类,测试飞机和鸟,在main方法中创建飞机对象和鸟对象,
再定义一个makeFly()方法,其中让会飞的事物飞。并在main方法中调用该方法,
让飞机和鸟起飞。
*/
3./*编写程序,求柱体的体积:
(1)、为柱体的底面设计一个接口Geometry,包含计算面积的方法getArea();
(2)、为柱体设计类pillar,要求:
a)有两个成员变量,底面和高度。底面是任何可以计算面积的几何形状。
b)实现构造方法,对成员变量赋值。
c)包含成员方法,计算柱体Pillar的体积。
(3)、编写测试类圆形类、矩形类实现Geometry接口,编写测试类Test,
分别用圆形、矩形作为柱体的底面,并计算其体积。
*/
4./*1.定义一个canAttack()接口,其中有一个attack()抽象方法
2.定义一个canMove()接口,其中有一个move()抽象方法
3.定义一个抽象类Weapon(),实现canAttack()和canMove()两个接口,但不实现其中的抽象方法。
4.定义三个类,Tank坦克,Airplane战斗机,Ship军舰,
都继承Weapon武器分别用不同的方式实现 Weapon 类中的抽象方法
5.写一个类Army,代表一支军队,这个类有一个属性是Weapon数组weapons(用来存储该军队所拥有的所有武器)该类还
提供一个构造方法,在构造方法里通过传一个int类型的参数来限定该类所能拥有的最大武器数量,并用这一大小
来初始化数组w。该类还提供一个方法addWeapon(Weapon weapon),
表示把参数weapon所代表的武器加入到数组weapons中。在这
个类中还定义两个方法attackAll()和moveAll(),让weapons数组中的所有武器攻击和移动
6.定义一个主类来实现这些步骤。
*/
5./* 1.定义一个接口IShape,该接口中包含两个成员:周长和面积;
2.分别定义四个类,矩形类:Rectangle,三角形类:Triangle,
平行四边形类:Parallelogram,梯形类Echelon,这四个类都实现接口IShape,
同时各类拥有自己的私有属性,比如说矩形的属性长和宽,平行四边形的属性边长和高,
三角形的属性三个边长和高,梯形的属性上底、下底、腰长和高等,给每个类添加相应的构造方法,
使各私有属性都能获得相应的值。
3.定义一个测试类TestShape,在该类中定义一个方法,只要调用该方法就能获得对应类型的周长和面积,
然后在该类中进行相关测试。
注:类中描述的成员除上述内容外,可通过自己的想法自行添加,也可不添加。
*
*/
建议初学者都敲一敲,而且是不看我的答案,先自己敲,很多东西看着会,实际自己上手敲的时候往往会出错。另外题解肯定不止一个,我也只是记录其中一种,大家大可寻找更优解,同时我基本没写注释,希望大家还是多自己思考原因。
3.2部分习题参考答案
1.
package 抽象类与接口码云作业;
//利用接口做参数,写个计算器,能完成+-*/运算
//(1)定义一个接口Compute含有一个方法int calc(int one,int two);
//(2)设计四个类分别实现此接口,完成+-*/运算
//(3)设计一个类UseCompute,含有方法:public void useCom(Compute com, int one, int two)
//此方法要求能够:1.用传递过来的对象调用computer方法完成运算
//2.输出运算的结果
//(4)设计一个测试类,调用UseCompute中的方法useCom来完成+-*/运算interface Compute{void calc(int one,int two);}class plus implements Compute{public void calc(int one, int two) {double num=one+two;System.out.println("两个数的和为"+num);} }class subtract implements Compute{public void calc(int one, int two) { double num=one-two;System.out.println("两个数相减的值为:"+num);} }class ride implements Compute{public void calc(int one, int two) { double num =one*two;System.out.println("两个数相乘的值为:"+num);} }class divide implements Compute{public void calc(int one, int two) {double num =one/two;System.out.println("两个数相除的值为:"+num);} }class UseCompute{public void useCom(Compute com,int one,int two) {System.out.println("两个数的和为"+(one+two));System.out.println("两个数相减为"+(one-two));System.out.println("两个数相乘为"+(one*two));System.out.println("两个数相除为"+(one/two));}}public class Demo {public static void main(String[] args) {/*plus p=new plus();p.calc(10, 2);subtract s =new subtract();s.calc(10, 2);ride r =new ride();r.calc(10,2);divide d =new divide();d.calc(10,2);*/UseCompute u =new UseCompute();u.useCom(new plus(), 10, 2); }
}
2.
package 抽象类与接口码云作业;/*码云作业2、按要求编写一个Java应用程序程序:(1)定义一个接口CanFly,描述会飞的方法public void fly();(2)分别定义类飞机和鸟,实现CanFly接口。(3)定义一个测试类,测试飞机和鸟,在main方法中创建飞机对象和鸟对象,再定义一个makeFly()方法,其中让会飞的事物飞。并在main方法中调用该方法,让飞机和鸟起飞。*/interface CanFly{public abstract void fly();}class Plane implements CanFly{public void fly() {System.out.println("飞机在天上飞");}}class Bird implements CanFly{public void fly() {System.out.println("小鸟也在飞");} }
public class Demo2 {public static void main(String[] args) {CanFly plane = new Plane();CanFly bird = new Bird();makeFly(plane);makeFly(bird);}public static void makeFly(CanFly canFly) {canFly.fly();}
}
3.
package 抽象类与接口码云作业;/*编写程序,求柱体的体积:(1)、为柱体的底面设计一个接口Geometry,包含计算面积的方法getArea();(2)、为柱体设计类pillar,要求:a)有两个成员变量,底面和高度。底面是任何可以计算面积的几何形状。b)实现构造方法,对成员变量赋值。c)包含成员方法,计算柱体Pillar的体积。(3)、编写测试类圆形类、矩形类实现Geometry接口,编写测试类Test,分别用圆形、矩形作为柱体的底面,并计算其体积。*/interface Geometry{public double getArea();}class Pillar{Geometry bottom;double height;public Pillar(Geometry bottom,double height) {this.bottom=bottom;this.height=height;}public double Volume() {return bottom.getArea()*this.height; }}class Circle implements Geometry{double radius;public Circle(double radius) {this.radius=radius;}public double getArea() {return Math.PI*this.radius*this.radius;}}class Rect implements Geometry{double wide,length;public Rect(double wide,double length) {this.wide=wide;this.length=length;}public double getArea() {return wide*length;}}
public class Demo3 {public static void main(String[] args) {Pillar pillar;Geometry bottom;bottom =new Rect(10,5); pillar=new Pillar(bottom,5);System.out.println("矩形的柱体体积:"+pillar.Volume());bottom=new Circle(5);pillar =new Pillar(bottom,5);System.out.println("圆形柱体的体积:"+pillar.Volume());}
}
4.
import java.util.Scanner;/*1.定义一个canAttack()接口,其中有一个attack()抽象方法
2.定义一个canMove()接口,其中有一个move()抽象方法
3.定义一个抽象类Weapon(),实现canAttack()和canMove()两个接口,但不实现其中的抽象方法。
4.定义三个类,Tank坦克,Airplane战斗机,Ship军舰,
都继承Weapon武器分别用不同的方式实现 Weapon 类中的抽象方法
5.写一个类Army,代表一支军队,这个类有一个属性是Weapon数组weapons(用来存储该军队所拥有的所有武器)该类还
提供一个构造方法,在构造方法里通过传一个int类型的参数来限定该类所能拥有的最大武器数量,并用这一大小
来初始化数组w。该类还提供一个方法addWeapon(Weapon weapon),
表示把参数weapon所代表的武器加入到数组weapons中。在这
个类中还定义两个方法attackAll()和moveAll(),让weapons数组中的所有武器攻击和移动
6.定义一个主类来实现这些步骤。*/interface canAttack{void attack(); }interface canMove{void move();}abstract class Weapon implements canAttack,canMove{public void attack() {};public void move() {};}class Tank extends Weapon{public void attack() {System.out.println("坦克在开炮...");}public void move() {System.out.println("坦克在行驶...");}}class Ship extends Weapon{public void attack() {System.out.println("军舰在攻击中...");}public void move() {System.out.println("军舰移动在海洋中...");}}class Airplane extends Weapon{public void attack() {System.out.println("战斗机在攻击中...");}public void move() {System.out.println("战斗机在天上飞行...");}}class Army{int j=0; int n; Weapon[] w;public int getMax() { return n; } public void setMax(int n){ this.n = n; } public Army(int n) { this.n = n; w = new Weapon[n]; System.out.println("您最多拥有"+n+"个武器!!!"); }public void addWeapon(Weapon wa) {if(j<getMax()) {System.out.println("武器足够使用!"+"已增加"+(j+1)+"个武器");w[j]=wa;j++;}else {System.out.println("武器足够,不能增加武器!!!");}}public void attackAll() {System.out.println();System.out.println("所有武器准备战斗!!");for(int i=0;i<j;j++) {System.out.println((i+1)+"号");w[i].attack();}}public void moveAll(){System.out.println();System.out.println("所有武器准备移动");for(int i=0;i<j;i++) {System.out.println((i+1)+"号");w[i].move();}}}
public class Demo4 {public static void main(String[] args) {Scanner s = new Scanner(System.in); System.out.println("请输入武器库容量"); int n = s.nextInt(); Army a = new Army(n); System.out.println("输入yes添加武器,输入其他则不录入"); String m = s.next();//添加武器 while(m.equals("yes")) { System.out.println("1.坦克 2.战斗机 3.军舰"); System.out.println("请选择:"); int l=s.nextInt(); if(l==1) { a.addWeapon(new Tank()); } else if(l==2) { a.addWeapon(new Airplane()); } else if(l==3) { a.addWeapon(new Ship()); } else{ System.out.println("输入错误"); } System.out.println("输入yes添加武器,输入其他则退出"); m = s.next(); } a.moveAll(); a.attackAll(); }
5.
package 抽象类与接口码云作业;
/*1.定义一个接口IShape,该接口中包含两个成员:周长和面积;2.分别定义四个类,矩形类:Rectangle,三角形类:Triangle,平行四边形类:Parallelogram,梯形类Echelon,这四个类都实现接口IShape,同时各类拥有自己的私有属性,比如说矩形的属性长和宽,平行四边形的属性边长和高,三角形的属性三个边长和高,梯形的属性上底、下底、腰长和高等,给每个类添加相应的构造方法,使各私有属性都能获得相应的值。3.定义一个测试类TestShape,在该类中定义一个方法,只要调用该方法就能获得对应类型的周长和面积,然后在该类中进行相关测试。注:类中描述的成员除上述内容外,可通过自己的想法自行添加,也可不添加。* */
interface IShape{int getPerimeter();//求周长int getArea();//求面积
}
class Triangle implements IShape {private int length;private int width;public Triangle(int length, int width) {this.length = length;this.width = width;}public int getPerimeter() {return (length+width)*2;} public int getArea() {return length*width;}
}
class Rectangle implements IShape { private int line1;private int line2;private int line3;private int height1;private int height2;private int height3;public Rectangle(int line1, int line2, int line3, int height1, int height2, int height3) {this.line1 = line1;this.line2 = line2;this.line3 = line3;this.height1 = height1;this.height2 = height2;this.height3 = height3;}public int getPerimeter() {return line1+line2+line3;} public int getArea() {return line1*height1/2;}
}
class Parallelogram implements IShape { private int line1;private int line2;private int height1;private int height2;public Parallelogram(int line1, int line2, int height1, int height2) {this.line1 = line1;this.line2 = line2;this.height1 = height1;this.height2 = height2;} public int getPerimeter() {return (line1+line2)*2;}public int getArea() {return line1*height1;}
}
class Echelon implements IShape { private int topLine;private int bottomLine;private int line1;private int line2;private int height; public Echelon(int topLine, int bottomLine, int line1, int line2, int height) {this.topLine = topLine;this.bottomLine = bottomLine;this.line1 = line1;this.line2 = line2;this.height = height;}public int getPerimeter() {return topLine+bottomLine+line1+line2;}public int getArea() {return (topLine+bottomLine)*height/2;}
}
public class Demo5{public static void main(String[] args) {Triangle triangle = new Triangle(4,5); Rectangle rectangle = new Rectangle(3,4,5,4,3,6); Parallelogram parallelogram = new Parallelogram(6,7,4,5); Echelon echelon = new Echelon(3,4,6,7,8);System.out.println("矩形周长:"+triangle.getPerimeter());System.out.println("矩形面积:"+triangle.getArea()); System.out.println("三角形周长:"+rectangle.getPerimeter());System.out.println("三角形面积:"+rectangle.getArea());System.out.println("平行四边形周长:"+parallelogram.getPerimeter());System.out.println("平行四边形面积:"+parallelogram.getArea()); System.out.println("梯形周长:"+echelon.getPerimeter());System.out.println("梯形面积:"+echelon.getArea()); }
}
以上就是今天的所有知识点了。有段时间没碰csdn了,没想到一下就落了不少文章了,我抓紧总结发出来。
今天的知识点比较多,而且都很重要,特别是多态,多态的上下转型,instanceof关键字等,大家自己要多看多敲多写,才能掌握好这部分内容。,可以看到今天的习题也不少,一定要多看多敲,我自己有几天没碰代码,再次上手idea就都是很陌生的感觉了。
加油吧,预祝大家变得更强!
更多推荐
Java学习day10:多态、向下转型、instanceof关键字
发布评论