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

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

标题意思有点绕,说白了就是下面使用方式的选择问题

//implA 为接口 ClassB为其实现类
implA A=new ClassB();//接口类型的引用变量A 去接收对象地址
or
ClassB A=new ClassB();//类类型的引用变量A 去接收对象地址
  • 1
  • 2
  • 3
  • 4

先附上有关接口的相关知识 
知乎Java中的接口有什么作用? 
博客园深入理解Java的接口和抽象类


我们假设有一个接口A,和它得实现类B,简化代码如下:

interface A { //接口A               
 //接口的方法声明必须是 public abstract ,即便不写默认也是
    public void fun();

}
public class B implements A {

    @Override
    public void fun() {
        //your coding
    }

}
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

A demo=new B();
  • 1

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

结论先把来吧丢出 

应该优先使用接口而不是类来引用对象,只有但存在适当的接口类型时 

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

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");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 三十
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

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

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

在第二版的“Effective Java”中也有说到这也问题 
Effective Java 2nd Edition,Item 52:通过它们的接口引用对象

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.


  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10

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



【转型问题】

继续上面的例子

 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
    }
  • 1
  • 2
  • 3
  • 4
  • 6

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

//p.batheSelf();替换为下面形式
((Cat)p).batheSelf();//向下转型,可正常调用执行
  • 1
  • 2

有关向上转型与向下转型的问题见下面的拓展链接

【参考】 
https://stackoverflow.com/questions/3383726/java-declaring-from-interface-type-in​​stead-of-class 
【扩展】 
重新认识java(五) - 面向对象之多态(向上转型与向下转型)

猜你喜欢

转载自blog.csdn.net/qiuzhongweiwei/article/details/80762324
今日推荐