一:多态
1、多态的前提:
(1)要有继承关系
(2)要有方法的重写。 其实没有重写也是可以的,但是不重写就没有意义,动物都有吃这个方法,但是每个具体的动物吃的实现不一样,变现出不同动物的特有属性
(2)要有父类的引用指向子类对象 父类名 f = new 子类名(...);
2、多态访问成员的特点(左父右子)
(1)成员变量:编译看左,运行看左
(2)构造方法:创建子类对象的时候,先访问父类中的构造方法,对父类的数据先进行初始化
(3)成员方法 :编译看左,运行看右。 因为成员方法存在重写,所以访问看右边,若子类没有方法,去父类中找。
(4)静态成员方法 :编译看左,运行也看左。 由于被static修饰的成员都是与类相关的,这里不是重写,所以运行的时候,访问的还是左边的。
class Fu3{
int num = 100;
public void show(){
System.out.println("这是父类中show()方法");
}
public static void fun(){
System.out.println("这是父类中的静态fun方法");
}
}
class Zi3 extends Fu3{
int num = 1000;
@Override
public void show(){
System.out.println("这是子类中的show()方法");
}
public void show2(){
System.out.println("这是子类特有的方法1");
}
public static void fun(){
System.out.println("这是子类中的静态fun方法");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建了一个对象
Fu3 f = new Zi3();
System.out.println(f.num);
// f.show2();//报错,编译看左,但父类中没有该方法。
f.show(); // 这是子类中的show()方法,编译看左,运行看右
f.fun(); //这是父类的fun()方法,编译看左,运行看左
}
}
class Fu{
Fu(){
System.out.println("这是父类构造方法");
}
public void show(){
System.out.println("父类show");
}
public static void show2(){
System.out.println("父类show2");
}
}
class Zi extends Fu{
Zi(){
System.out.println("这是子类构造方法");
}
@Override
public void show() {
System.out.println("子类1");
}
public static void show2(){
System.out.println("子类2");
}
}
class daoYong{
public static void dy(Fu f){ //Fu f = z = new Zi();
f.show();
f.show2();
}
}
public class Test2 {
public static void main(String[] args) {
Zi z=new Zi();//创建子类对象,初始化父类构造方法,在初始化子类构造方法。
daoYong.dy(z);//静态方法可以用类直接调用,可以看成Fu f=new Zi();
//f.show 是成员方法,编译看左运行看右,f.show2是静态成员方法,编译看左,运行看左。
}
}
3、向下转型
多态无法访问父类中的方法名一样的方法,且不能访问子类中特有的方法。
如何访问子类中特有的方法,java提供了向下转型的方法 将父类的引用强制转换成子类的引用
向下转型: 子类类名 变量名 = (子类类名)父类的引用;
这样可以调用子类中特有的方法,不用看父类中有没有。
注意:要求转型的类与父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类。
向上转型:父类名 f = new 子类名(...);
二、抽象类abstract
1、特点:
(1)抽象类和抽象方法都要用一个关键字修饰:abstract 修饰一个类 放在class的前面 举例: abstract class Animal3{}
修饰一个方法 一般是放在权限修饰符后面 定义一个抽象的show方法 举例:public abstract void show();(没有大括号,没有方法主体)
abstract不能修饰构造方法。
(2)有抽象方法的类一定要是抽象类,抽象类不一定要有抽象方法,具体的类中不能有抽象方法,抽象类中既可以存在抽象方法 也可以存在有方法体的方法。
(3)抽象类不能被实例化(创建对象) , 通过多态的形式,使用具体的子类去实例化调用方法,专业术语称之为:抽象多态
(4)如果继承抽象类的是一个具体的子类,必须要重写该抽象类中所有的抽象方法 如果继承抽象的也是一个抽象类,可以不去重写父类中的抽象方法,也可以选择性的去重写。
2、抽象类的成员的特点:
成员变量: 既可以是变量,也可以是常量
构造方法: 可以存在构造方法,抽象类不能被实例化,要想初始化子类,必须先初始化父类,所以这里构造方法是提供初始化父类的作用
成员方法: 可以是抽象方法,但是具体的子类必须要重写该方法 也可以不是抽象方法,提高代码的复用性。
abstract class Animal5{
public abstract void eat();//抽象方法没有主体
public abstract void sleep();
}
class Dog5 extends Animal5{
@Override
public void eat() {
System.out.println("狗吃肉");
}
@Override
public void sleep() {
System.out.println("狗侧着睡");
}
}
class Cat5 extends Animal5{
@Override
public void eat() {
System.out.println("猫吃🐟");
}
@Override
public void sleep() {
System.out.println("🐱趴着睡");
}
}
public class AbstractTest1 {
public static void main(String[] args) {
//抽象多态创建一个对象
Animal5 a = new Dog5();
a.eat();
a.sleep();
//抽象多态创建第二个对象
Animal5 c = new Cat5();
c.eat();
c.sleep();
}
}
三、接口
1、定义格式
interface 接口名 {}
2、implements
接口不能直接实例化,需要多态的形式进行实现,由具体的子类进行实例化,叫做接口多态(以后经常用),可以把接口类看成父类。
class 子类名 implements 接口名{ }
class 子类名 extends 父类名 implements 接口名 { } 该子类继承了父类,又实现了接口类。
具体子类要实现接口类必须重写接口类中的成员方法。
抽象类实现接口的时候,可以选择不实现接口中的方法,也可以选择性的实现
3、接口中成员的特点:
(1)成员变量: 只能是常量,并且是静态的 JVM在真正运行之前会自动补齐修饰符:public static final
(2)构造方法: 接口中没有构造方法。
(3)成员方法: 接口中的方法只能是抽象方法,没有方法体,连大括号都没有,JVM在真正运行之前会自动补齐修饰符:public abstract
4、类与类,类与接口,接口与接口的关系
类与类: 存在继承关系,只能进行单继承,不可以继承多个,但是可以是多层继承
类与接口: 实现关系,可以是单实现,也可以是一次性实现多个接口,也可以在继承一个类的同时,实现多个接口
接口与接口: 存在的是继承关系,可以进行单继承,也可以进行继承多个。
interface Inter{
public static final int a = 10;//public static final不写也会默认
public abstract void fun();
public abstract void fun2();
}
class Demo extends Object implements Inter{
@Override
public void fun() {
System.out.println("Demo类中实现玩游戏方法");
}
@Override
public void fun2() {
System.out.println("Demo类中实现玩游戏方法2");
}
}
abstract class Demo2 implements Inter{
@Override
public void fun() {
System.out.println("抽象类中实现接口抽象方法");
}
}
public class InterfaceDemo2 {
public static void main(String[] args) {
Inter i = new Demo();
System.out.println(i.a);
System.out.println(Inter.a);
i.fun();
}
}
四:引用数据类型
1、形式参数
类:当类作为方法的形式参数的时候,实际上需要的是该类的对象
抽象类:当抽象类作为形式参数传参的时候,实际上需要的时候该类子类实现对象的地址值,利用多态的形式创建
接口:当接口作为形式参数传参的时候,实际上需要的是该接口的实现类对象的地址值,利用接口多态的方式创建
2、返回值
类:当类作为方法的返回值的时候,实际上返回的是该类对象的地址值。
抽象类:当抽象类作为返回值的时候,需要返回的是该抽象类的子类对象
接口:当接口作为返回值类型的时候,需要的是实现该接口的类的对象
五:权限修饰符
其他包中的子类要想使用被protected修饰的方法,使用super关键字调用
类及其组成可以用的修饰符:
修饰符:
访问权限修饰:public,protected,默认的,private
状态修饰饰:static,final
抽象修饰符:abstract
类:
访问权限修饰:public,默认的,
状态修饰饰:final
抽象修饰符:abstract
成员变量:
访问权限修饰:public,protected,默认的,private
状态修饰饰:static,final
构造方法:
访问权限修饰:public,protected,默认的,private
成员方法:
访问权限修饰:public,protected,默认的,private
状态修饰饰:static,final
抽象修饰符:abstract
常见的修饰符组合:
成员变量:public static final 在接口中遇见
成员方法:
1、public abstract
2、public static
3、public final