For example: Foo ab=new Dog();
Saving object of another type class to reference of another class!
For example: Foo ab=new Dog();
Saving object of another type class to reference of another class!
Yes if Foo is an interface then this approach gives you more control on your code. You achieve Polymorphism
, Plug-ability
, Maintainability
and Loose coupling
characteristics of java programming language.
Let's say if you are supposed to connect to oracle from your application and written the code like this
OracleDrive driver= new OracleDriver()
driver.connect();
it will solve your problem. But will make your code tightly coupled with OracleDriver. Your application won't compile at all if you remove Oracle related jar from your classpath. And if someone ask you make your app connect to different DBs based on their configuration then you end up with multiple if
s based on your application supported DBs. which is bad practice as per programming standards.
If you all DB drives implements an interface Driver
then you can load driver based on configuration without tightly coupling your code to any specific driver class like this
Driver driver = properties.get(db.driver.class)
driver.connect()
Now you see that you need to change you application to connect to MySql you just need to set that class in your configuration file.
Hope you got my point!
并不总是需要做类似Foo foo = new Bar()
的事情,但通常建议参考接口而不是实现。这样您就可以更改您的实现,而无需更改其他代码。例如,如果您使用 Lists 做某事并使用 ArrayLists,您可能会这样做:
ArrayList<Integer> numbers = new ArrayList<>();
//Do stuff with numbers
但是,您可能不在乎它是哪种列表,因此您可能会更好
List<Integer> numbers = new ArrayList<>();
//Do stuff with numbers
现在,你拥有什么样的 List 并不重要,也许你会发现使用 LinkedList 可以获得更好的性能,你可以使用它而不是更改任何其他代码。
我想说的是,当其他调用者接收对象时,多态性是最重要的。
它对方法参数更有用。
class Animal {
public boolean hasHair = true;
public void speak() {}
}
class Dog extends Animal {
public void speak() {
System.out.println("Woof!");
}
}
class Person {
public void shave(Animal a) {
a.hasHair = false;
a.speak();
}
}
class Main {
public static void main(String[] args) {
Person joe = new Person();
Dog fido = new Dog();
joe.shave(fido);
}
}
在这种情况下,Person 可以为任何 Animal 剃毛,但我们将它传递给 Dog。
Animal fido = new Dog();
会不太有用,因为我们知道 fido 是一只狗,但考虑一下:
Animal pet;
if(joe.prefersCats)
pet = new Cat();
else
pet = new Dog();
简单的回答,你不能那样做。
更复杂的答案,只有当 'Dog' 是 'Foo' 的类型时,你才能做到这一点。我们什么时候说 Dog 是 'Foo' 的类型是 Dog 是实现 Foo(如果是接口)还是扩展 Foo(如果是另一个类或抽象类)
现在,利用 Coding to Interfaces(您的问题的技术名称)的优势是
1)Java 的多态性基于此(多态性使行为的运行时变化成为可能,请在 java 中搜索多态性以获取更多信息) 2)您正在通过这种方法使接口独立于实现。
希望这回答了你的问题。
这种类型的声明是唯一可能的
Foo ab=new Dog();
如果 Dog 类扩展类 Foo 或 Foo 是由 Dog 类实现为的接口
class Dog extends Foo { .... }
或者
class Dog implements Foo { ... } //Here Foo is an interface
我认为,如果您将具有继承接口或继承类的类对象初始化为所有基类函数,那么属性将在您的派生类对象中可用。如果您要初始化具有相同基类和不同派生类的多个对象,这种类型的声明将派上用场。
例如,
public class MyObject
{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class MyFile extends MyObject
{
private String extension;
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
}
public class MyFolder extends MyObject
{
}
如果你正在初始化
MyObject file = new MyFile();
这确实没有用,但是当我们要初始化时它会很有用
List<MyObject> listOfFilesFolders = new ArrayList<MyObject>();
listOfFilesFolders.add(new MyFile());
listOfFilesFolders.add(new MyFolder());
这个“listOfFilesFolders”可以是另一个类的私有变量,它保持文件/文件夹列表的存在。
或者我们希望具有如下功能
private void SomeFunction(MyObject obj)
{
}
它可以获取从基类派生的所有对象,并根据基类的属性或功能进行操作。
在这里查看我的旧答案之一:
这是关于我的一位教授曾经告诉我们的轶事的轶事。
长话短说,当您进入更复杂的系统时,您想要这样做的原因会变得更加清晰。将规范(接口/抽象类及其契约)与实现(具体类)分离的能力是一个强大的工具,它使编写新实现变得非常容易,而无需在应用程序的其他地方更改代码。您在代码中使用规范,例如规范:
public interface Animal { ... }
您的实施:
public class Dog implements Animal { ... }
然后在代码中,尽可能使用规范:
Animal a = new Dog();
a.eat(); // All animals eat, so eat() is on the Animal interface
除非您绝对需要使用实现本身:
Dog d = new Dog();
d.bark(); // Other animals don't bark, so we need to have the Dog here
这使您的代码更干净。例如,假设我有一个方法feedAndGroom
。如果我没有接口,我需要为我想要支持的每种动物创建一个新方法:
public static void feedAndGroom(Cat c) { ... }
public static void feedAndGroom(Dog d) { ... }
public static void feedAndGroom(Turtle t) { ... }
根据具体情况,每个代码块甚至可能看起来完全相同。更糟糕的是,当有人发现一种新动物时会发生什么?我们每次都必须添加一个新方法,这将导致大量的方法。所有这些重复的解决方案是围绕功能创建一个接口,然后使用一个方法:
public static void feedAndGroom(Animal a) { ... }
这将采用任何实现Animal
接口的东西。所有这些方法调用都是合法的:
feedAndGroom(new Cat());
feedAndGroom(new Dog());
feedAndGroom(new Turtle());
但是,这些方法调用也是合法的:
feedAndGroom(new Hyena());
feedAndGroom(new Lion());
feedAndGroom(new Panther());
我们可能不想尝试喂养和梳理这些动物,至少不是野生动物,所以我们可以添加一个名为DomesticatedAnimal
extends的新接口Animal
:
public interface `DomesticatedAnimal` extends `Animal` { ... }
并将我们的方法更改为:
public static void feedAndGroom(DomesticatedAnimal da) { ... }
然后代替实现Animal
,Dog
,Cat
和Turtle
类将实现DomesticatedAnimal
。例如:
public class Dog implements DomesticatedAnimal { ... }
这意味着Dog
它既是一个DomesticatedAnimal
,因为它直接实现它,也是一个Animal
继承自DomesticatedAnimal
extends Animal
。其他动物 、Hyena
、Lion
和Panther
只是实现Animal
接口。这意味着我们的新方法不会Animal
像原来的那样采用任何方法,而是将其限制为特定类型的Animal
对象。同时,任何为使用原始Animal
接口而编写的方法仍然适用于所有涉及的对象。
您总是可以用对子类的引用代替基类。
换句话说,你总是可以使用更具体的东西来代替更一般的东西——所以如果你有一行代码需要一个 Canine,你可以给它发送一个 Dog 的引用。所以这行代码:
Foo ab=new Dog();
意味着您正在实例化一个新Dog
对象,然后创建一个
Foo
名为的引用ab
并将其指向该对象。