面向对象(Java)--- 引用变量

变量

        定义:能够存储可变数据的容器成为变量。变量内部存储的是数据的数值。就好比篮子里装的是苹果。

        基本变量

        定义:储存基本数据类型的变量。

        引用变量

        定义:储存引用数据类型的变量。在java中表示存储了引用数据类型(数组,类)对象的地址的变量。内部存储的的是对象的内存地址。好比篮子里装的不是苹果,而是苹果的位置。我们可以将引用变量看成被引用的对象使用。

        引用变量的默认值为:null(空)。

        java中引用变量也是常用且重要的内容,所以本篇将其分开表达。

引用变量的声明以及使用

//声明变量以及使用
类名 变量名 = 对象;
//声明一维数组以及使用
类型名[] 变量名 = new 类型名[]{对象,对象...};
类型名[] 变量名 = new 类型名[数组长度];
类型名[] 变量名 ={对象,对象...};

 我们可以通过 . 的方式进行调用引用对象允许访问的方法与属性。

class A{
    public int i=1;
    public void f1(){
        System.out.println("f1()");
    }
}
class Main{
    public static void main(String[] args){
        A a=new a();
        System.out.println(a.i);
        a.f1();
    }
}

         我们如果引用的类型没有您想要调用的方法时将报出编译错误。

子类的引用变量与父类的引用变量

        在现实中,我们是动物类群中的人类类群,我们是人类,但我们也可以称为动物,java也是类似,父类的引用类型变量可以引用子类的对象

//格式
父类 变量名 = new 子类名(参数);
//例子
Object object= new String("string");//Object是所有类的基类(即父类的父类的。。)

        此时我们虽然引用的是子类对象,但我们使用的是父类的引用变量,编译器将会把引用变量识别为声明时的类型,这就出现一个问题,当我们想使用子类对象的方法或属性,但父类没有对应子类方法时,将会出现编译错误,该怎么办?

        强制类型转换

           我们可以使用 ()内添加数据类型的方式进行数据的强制转换。将使用的类型转换为我们需要的类型。

//基本数据类型的强制转换
int i= (int)1.2;

//引用数据类型的强制转换
B a= (B)new A();//假设B继承A

         基本数据类型变量存储的是数值,往往强制转换往往伴随着数据的丢失,或者溢出。如途中1.2转换为int类型时,将会伴随着小数点后的数据丢失。

        由于引用数据类型保存的是数据的地址,不会对实际内存中的实例对象造成影响。但是会存在一个问题。

        我们无法将父类对象赋值给子类。即使使用了强制类型转换也会报出 类型转换异常 。这就像是父亲穿不下孩子的衣服一样。当两个数据类型不匹配时,我们将无法进行强制转换。

        那怎么判断呢?

        instanceof关键字

        instanceof将比较对象与一个数据类型是否匹配。当匹配时返回true;反之false;

//格式
    需要判断的对象 instanceof 比较的数据类型 //返回boolean值
//例子
boolean b = new String() instanceof Object;

         我们先进行判断数据类型是否匹配在进行数据的强制转换。

//格式
if( 需要判断的对象 instanceof 要转换的数据类型);
    要转换的数据类型引用变量 = (要转换的数据类型)需要判断的对象; 
//例子
//假设A是B的父类
A a=new B();
if( a instanceof B)
    B b=(B)a; 

        父类添加对应的方法或属性

        这个很容易理解,就是在父类中添加变量能访问到的相同方法和属性。这能解决编译问题,调用的方法在运行阶段调用的也是引用的子类对象的方法

        但是添加相同的属性虽然能解决编译问题,但还是调用的是父类的属性而不是子类的属性。缺少属性建议按照上条的方法进行。 

接口或抽象类与引用变量

        我们无法直接使用接口或抽象类但我们可以给接口引用变量赋值实现接口方法的类的对象,或者使用上节提到的匿名类的方式进行引用。

//例子
class A extends C implements B{
    void f1(){
    
    }
    void f2(){
        
    }
}

interface B{

    void f1();
}
abstract class C{
    public abstract void f2();
}
class Test{
    B b1 = new A();
    B b2 = new B(){
        void f1(){
        
        }
        void f2(){
        
        }
    }
}

向上造型

        大家想过java作为强类型语言,类型之间不能随意转换。为什么允许父类引用变量可以直接引用子类对象呢?

        根据上文我们可以知道,当父类或者借口的引用变量引用子类对象时,在编译时将被作为父类使用。这就意味着,子类自己相比父类或者借口特有的方法以及属性将无法使用。子类的方法被屏蔽了!这意味着我们能更加专注于父类或者接口中的方法。当编译时引用变量使用的被引用的对象,所以调用的是被引用的对象同名方法(后续我们将讲到的重写方法 重写,override)。这意味着我们为子类提供了一个模板,这个标准中我们将只能使用父类或接口提供的方法或属性。

class A{
    void f1(){
        System.out.println("A");
    }
}
class B extends A{
    public int i=1;
    void f1(){
        System.out.println("B");
    }
}

class Test{
    public static void main(String[] args){
        A b = new B();
        b.f1();//将输出 B
        //以下为错误示范!!!!
        //将发生编译错误。因为A类中没有 变量 i;
        b.i;
    }
}

         在上文中虽然B有属性 i,但是引用变量 b 类型是 A,A中没有属性 i 所以我们无法使用。只能使用A类B类都有的f1()方法。

        不过我们如果想要一个模板时,一个具体的类作为模板会出现问题。

public class Test {
    public static void main(String[] args) {
        A a=new B();
            a.f1();
    }
}
class A{
    void f1(){
        System.out.println("aaa");
    }

}
class B extends A{
}

         我们可以发现子类中没有f1()方法,这时将出现问题,这时虽然编译不会出错,并且会调用父类的方法,就像是一个三角的模具没有放入东西,倒出来的却也被叫三角。但是我们需要的是这个模板可以完整的“复制”。

        这就是为什么我们使用抽象类或者接口作为模板。

        由于抽象的方法无法直接使用,需要进行实现,当继承了抽象类或者实现接口的方法时,子类必然实现了这类抽象方法,即完整的“复印”下来。

interface A{
    void f1();
}
abstract class B{
    abstract void f2();
}

class C extends B implements A{
    //实现子类必须实现继承抽象类或者接口的抽象方法
   void f1(){
    }
   void f2(){
    } 
}

         

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值