多态
什么是多态
package Demo1;
public class Person {
private String name;
private int age;
public void work(){
System.out.println("工作");
}
public void look(){
System.out.println(name+"年龄"+age);
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + "}";
}
}
package Demo1;
public class student extends Person{
@Override
public void look() {
System.out.println("学生的信息:"+getName()+","+getAge());
}
}
package Demo1;
public class teacher extends Person{
@Override
public void look() {
System.out.println("老师的信息:"+getName()+","+getAge());
}
}
package Demo1;
public class admin extends Person{
@Override
public void look() {
System.out.println("管理员的信息:"+getName()+","+getAge());
}
}
package Demo1;
public class Test {
public static void main(String[] args) {
student s = new student();
s.setName("小李");
s.setAge(18);
teacher t = new teacher();
t.setName("小王");
t.setAge(30);
admin a = new admin();
a.setName("admin");
a.setAge(50);
show(s);
show(t);
show(a);
}
//写一个方法用于调用
public static void show(Person p){
p.look();
}
}
运行结果:
学生的信息:小李,18
老师的信息:小王,30
管理员的信息:admin,50
多态调用成员的特点
调用成员变量:
- 编译看左边:javac编译时会看左边的父类中有没有这个变量,如果有,编译成功,没有则编译失败。
- 运行也看左边:运行代码实际上获取的是左边父类中的成员变量的值。
调用成员方法
- 编译看左边:javac编译时会看左边的父类中有没有这个方法,如果有,编译成功,没有则编译失败。
- 运行看右边:运行代码实际上运行子类中的方法。
理解:
例如:Anomal a = new Dog();
现在用a 去调用变量和方法,而a是Animal类型的所以默认从Animal这个类中找
成员变量:在子类的对象中会把父类的变量继承
成员方法:如果子类进行了方法重写则在虚方法表中会覆盖父类的方法。
多态调用成员的内存图
多态的优势
多态的弊端:
不能调用子类特有的方法。
可以进行强转来调用。如下:
package Demo.Demo2;
public class Test {
public static void main(String[] args) {
//多态
Animal a = new Dog();
//只能使用Animal中的方法而无法使用Dog中的方法
a.eat();
//如果想使用可以进行强转,强转要考虑转换的类型,类型不正确则报错
Dog d = (Dog) a;
// Cat c = (Cat) a;//运行时报错
//要判断a的类型可以使用
if (a instanceof Dog){
Dog d1 = (Dog) a;
d1.lookhome();
} else if (a instanceof Cat) {
Cat c = (Cat) a;
c.catchmocer();
}else {
System.out.println("没用对应的类型");
}
//jdk14的新特性,将判断和转换放在一起
if (a instanceof Dog d2){
d2.lookhome();
} else if (a instanceof Cat c2) {
c2.catchmocer();
}else {
System.out.println("没用对应的类型");
}
}
}
package Demo.Demo2;
public class Animal {
String name;
public void eat(){
System.out.println("吃东西");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃东西");
}
public void lookhome(){
System.out.println("狗看门");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchmocer(){
System.out.println("猫抓老鼠");
}
}
多态优劣的总结:
多态综合练习
练习一:
根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家lookHome方法(无参数)
2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)
3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法
4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String somethind)方法打印内容如下:
年龄为30岁的老王养了一只黑颜色的2岁的狗
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat,String somethind)方法打印内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的猫
3岁的灰颜色的猫眯着眼睛侧着头吃鱼
5.思考:
1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
package Demo.Demo3;
public class Animal {
private int age;
private String color;
public Animal() {
}
public Animal(int age, String color) {
this.age = age;
this.color = color;
}
public void eat(String something){
System.out.println(something+"被吃了");
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return color
*/
public String getColor() {
return color;
}
/**
* 设置
* @param color
*/
public void setColor(String color) {
this.color = color;
}
public String toString() {
return "Animal{age = " + age + ", color = " + color + "}";
}
}
package Demo.Demo3;
public class Dog extends Animal{
public Dog() {
}
public Dog(int age, String color) {
super(age, color);
}
public void lookHome(){
System.out.println("看家");
}
@Override
public void eat(String something) {
System.out.println(getAge()+"岁的"+getColor()+"颜色的狗两只前腿死死的抱着"+something+"猛吃");
}
}
package Demo.Demo3;
public class Cat extends Animal{
public Cat() {
}
public Cat(int age, String color) {
super(age, color);
}
public void catchMouse(){
System.out.println("抓老鼠");
}
@Override
public void eat(String something) {
System.out.println(getAge()+"岁的"+getColor()+"颜色的猫眯着眼睛侧着头吃"+something+"猛吃");
}
}
package Demo.Demo3;
public class Person {
private String name;
private int age;
public void keepPet(Animal a,String something){
//判断输入的类型
if (a instanceof Dog d){
System.out.println("年龄为"+age+"岁的"+name+"养了一只"+d.getColor()+"色的"+d.getAge()+"岁的狗");
d.eat(something);
} else if (a instanceof Cat c) {
System.out.println("年龄为"+age+"岁的"+name+"养了一只"+c.getColor()+"色的"+c.getAge()+"岁的猫");
c.eat(something);
}else {
System.out.println("输入的类型有误");
}
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + "}";
}
}
public class Test {
public static void main(String[] args) {
// Animal a = new Dog();
// a.setAge(3);
// a.setColor("灰");
// Person p = new Person();
// p.setName("老李");
// p.setAge(30);
// p.keepPet(a,"头骨");
// Animal a = new Cat();
// a.setAge(3);
// a.setColor("灰");
// Person p = new Person();
// p.setName("老李");
// p.setAge(30);
// p.keepPet(a,"巨骨舌鱼");
//父类的形参可以传入子类
Person p = new Person("老赵",30);
Dog d = new Dog(3,"黑");
Cat c = new Cat(3,"黑");
p.keepPet(d,"骨头");
p.keepPet(c,"鱼");
}
}
运行结果:
年龄为30岁的老赵养了一只黑色的3岁的狗
3岁的黑颜色的狗两只前腿死死的抱着骨头猛吃
年龄为30岁的老赵养了一只黑色的3岁的猫
3岁的黑颜色的猫眯着眼睛侧着头吃鱼猛吃
shift+F6 为批量修改
包和final、权限修饰符、代码块
包
什么是包
使用其他类的规则
- 使用同一个包中的类时,不需要导包
- 使用java.long 包中的类时,不需要导包
- 其他情况都需要导包
- 如果同时使用两个包中的同名类,需要使用全类名。
包入门小结:
final关键字(最终)
常量:
常量总结:
权限修饰符
空着不写被叫做默认或缺省。
- private 私房钱,只能自己用。
- 缺省 自己家里的钱,只能自己家用。
- protected 自己家和私生子能用。
- public 公共的,所有人都能用。
权限修饰符使用规则:
代码块
- 局部代码块
- 构造代码块
- 静态代码块
局部代码块
局部:写在代码里的
作用:提前结束变量的生命周期。
好处:节约内存。
构造代码块:
- 生成成员位置的代码块
- 作用:可以把多个构造方法中重复的代码抽取出来
- 执行时间:我们在创建本类对象的时候会先执行构造代码块在执行构造方法
- 逐渐被淘汰
public class Student {
private String name;
private int age;
//构造代码块
{
System.out.println("构造代码块执行");
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
public class Test {
public static void main(String[] args) {
Student s = new Student();
Student s1 = new Student("小李",18);
}
}
如果有构造方法不需要加入该公共代码时的处理方法: