Java – 在接口实现中添加方法

huangapple go评论76阅读模式
英文:

Java - Adding methods to interface implementation

问题

我将用一个简单的例子来说明这个问题。

如果我有一个名为AnimalInterface,就像这样:

public interface Animal {
    void jump();
}

并且我正在即时创建一个接口对象,像这样:

public class Main {
    public static void main(String[] args) {
        
        Animal cat = new Animal() {
            @Override
            public void jump() {
                System.out.println("The cat jumped");
            }

            public void sleep() {
                System.out.println("The cat slept");
            }
        };
        cat.jump(); 
        cat.sleep(); // 无法这样做。
    }
}

现在,我在接口实现中添加了sleep()方法,希望从调用cat.jump()的地方调用该方法。这就是我想要的。我看到会抛出错误,我也理解,因为对象的类型是Animal,而Animal没有sleep()方法。

如果我不想向interface添加新的方法,在这种情况下,我还有哪些选项可以调用我在接口实现中创建的方法呢?

英文:

I'll use an easy example for the sake of the question.

If I have an Interface say Animal which is like

public interface Animal {
    void jump();
}

And I'm creating an object of the interface on the go, like

public class Main {
    public static void main(String[] args) {
        
        Animal cat = new Animal() {
            @Override
            public void jump() {
                System.out.println("The cat jumped");
            }

            public void sleep() {
                System.out.println("The cat slept");
            }
        };
        cat.jump(); 
        cat.sleep(); // cannot do that. 
    }
}

Now, I added the sleep() method to the interface implementation and want that method to be callable from the place where I'm calling cat.jump(). That is what I want. I see that throws an error and I do understand because the object is of type Animal and Animal does not have the sleep() method.

If I do not want to add a new method to the interface, in that case, what other options do I have to be able to call a method that I created in interface implementation?

答案1

得分: 2

问题在于你没有理解什么是针对接口编程。我相信你在想这是你创建的必须遵循的规则。事实并非如此。它是一种理解为什么存在并在必要时进行操作的东西。

如果你只需要接口中的内容,你必须将变量声明为接口。如果你需要具体类中的内容,那么你必须声明具体类。

强制转换或其他操作是为了修复第一个错误而犯的第二个错误。

接口应该用于隔离职责。你编程到接口,以便接收对象的内容只能访问该类型中的内容。它有意不允许访问具体对象的其他成员。如果你使用了接口,那么代码就不知道接口之外的内容。

你还想通过接口调用 didSomething() 吗?你有两种可能性:

  • 创建一个新接口,并在其中声明带有此方法,然后你可以使用接口类型声明变量,访问所需的方法,这样你就是在针对接口进行编程。我认为这是最合适的方法,但在像这样的抽象示例中,一切皆有可能;
  • 将方法放入现有接口中,然后你就可以访问它。这可能不是你想要的,但这是一个可能性。我不知道你想要什么,使用的名称并没有指示它应该是什么。

实际上,虽然了解其工作原理很有用,但在像这样简单的情况下,针对接口进行编程是没有实际用途的。当你有复杂的系统需要维护和灵活更改实现而不必更改合同时,使用这种技术很有用。

interface Something {
    void doSomething();
}

interface Otherthing {
    void doOtherthing();
}

class Whatever implements Something, Otherthing {
    public void doSomething() {
       System.out.println("Do something!");
    }     
    public void doOtherthing() {
       System.out.println("Do otherthing!");
    }
}

class Test {
    public static void main(String[] arguments) {
        Something s = new Whatever();
        s.doSomething();
        Otherthing w = new Whatever(); 
        w.doOtherthing();
    }
}
英文:

The problem is that you didn't understand what it is to program for the interface. I believe you are thinking that it is a rule that you have created and must follow. It is not. It is something to understand why it exists and to do it when necessary.

You must declare a variable as the interface if you only need what is in the interface. If you need what is in the concrete class then you must declare the concrete class.

Casting or something else is adopting a mistake to fix the first mistake.

Interfaces should be used to segregate responsibilities. You program to interface so that what will receive the object can only access what is in that type. It is purposeful that it does not allow other members of the concrete object to access. If you used the interface, that code does not know what is not in the interface.

Do you still want to call didSomething () and be through an interface? You have two possibilities:

  • Create a new interface with this method and there you can declare the variable with the type of the interface, access the desired method, and you will be programming for the interface. I consider this the most appropriate, but it may not be, in an abstract example like this, everything is possible;
  • Place the method in the existing interface and you will be able to access it. It may not be what you want, but it is a possibility. I don't know what you want, the names used don't indicate what it should be.

In fact, although it is useful to see how it works, programming for interface in something as simple as that is of no practical use. It is useful to use this technique when you have complex systems, which will need maintenance and flexibility to change the implementation without having to change the contract.

interface Something {
    void doSomething();
}

interface Otherthing {
    void doOtherthing();
}

class Whatever implements Something, Otherthing {
    public void doSomething() {
       System.out.println("Do something !");
    }     
    public void doOtherthing() {
       System.out.println("Do otherthing !");
    }
}

class Test {
    public static void main(String[] arguments) {
        Something s = new Whatever();
        s.doSomething();
        Otherthing w = new Whatever(); 
        w.doOtherthing();
    }
}

答案2

得分: 1

如果您想调用接口中没有的方法,那么您不能使用接口来进行调用,您必须使用类来进行调用。

由于该类是匿名的,您不能使用该类。

创建一个真正的命名类,而不是使用匿名类,例如创建一个Cat类。

class Cat implements Animal {
    // 匿名类中的方法在这里
}
Cat cat = new Cat();
cat.jump();
cat.sleep(); // 您现在可以这样做
英文:

If you want to call a method that's not in the interface, then you can't use the interface to make the call, you have to use the class.

Since the class is anonymous, you can't use the class.

Make a real named class, instead of using anonymous classes, e.g. create a class Cat.

class Cat implements Animal {
    // methods from anonymous class here
}
Cat cat = new Cat();
cat.jump();
cat.sleep(); // you can do this now

答案3

得分: 0

使用以下语法时:

SuperClass anonymousInstance = new SuperClass() {
   /*Code here*/
}

并没有创建一个超类(在这种情况下是Animal)的实例。相反,你正在创建一个未指定的超类子类的实例。之所以能够将其存储在超类的引用变量中,是因为涉及了多态性

只有在想要重写超类中的单个方法并且只打算使用新类一次时,才应该使用匿名内部类,而不是创建和实例化实际类。如果你要创建一个新方法,就像你在sleep方法中所做的那样,最好的做法是创建一个实际的类。

话虽如此,如果你必须使用匿名内部类,并且你正在使用Java 10或更高版本,则可以选择使用局部变量类型推断。这可以通过var关键字来实现。

var anonymousInstance = new SuperClass() {
   /*Code here*/
}

如果你使用var关键字,Java编译器将推断出子类的匿名类型,其中将包括所有子类中的方法。这确实有其局限性 - 如果将对象作为参数传递,你将无法访问新方法 - 但在其他情况下它仍然有效。

英文:

When you use the following syntax:

SuperClass anonymousInstance = new SuperClass() {
   /*Code here*/
}

you are not creating an instance of the Superclass (in this case, Animal). Rather, you are creating an instance of some unspecified Subclass of the Superclass. The only reason why you are able to store it in a reference variable of the Superclass is because of polymorphism.

You should only be using anonymous inner classes, as opposed to creating and instantiating an actual class, when you want to override a single method in the Superclass and only intend to use the new class once. If you are creating a new method, as you did here with the sleep method, it is better practice to create an actual class.

With that being said, if you must use an anonymous inner class and you are using Java 10 or later, you do have the option of using local variable type inference. This is accomplished via the var keyword.

var anonymousInstance = new SuperClass() {
   /*Code here*/
}

In you use the var keyword instead, the Java compiler will infer the anonymous type of the Subclass, which will include all of the methods in the Subclass. This does have its limitations - you'll lose access to new methods if you pass the object as a parameter - but it will work otherwise.

huangapple
  • 本文由 发表于 2020年9月25日 09:08:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/64056408.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定