生活中的多态:
人类:那个漂亮的小姐姐(类型:小姐姐),那个长的有点像周冬雨的人(类型:像周冬雨的人),那个爱笑的人(类型:爱笑的人)
猫类:那只喵星人(类型:喵星人),那只小宠物(类型:小宠物),那只小动物(类型:小动物),那只小可爱(类型:小可爱)
程序中的多态:
在程序中习惯性将对象的类型分为编译时类型和运行时类型
单态:当编译时类型和运行时类型是一样的时候
举例:Student s = new Student();
多态:当编译时类型和运行时类型不一样的时候
举例:Animal a = new Cat();
备注:
在程序中我们将子类对象或实现类对象赋值给父类类型的引用或父接口类型的引用的现象
多态的前提条件:
1.程序必须具有继承关系或实现关系
2.程序中必须要有方法的重写(没有方法重写也可以构成多态的格式,但是这样的多态没有任何意义)
衍生出:多态只和对象实例方法有关,和其它成员或内容无法
3.如果是继承关系,父类的引用指向子类对象
格式:
父类类名 对象名 = new 子类类名(实参);
如果是实现关系,父接口的引用指向子类对象
格式:
父接口名 对象名 = new 实现类类名(实参);
多态关系中各成员和内容的特点:
构造器
实例变量
实例方法
多态关系中构造器的特点:
多态关系中无需额外考虑构造器的执行特点,因为和以前的执行流程一模一样
构造器和多态没有任何关系
多态关系中实例变量的特点
多态关系中无需额外考虑实例变量的执行特点,因为和以前的变量执行特点一模一样
实例变量和多态没有任何关系
多态关系中实例方法的特点:
通过多态形式的对象进行方法调用,先判断父类或者父接口中是否含有这个方法,
如果含有,执行子类或实现类重写后的方法;
如果没有,程序编译报错
多态的好处
提高方法的复用性.在实际中无需声明多个重载的方法,直接声明一个父类或者父接口作为形参的方法即可
学习多态是学习"匿名内部类"的前提条件
//person 类
public class Person {
public Person() {
}
public void keepPet (Animal animal , String something) {
//针对参数进行非空校验
if (animal == null) {
return;
}
//调用动物的eat()
animal.eat(something);//多态形式的对象调用方法
}
}
//animal 类
public abstract class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public Animal() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//抽取子类们中的共性方法,且需要重写
public abstract void eat(String something);
//抽取子类们中的共性方法,且不需要重写
public void sleep () {
System.out.println("睡觉觉");
}
}
//cat 类
public class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}
public Cat() {
}
@Override
public void eat(String something) {
System.out.println(getAge() + "岁的" + getName() + "正在吃" + something);
}
//猫的特有方法
public void catchMouse () {
System.out.println(getAge() + "岁的" + getName() + "正在抓老鼠");
}
}
//dog 类
public class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
public Dog() {
}
@Override
public void eat(String something) {
System.out.println(getAge() + "岁的" + getName() + "正在吃" + something);
}
//狗的特有方法
public void lookHome () {
System.out.println(getAge() + "岁的" + getName() + "正在看家");
}
}
//main 方法
//创建猫对象
Cat tom = new Cat("Tom", 2);
//创建狗对象
Dog twoHa = new Dog("TwoHa", 3);
//创建饲养员对象
Person p = new Person();
//饲养员喂养猫
p.keepPet(tom,"鱼");
//饲养员喂养狗
p.keepPet(twoHa,"骨头");
多态的弊端
使用多态的对象无法调用子类(实现类)的特有方法
引用类型间的转换(向上转型和向下转型)
向上转型:
将子类类型对象转换成父类类型的对象(其实就是多态)
向下转型:
将父类类型对象转换成子类类型的对象
补充:
无法直接进行转换,需要借用类型转换的格式
格式:
子类类名 对象名 = (子类类名)父类类型对象;
注意事项:
将某个对象转换为不是该对象的对应的数据类型时,可能发生类型转换异常(ClassCastException)
instanceof关键字:
含义:
包含
作用:
判断指定的对象在内存中是否为指定类型或者其子类类型
格式:
对象名 instanceof 类型
指定的对象在内存中是指定类型本身或者其子类类型,返回true
指定的对象在内存中不是指定类型本身或者其子类类型,返回false
//使用多态的方式创建猫对象
Animal tom = new Cat("Tom",2);
//将Animal类型的对象向下转型为Cat类型对象
if (tom instanceof Cat) {
Cat cat = (Cat)tom;
cat.catchMouse();
} else {
System.out.println("对象tom在内存中不是Cat类型或者Cat的子类类型");
}
//希望狗可以抓老鼠
//使用多态的形式创建狗对象
Animal twoHa = new Dog("TwoHa",3);
//将Animal类型的对象向下转型为Cat类型对象
if (twoHa instanceof Cat) {
Cat c = (Cat)twoHa;
c.catchMouse();
} else {
System.out.println("对象twoHa在内存中不是Cat类型或者Cat的子类类型");
}
内部类:
在一个类中存在另外的一个
分类:
成员内部类
实例成员内部类(实例内部类)
静态成员内部类(静态内部类)
局部内部类
标准局部内部类(局部内部类)
匿名局部内部类(匿名内部类)
学习内部类的小技巧:
1.学习目的
2.内部类的权限访问级别
3.语法格式
4.注意事项(内部类对象创建和内部类和外部类的互相访问特点)
成员内部类的学习目的
在程序中,有些场景个别类不想被外界(本包之外或本类之外)进行访问,只进行自己使用,这个时候需要将类进行私有化,但是类文件的权
限访问级别只能是public和缺省,需要将这个类声明在某个类的成员位置,一旦这个类成为某个类的成员,该类的权限访问级别四种都
可以进行修饰使用
应用场景:
1.底层源码讲解
2.编写算法,设计模式,框架的底层源码时
实例成员内部类(实例内部类)
1.学习目的
在程序中,有些场景个别类不想被外界(本包之外或本类之外)进行访问,只进行自己或本包中使用,这个时候需要将类进行私有化,
但是类文件的权限访问级别只能是public和缺省,需要将这个类声明在某个类的成员位置,一旦这个类成为某个类的成员,该类的
权限访问级别四种都可以进行修饰使用
2.权限访问级别:
四种都可以,推荐private和缺省
3.语法格式:
public class 外部类类名 {
修饰符 class 内部类类名 {
}
}
4.注意事项:
(1)内部类的对象创建方式
当内部类的权限访问级别不是private时
a.如果后续需要使用外部类对象
外部类类名 外部类对象名 = new 外部类类名(实参);
外部类类名.内部类类名 内部类对象 = 外部类对象名.new 内部类类名(实参);
b.如果后续不需要使用外部类对象
外部类类名.内部类类名 内部类对象 = new 外部类类名(实参).new 内部类类名(实参);
当内部类的权限访问级别是private时
必须在该外部类的实例成员中进行对象的创建
内部类类名 内部类对象名 = new 内部类类明();
(2)在实例成员内部类中无法声明静态成员,如果需要声明静态成员,选择静态成员内部类即可
(3)外部类访问实例内部类的实例成员时,需要通过内部类对象进行访问,而且可以访问内部类中的私有成员
(4)在内部类中可以访问外部类所有的非同名成员
(5)在内部类中访问外部类的同名成员时,需要通过"外部类类名.this".实例成员名进行区分
静态成员内部类(静态内部类)
1.学习目的
在程序中,有些场景个别类不想被外界(本包之外或本类之外)进行访问,只进行自己或本包中使用,这个时候需要将类进行私有化,
但是类文件的权限访问级别只能是public和缺省,需要将这个类声明在某个类的成员位置,一旦这个类成为某个类的成员,该类的
权限访问级别四种都可以进行修饰使用,且需要在其内部声明静态成员,考虑实例内部类无法声明静态成员,需要声明静态内部类
2.权限访问级别:
四种都可以,推荐private和缺省
3.语法格式:
public class 外部类类名 {
修饰符 static class 内部类类名 {
}
}
4.注意事项:
(1)在静态成员内部类中可以声明实例成员,如果需要访问这些实例成员,需要创建内部类对象才能进行访问
(2)在静态成员内部类中无法直接访问外部类的非静态成员,如果需要访问需要在静态内部类中创建外部类对象才能访问
(3)在静态成员内部类中的实例方法或构造器里可以使用this或super关键字
(4)在外部类中可以访问静态成员内部类的私有成员
(5)在内部类中可以访问外部类所有的非同名成员
(6)在内部类中访问外部类的同名成员时,
如果该同名成员是静态成员,通过类名.静态成员名进行区分
如果该同名成员是实例成员,只能通过创建外部类对象进行区分,无法使用外部类类名.this
标准局部内部类(局部内部类)
1.学习目的
(1)笔试题
(2)学习匿名内部类的前提条件
2.权限访问级别
只能是缺省
3.语法格式:
public class 外部类类名 {
修饰符 返回类型 方法名 () {
class 内部类类名 {
}
}
}
4.注意事项
(1)局部内部类修饰符可以是abstract或final,但不可以同时修饰一个类,也不可以声明为static
(2)局部内部类对象只能在其所属的方法中进行对象的创建
(3)在局部内部类中不可以声明静态成员
(4)当局部内部类所属方法的局部变量和该局部内部类中的实例变量或局部变量发生同名的时候,在该局部内部类中无法进行访问
(5)局部内部类如果需要使用所属方法的局部变量,该局部变量在局部内部类中被JVM自动填充一个final关键字,不能进行修改
匿名局部内部类(匿名内部类):
学习目的:
(1)简化多态情况下接口的使用步骤
(2)学习Lambda表达式的前提条件
语法格式:
接口名 实现类对象名 = new 接口名(){
接口实现类的类体
};
注意事项:
匿名内部类中的匿名指的是接口的实现类没有类名
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)