前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 中到底是应该用接口类型 还是实现类的类类型去引用对象?

Java 中到底是应该用接口类型 还是实现类的类类型去引用对象?

作者头像
浩Coding
发布2019-07-03 12:49:24
1.6K0
发布2019-07-03 12:49:24
举报
文章被收录于专栏:浩Coding浩Coding

如题,Java 中到底是应该用接口类型 还是实现类的类类型去引用对象?首先贴出答案:

应该优先使用接口而不是类来引用对象,但只有存在适当的接口类型时 。换而言之,如果存在适当的接口类型,那么参数,返回值和字段都应该使用接口类型。 如果你养成使用接口类型的习惯,你的程序将更加灵活。 如果没有合适的接口存在,则通过类来引用对象。

因为定义接口的目的是让代码有更强的可扩展性隐藏内部代码解耦

标题描述的情况在实际应用中的代码:

代码语言:javascript
复制
//implA 为接口 ClassB为其实现类
implA A=new ClassB();//接口类型的引用变量A 去接收对象地址
//或者
ClassB A=new ClassB();//类类型的引用变量A 去接收对象地址

什么时候接口类型不适合做引用呢,我们看下面这个例子:

代码语言:javascript
复制
interface A { //接口A               
    //接口的方法声明必须是 public abstract ,即便不写默认也是
    public void Save();

}
public class B implements A {
    @Override
    public void Save() {
        //TODO
    }
}

如果我们要使用B类对象,调用B类方法,我们很容易就会习惯的写出:

代码语言:javascript
复制
A temp=new B();

用接口类型的引用变量temp,去接收实现类B实例化出来的对象地址(这里的=是传递的地址)。

为什么不是B demo=new B(); 呢,这样也不会有问题啊?(当然A demo=new A();是不可能的,因为接口是不能用来实例化对象的,但可以用来声明一个接口类型的引用变量)。

我们回到我们文章开头的结论:应该优先使用接口而不是类来引用对象,但只有存在适当的接口类型时 。

这句话是什么意思呢,我们再来看一个例子,代码如下:

代码语言:javascript
复制
public class InterfaceTest {

    public static void main(String[] args) {

        PetInterface p = new Cat();
        p.talk();
        p.batheSelf();//无法调用 ,报错The method batheSelf() is undefined for the type PetInterface
    }

}

interface PetInterface {                

    public void talk();

}

class Dog implements PetInterface {

    @Override
    public void talk() {
        System.out.println("Bark!");
    }

}

class Cat implements PetInterface {

    @Override
    public void talk() {
        System.out.println("Meow!");
    }

    public void batheSelf() {
        System.out.println("Cat bathing");
    }

}

我们看到,方法batheSelf()仅仅存在实现类中时,若我们仍然使用接口来引用对象时PetInterface p = new Cat(),那些仅仅存在实现类中的方法,是无法直接调用的即p.batheSelf()无法调用会报错。所以这时使用Cat p = new Cat()即类来引用是更好的。

也就是说,使用接口类去引用对象是有前提条件的——即实现类中全是接口类的方法的实现,没有自己单独的方法。当实现类存在自己的方法时,使用实现类来声明变量。

在第二版的《Effective Java 》中也有说到这也问题

Effective Java 2nd Edition, Item 52: Refer to objects by their interfaces.

代码语言:javascript
复制
If appropriate interface types exist, then parameters, return values, 
 and fields should all be declared using interface types. 

If you get into the habit of using interface types,
 your program will be much more flexible. 

It is entirely appropriate to refer to an object by a class if no appropriate interface exists.

翻译过来大概就是: 如果存在适当的接口类型,那么参数,返回值和字段都应该使用接口类型。 如果你养成使用接口类型的习惯,你的程序将更加灵活。 如果没有合适的接口存在,则通过类来引用对象是完全合适的。

【转型问题】

继续上面的例子:

代码语言:javascript
复制
 public static void main(String[] args) {

        PetInterface p = new Cat();//向上转型 Cat->PetInterface 
        p.talk();
        p.batheSelf();//无法调用 ,报错The method batheSelf() is undefined for the type PetInterface
    }

我们说直接p.batheSelf()会报错,这是因为向上转型的过程中Cat->PetInterface ,对PetInterface 接口造成的唯一效应就是函数的“遗失”而非”获得”(即遗失了实现类自己独有的函数方法batheSelf()),而Cat向上转型至PetInterface可能会窄化其功能,但无论如何不会窄于PetInterface接口功能。

当然也存在向下转型,

代码语言:javascript
复制
//p.batheSelf();替换为下面形式
((Cat)p).batheSelf();//向下转型,可正常调用执行

参考文章:

Java 中到底是应该用接口类型 还是实现类的类类型去引用对象?

用接口类型的引用变量demo,去接收实现类B实例化出来的对象地址(这里的=是传递的地址)。为什么不是B demo=new B(); 呢,这样也不会有问题啊?(当然A demo=new A();是不可能的,因为接口是不能用来实例化对象的,但可以用来声明一个接口类型的引用变量)。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浩Coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 【转型问题】
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档