Java学习基础知识4

多态和特殊类

4.1 多态

多态是指同一种事务表现出来的多种形态。
语法格式:父类类型 引用变量名 = new 子类类型()(父类类型指向子类)

案例:创建父类Shape类和子类Rect类,并进行测试

public class Shape {
    //1、私有化成员变量
    private int x;
    private int y;
    //3、提供无参和有参构造方法
    public Shape() {
    }
    public Shape(int x, int y) {
        setX( x );
        setY( y );
    }
    //2、提供公有的get和set方法
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }

    //4、自定义成员方法
    public void show(){
        System.out.println("横坐标为:" + getX() + ", 纵坐标为:" + getY() );
    }

    //5、自定义静态方法
    public static  void test(){
        System.out.println("Shape类中的静态方法!");
    }
}

public class Rect extends Shape {
    private int len;
    private int wid;

    public Rect(int len, int wid) {
    }
    public Rect(int x, int y, int len, int wid) {
        super(x, y);
        setLen( len );
        setWid( wid );
    }

    public int getLen() {
        return len;
    }
    public void setLen(int len) {
        if( len > 0 ){
            this.len = len;
        }else{
            System.out.println("长度值有误");
        }
    }
    public int getWid() {
        return wid;
    }
    public void setWid(int wid) {
        if( wid > 0 ){
            this.wid = wid;
        }else{
            System.out.println("宽度值有误");
        }
    }

    //在Rect类中重写show方法
    @Override
    public void show() {
        super.show();
        System.out.println( "长度为:" + getLen() + ", 宽度为:" + getWid() );
    }
    //自定义静态方法
    public static  void test(){
        System.out.println("-------Rect类中的静态方法!");
    }
}
public class ShapeRectTest {

    public static void main(String[] args) {
        //1、声明shape类型的引用指向Shape类型的对象并打印特征
        Shape s1 = new Shape(1,2);
        //当Rect类中没有重写show方法时,下面调用Shape类中的show方法
        //当Rect类中重写show方法时,下面调用Shape类中的show方法
        s1.show();
        System.out.println("-------------------");

        //2、声明Rect类型的引用指向Rect类型的对象并打印特征
        Rect r1 = new Rect(3,4,5,6);
        //当Rect类中没有重写show方法时,下面调用Shape类中的show方法
        //当Rect类中重写show方法时,下面调用Rect类中的show方法
        r1.show();
        System.out.println("-------------------");

        //3、声明shape类型的引用指向Rect类型的对象并打印特征
        Shape sr = new Rect(7,8,9,10);
        //当Rect类中没有重写show方法时,下面调用Shape类中的show方法
        //当Rect类中重写show方法时,下面代码在编译阶段调用Shape类的show方法,在运行阶段调用Rect类中的show方法
        sr.show();
        System.out.println("-------------------");

        //4、测试Shape类型的引用能否直接调用父类和子类独有方法
        int ia = sr.getX();
        System.out.println("获取到的横坐标:" + ia);
        //sr.getLen(); error Shape类中找不到getLen方法,也就是还在Shape类中查找

        //调用静态方法
        sr.test();//背景色为提示 不建议使用引用.的方式访问
        Shape.test();//推荐使用类名.的方式访问
    }
}

运行结果:

横坐标为:1, 纵坐标为:2
-------------------
横坐标为:3, 纵坐标为:4
长度为:5, 宽度为:6
-------------------
横坐标为:7, 纵坐标为:8
长度为:9, 宽度为:10
-------------------
获取到的横坐标:7
Shape类中的静态方法!
Shape类中的静态方法!

多态特点总结

  • 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法。
  • 当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法。
  • 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)。
  • 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。

4.2 引用类型转换

引用数据类型转换的方式有两种:自动类型转换和强制类型转换

//3、声明shape类型的引用指向Rect类型的对象并打印特征
//相当于从Rect类型到Shape类型的转换 也就是子类到父类的转换 小到大的转换 自动类型转换
Shape sr = new Rect(7,8,9,10);

//5、使用父类类型的引用调用子类独有的方法的方式
//相当于从Shape类型到Rect类型的转换,也就是父类到子类的转换 大到小的转换 强制类型转换
int ib = ((Rect) sr ).getLen();
System.out.println("获取到的长度为:" + ib ); //9
  • 自动类型转换主要是指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型;
  • 强制类型转换主要是指大类型向小类型的转换,也就是父类转向子类,也叫做向下转型或者显示类型转换。
  • 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
  • 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
  • 为了避免上述错误发生,应该在强转之前进行判断,格式如下:
    if( 引用变量 instanceof 数据类型 ) 判断引用变量指向的对象是否为后面的数据类型。
if( sr instanceof Rect ){
	System.out.println("可以放心转换!"); 
}else{
	System.out.println("不可进行强转!"); 
}

方法前面加上static关键字,就是静态方法,其很大的一个作用就是可以使用类名.的方式访问。

    //自定义成员方法既能打印矩形又能打印圆形对象特征
    // Shape s = new Rect( 1,2, 3, 4);//父类类型指向子类类型对象,形成多态
    // Shape s = new Circle( 5, 6, 7);
    //多态使用场景一:通过参数传递形成多态
    public static void draw( Shape s ){
        //编译阶段使用父类的版本,运行阶段调用子类重写以后的版本
        s.show();
    }

多态实际意义在于屏蔽不同子类的差异性实现通用编程带来不同效果。

4.3 抽象方法和抽象类

抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是,没有方法体。
具体格式如下:
访问权限 abstract 返回值类型 方法名( 形参列表 );
public abstract void cry();

抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是,不能创建对象。
两者关系

  • 抽象类中可以有成员变量,构造方法、成员方法;
  • 抽象类中可以没有抽象方法,也可以有抽象方法;
  • 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类。

实际意义

  • 抽象类的实际意义不在于创建对象而在于被继承。
  • 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对于子类具有强制性和规范性,否则也加做模板设计模式。

多态使用的场合之二:直接在方法体中使用抽象类的引用指向子类类型的对象

在以后开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法,若要更换子类时,只需将new关键字后面的子类类型修改而其他地方无需修改就可以立即生效,从而提高代码可维护性和可扩展性。
该方式缺点:父类引用不能直接调用子类独有的方法,若调用则需要强制类型转换。

注意
private 和 abstract 关键字不能共同修饰一个方法(private 不能被继承,更不必谈重写);
final 和 abstract 关键字不能共同修饰一个方法(final修饰方法不能被重写,而abstract必须要重写)
static和 abstract 关键字不能共同修饰一个方法( static将方法提升为类层级,可以使用类调用,而abstract不能实例化对象)

4.4 接口

基本概念:接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象类;定义类的关键字为class,而定义接口关键字是interface

接口里面只能有常量。
从java9开始,接口中可以使用私有方法。

public interface InterfaceTest{
	public static final int CNT = 1;
	private void show(){};
	public abstract void show();
}

不能多继承,但可以多实现(利用接口)。

名称关键字关系
类与类之间使用extends关键字表达继承关系只支持单继承
类与接口之间使用implements关键字表达实现关系支持多实现
接口与接口之间使用extends关键字表达继承关系支持多继承

接口与抽象类的区别

  • 定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
  • 继承抽象类的关键字是extends,而实现接口的关键字是implements。
  • 继承抽象类支持单继承,而实现接口支持多实现。
  • 抽象类中可以有构造方法,而接口中不可以有构造方法。
  • 抽象类中可以有成员变量,而接口中中只可以有常量。
  • 抽象类中可以有成员方法,而接口中只能有抽象方法。
  • 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8之前的版本)。
  • 从Java8开始增加新特性,接口中允许出现非抽象和静态方法,但非抽象方法需要使用default关键字修饰。
  • 从java9开始增加新特性,接口中允许出现私有方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值