【问题标题】:What is the use of passing object to another class reference in java?在java中将对象传递给另一个类引用有什么用?
【发布时间】:2013-10-07 04:49:53
【问题描述】:

例如:Foo ab=new Dog();

保存另一个类型类的对象以引用另一个类!

【问题讨论】:

  • 实现覆盖
  • 这与stackoverflow.com/questions/19203322/object-type-declaration/… 密切相关,如果不是重复的话。您可能会在该问题的答案中找到一些有用的信息。
  • @david->谢谢,但我们正在将另一个类型类的值(方法)分配给完全另一种类型..... int a="dog values"。类似于 String 类型到 int 的东西。
  • 如果您正在这样做,那么我会在您的未来看到编译错误。不需要水晶球。
  • @DavidWallace-->请多解释一点。

标签: java


【解决方案1】:

并不总是需要像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 可以获得更好的性能,你可以直接使用它而不是更改任何其他代码。

我会说多态性在其他调用者接收对象时是最重要的。

【讨论】:

  • 这和多态有关吗??
  • 我会说是,因为您通过接口引用对象,并且实现可以是任何东西,甚至是另一个实现的子类。
  • @RoundRobin 它实际上被视为run time polymorphism,其中引用在运行时与它所指向的对象绑定,而不是在一般情况下在编译器时。
【解决方案2】:

是的,如果 Foo 是一个接口,那么这种方法可以让您更好地控制您的代码。你实现了java编程语言的PolymorphismPlug-abilityMaintainabilityLoose coupling特性。

假设您是否应该从您的应用程序连接到 oracle 并编写这样的代码

    OracleDrive driver= new OracleDriver()
    driver.connect();

它会解决你的问题。但是会使你的代码与OracleDriver 紧密耦合。如果从类路径中删除与 Oracle 相关的 jar,您的应用程序将根本无法编译。如果有人问你让你的应用程序根据他们的配置连接到不同的数据库,那么你最终会得到多个ifs,这取决于你的应用程序支持的数据库。根据编程标准,这是不好的做法。

如果您所有的数据库驱动器都实现了一个接口Driver,那么您可以根据配置加载驱动程序,而无需将您的代码紧密耦合到任何特定的驱动程序类,例如

Driver driver = properties.get(db.driver.class)
driver.connect()

现在您看到您需要更改应用程序以连接到 MySql,您只需在配置文件中设置该类。

希望你明白我的意思!

【讨论】:

  • 一个更好的解释基类声明确实派上用场
【解决方案3】:

使用方法参数更有用。

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

在这种情况下,人可以为任何动物剃毛,但我们将其传递给狗。

Animal fido = new Dog(); 用处不大,因为我们知道 fido 是一条狗,但请考虑一下:

Animal pet;
if(joe.prefersCats)
    pet = new Cat();
else
    pet = new Dog();

【讨论】:

  • 不错!尤其是关于joe.prefersCats
【解决方案4】:

简单的回答,你不能那样做。

更复杂的答案,只有当 'Dog' 是 'Foo' 的类型时,你才能做到这一点。 我们什么时候说 Dog 是 'Foo' 的类型是 Dog 是实现 Foo(如果是接口)还是扩展 Foo(如果是另一个类或抽象类)

现在,Coding to Interfaces(您的问题的技术名称)的优势是

1) Java 的多态性是基于此(多态性使得运行时行为的改变成为可能,请在 java 中搜索多态性以获取更多信息) 2)您正在通过这种方法使接口独立于实现。

希望这回答了你的问题。

【讨论】:

  • 同意多态性,但有更多的困惑。
【解决方案5】:

只有这种类型的声明是可能的

 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)
{

}

它可以获取从基类派生的所有对象,并根据基类的属性或功能进行操作。

【讨论】:

  • @RoundRobin,我认为这将为您的所有问题提供清晰的解释
  • @Pokuri 也给出了一个很好的解释,这种类型的声明很方便
【解决方案6】:

在此处查看我的旧答案之一:

What is the advantage of using interfaces

这是我的一位教授曾经告诉我们的轶事。

长话短说,当您进入更复杂的系统时,您想要这样做的原因会变得更加清晰。将规范(接口/抽象类及其契约)与实现(具体类)分离的能力是一个强大的工具,它使得编写新实现变得非常容易,而无需在应用程序的其他地方更改代码。您在代码中使用规范,例如规范:

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 的新接口,扩展 Animal

public interface `DomesticatedAnimal` extends `Animal` { ... }

并将我们的方法更改为:

public static void feedAndGroom(DomesticatedAnimal da) { ... }

然后,DogCatTurtle 类将实现 DomesticatedAnimal,而不是实现 Animal。例如:

public class Dog implements DomesticatedAnimal { ... }

这意味着Dog 既是一个DomesticatedAnimal,因为它直接实现了它,一个Animal 通过继承自DomesticatedAnimal 扩展Animal。其他动物,HyenaLionPanther,只需实现Animal 接口。这意味着我们的新方法不会像原来的那样只使用任何Animal,而是将其限制为特定类型的Animal 对象。同时,使用原始Animal 接口编写的任何方法仍然适用于所有涉及的对象。

【讨论】:

    【解决方案7】:

    您总是可以用对子类的引用代替基类。

    换句话说,您总是可以使用更具体的东西来代替更一般的东西——因此,如果您有一行代码要求使用 Canine,您可以向它发送对 Dog 的引用。 所以这行代码:

    Foo ab=new Dog();
    

    表示您正在实例化一个新的Dog 对象,然后创建一个 Foo 引用称为 ab 并将其指向该对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      • 2013-12-16
      • 2015-06-14
      相关资源
      最近更新 更多