如何理解对象赋值给接口的操作(关键在对象!)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 如何理解对象赋值给接口的操作(关键在对象!)

今天被人问了一个问题,然后我去查了源码,虽然解决了问题,但进而引发我另一个思考——如何理解对象赋值给一个接口。


众所周知,如果一个对象赋值给它的接口,那么这个用接口“接”的对象只有接口所定义的方法和属性,失去了原本对象独有的方法和内容。(当然也规范了代码,不过本文暂不讨论这些)


按我之前的理解就是——如果把原对象比作一辆拥有众多功能的跑车,那么接口就是大家统一规格的小汽车。如果把这“跑车”赋值给小汽车,那么势必会失去一些独有的功能和属性。


但原来的属性和方法真会消失吗?


我突然又想到很多框架为了通用性,方法返回值常常为Object,那如果是Object,失去了原来的的属性和方法,只保留Object的属性和方法的话,那框架如何继续操作呢?


这显然是不对,因此我进行了简单的测试:

q1.png

这里我们看到就算我们用接口接对象,对象依旧能够通过强转回原来的样子,而就算是接口Object,打印时依旧会输出这个对象的值。


这已经充分地说明了一点——用接口接对象,其属性和方法并没有丢失。


那我们该如何理解呢?


实际上我们得从Java的对象理解开始说起。


对象是什么?

学过c语言的小伙伴都知道c中有个叫做指针的东西(相当于指向内存地址的坐标),java相对于c来讲的一大“优势”(有人可能认为是优势,也有人可能认为是劣势)就是Java中没有指针,这极大的减少了因指针滥用的风险。

但java中真的没有指针吗?


Java中处处都是指针!

没错,Java处处都是指针,Java的对象就是指针,这也是我们为什么要复制一个相同的对象时得用clone方法,这也是我们为什么比较两对象值是否相等时要用equals方法而不是==。


因为对象就是指针!!!


以下是我在网上找到的一段话,概括的挺好的,分享给大家


JAVA中的对象类型本质上应该叫做 对象指针 类型。那么传统的对象类型呢?在JAVA里已经不见了踪影!

既然没有了传统的对象类型,那么 对象指针变量 前面的也就可以不要了。对象指针变量也就可以简称为对象变量了,

反正也不会和其它概念混淆! 所有的对象变量都是指针,没有非指针的对象变量,想不用指针都不行,这就是指针的泛化和强化。

不叫指针了,就叫对象变量,这就是概念上的淡化和弱化。 没有了指针的加减运算,也没有了*、->等运算符,这是对指针的简单化。


既然清楚了Java中对象即是指针,那么我们回到现在的问题上来。


如果把一个对象赋值给一个接口,那么实际上会发生什么呢?

真的去重新开辟了块内存空间,再把原来的属性值装进这个空间吗?

不不不,对象只是指针,对象的赋值只是指针的复制而已,把对象赋值给接口也只是把这个对象的地址给这个接口而已!


那么对象实际改变了吗?

并没有!

那改变了什么呢?

改变的只是程序“解析”(这里我愿意用解析一词来形容)这个对象或者说这个指针所指向的内存空间而已!

因为“解析的格式”(或者说解析的标准),对于一些不认识的属性和方法你当然就不能使用喽!


总结

对象赋给接口只是指针而已,至于为什么不能使用原来对象中的方法和属性,当然是因为“解析”的格式不同导致程序根本不认识接口中没有的方法和属性喽!


建议

虽然Java中没有指针的概念,但是最好把它看做指针,这对于你理解底层机制或者算法结构都有很多好处,也让你避免出现诸如为什么对象复制要用clone方法之类的疑惑了。


-----8月8日更新-------

自从小小的接触了下字节码后,对这个问题有了新的理解


方法在编译器会在编译阶段就进行静态分派。指向的还是父类的类,父类里面没有test3()方法


按照这个思路,赋值给接口后,虽然指向的还是实现类,但是编译器会去找其接口(也就是它的静态类型)


详细可以去看这篇文章https://www.cnblogs.com/bigbaby/p/12348956.html


---------11月13日更新----------------

随着自己技术的成长,对此问题有了更深层次的理解,所以重新写了另一篇文章如何理解子类对象赋值给父类(深入理解动态绑定、静态绑定)

相关文章
|
机器学习/深度学习 存储 Java
分支结构 && 方法的创建和调用 && 方法递归 && 数组的创建和使用 && 类和对象的认识 && 内部类 && 认识继承
分支结构 && 方法的创建和调用 && 方法递归 && 数组的创建和使用 && 类和对象的认识 && 内部类 && 认识继承
57 0
|
7月前
|
存储 Java
Java数组与带参数方法:定义、调用及实践
Java数组与带参数方法:定义、调用及实践
80 1
|
7月前
|
编译器 数据安全/隐私保护 C++
【类与对象】封装&对象的初始化及清理
【类与对象】封装&对象的初始化及清理
|
7月前
|
存储 编译器 程序员
【C++】类和对象①(什么是面向对象 | 类的定义 | 类的访问限定符及封装 | 类的作用域和实例化 | 类对象的存储方式 | this指针)
【C++】类和对象①(什么是面向对象 | 类的定义 | 类的访问限定符及封装 | 类的作用域和实例化 | 类对象的存储方式 | this指针)
对象的相等和引用相等的区别
对象的相等和引用相等的区别
|
安全 Java
创建对象的相关知识补充
创建对象的相关知识补充
65 0
|
设计模式
单子设计模式 (对创建初始对象为静态,构造函数私有,返回值为对象的创建函数,private应用)
单子设计模式 (对创建初始对象为静态,构造函数私有,返回值为对象的创建函数,private应用)
单子设计模式 (对创建初始对象为静态,构造函数私有,返回值为对象的创建函数,private应用)
|
JavaScript 前端开发 索引
带你手写一个对象,深入理解可迭代对象是什么,与类数组有什么区别
带你手写一个对象,深入理解可迭代对象是什么,与类数组有什么区别
187 0
带你手写一个对象,深入理解可迭代对象是什么,与类数组有什么区别
|
编译器 C++
C++继承中的对象模型与继承中构造和析构顺序
继承中的对象模型 问题:从父类继承过来的成员,哪些属于子类对象中? 示例: class Base { public: int m_A; protected: int m_B; private: int m_C; //私有成员只是被隐藏了,但是还是会继承下去
108 0
C++继承中的对象模型与继承中构造和析构顺序
java反射构建对象和方法的反射调用
java反射构建对象和方法的反射调用Java反射技术应用广泛,其能够配置:类的全限定名,方法和参数,完成对象的初始化,设置是反射某些方法。可以增强java的可配置性。 1.1 通过反射构建对象(无参数):   例如我们使用 ReflectServiceImpl 类讲解这个例子 1 public class ReflectServiceImpl {2 public void sayHello(String name){3 System.out.println("hello"+name);4 }5 }我们通过反射的方法去构建它。
876 0