Подтвердить что ты не робот

Интерфейсы в Java: не могут сделать реализованные методы защищенными или приватными

Я знаю, что интерфейс должен быть общедоступным. Однако я не хочу этого.

Я хочу, чтобы мои реализованные методы были доступны только из их собственного пакета, поэтому я хочу, чтобы мои реализованные методы были защищены.

Проблема заключается в том, что я не могу защитить интерфейс или реализованные методы.

Что такое работа? Есть ли шаблон дизайна, который относится к этой проблеме?

Из руководства Java абстрактный класс также не будет выполнять эту работу.

4b9b3361

Ответ 1

прочитайте this.

"Спецификатор общего доступа указывает, что интерфейс может использоваться любым классом в любом пакете. Если вы не укажете, что интерфейс является общедоступным, ваш интерфейс будет доступен только для классов, определенных в том же пакете, что и интерфейс.

Это то, что вы хотите?

Ответ 2

Вы можете использовать защиту пакета и по-прежнему реализовывать интерфейс:

class Foo implements Runnable 
{
    public void run()
    {
    }
}

Если вы хотите, чтобы некоторые методы были защищены/упакованы, а другие нет, это звучит так, как будто ваши классы имеют более одной ответственности и должны быть разделены на несколько.

Изменить после чтения комментариев к этому и другим ответам:

Если вы как-то думаете, что видимость метода влияет на способность ссылаться на этот метод, подумайте еще раз. Не вдаваясь в крайности, вы не можете помешать кому-либо использовать отражение, чтобы идентифицировать методы своего класса и вызвать их. Однако это не проблема: если кто-то не пытается взломать ваш код, они не будут вызывать случайные методы.

Вместо этого подумайте о частных/защищенных методах как определении контракта для подклассов и используйте интерфейсы для определения контракта с внешним миром.

О, и человеку, который решил, что мой пример должен использовать K & R bracing: если он определен в Условиях обслуживания, обязательно. В противном случае, не можете ли вы найти что-нибудь лучше с вашим временем?

Ответ 3

Когда я столкнулся с этим, я использую доступный пакет для внутреннего или вложенного класса для реализации интерфейса, вытесняя реализованный метод из открытого класса.

Обычно это потому, что у меня есть класс с определенным публичным API, который должен реализовать что-то еще, чтобы выполнить его работу (довольно часто, потому что что-то еще было обратным вызовом, замаскированным под интерфейс <grin> ) - это очень часто происходит с такие вещи, как Comparable. Я не хочу, чтобы публичный API был загрязнен реализацией интерфейса (принудительного публичного).

Надеюсь, что это поможет.

Кроме того, если вы действительно хотите, чтобы методы обращались только к пакету, вам не нужен спецификатор защищенной области, вам нужен спецификатор области по умолчанию (опущен). Разумеется, использование защищенной воли позволяет подклассам видеть методы.

Кстати, я думаю, что методы интерфейса причины считаются публичными, потому что это очень исключение для интерфейса, который реализуется только классами в одном пакете; они чаще всего вызываются чем-то в другом пакете, а это значит, что они должны быть общедоступными.

Ответ 4

Этот вопрос основан на неправильном утверждении:

Я знаю, что интерфейс должен быть общедоступным

Не совсем, у вас могут быть интерфейсы с модификатором доступа по умолчанию.

Проблема заключается в том, что я не могу защитить интерфейс или реализованные методы

Вот он:

C:\oreyes\cosas\java\interfaces>type a\*.java
a\Inter.java
package a;

interface Inter {
    public void face();
}

a\Face.java
package a;

class Face implements Inter {
    public void face() {
        System.out.println( "face" );
    }
}


C:\oreyes\cosas\java\interfaces>type b\*.java
b\Test.java

package b;
import a.Inter;
import a.Face;

public class Test {
    public static void main( String [] args ) {
        Inter inter = new Face();
        inter.face();
    }
}

C:\oreyes\cosas\java\interfaces>javac -d . a\*.java b\Test.java
b\Test.java:2: a.Inter is not public in a; cannot be accessed from outside package
import a.Inter;
        ^
b\Test.java:3: a.Face is not public in a; cannot be accessed from outside package
import a.Face;
        ^
b\Test.java:7: cannot find symbol
symbol  : class Inter
location: class b.Test
        Inter inter = new Face();
        ^
b\Test.java:7: cannot find symbol
symbol  : class Face
location: class b.Test
        Inter inter = new Face();
                          ^
4 errors

C:\oreyes\cosas\java\interfaces>

Следовательно, достижение того, что вы хотели, предотвратите использование интерфейса и класса за пределами пакета.

Ответ 5

Вот как это можно сделать с помощью абстрактных классов.

Единственное неудобство в том, что он делает вас "подклассом".

Согласно руководству по Java, вы должны следовать этому совету "большинство" времени, но я думаю, что в этой ситуации все будет хорошо.

public abstract class Ab { 
    protected abstract void method();
    abstract void otherMethod();
    public static void main( String [] args ) { 
        Ab a = new AbImpl();
        a.method();
        a.otherMethod();
    }
}
class AbImpl extends Ab {
    protected void method(){
        System.out.println( "method invoked from: " + this.getClass().getName() );
    }
    void otherMethod(){ 
        System.out.println("This time \"default\" access from: " + this.getClass().getName()  );
    }
}

Ответ 6

Здесь другое решение, вдохновленное идиомой С++ Pimpl.

Если вы хотите реализовать интерфейс, но не хотите, чтобы эта реализация была общедоступной, вы можете создать составной объект анонимного внутреннего класса, который реализует интерфейс.

Вот пример. Скажем, у вас есть этот интерфейс:

public interface Iface {
    public void doSomething();
}

Вы создаете объект типа Iface и помещаете туда свою реализацию:

public class IfaceUser {
    private int someValue;
    // Here our implementor
    private Iface impl = new Iface() {
        public void doSomething() {
            someValue++;
        }
    };
}

Всякий раз, когда вам нужно вызывать doSomething(), вы вызываете его на свой скомпонованный объект impl.

Ответ 7

Я просто наткнулся на это, пытаясь создать защищенный метод с намерением его использовать только в тестовом примере. Я хотел удалить тестовые данные, которые я набил в таблицу DB. В любом случае я был вдохновлен @Karl Giesing . К сожалению, это не сработало. Я сделал способ заставить его работать с защищенным внутренним классом.

Интерфейс:

package foo;
interface SomeProtectedFoo {
    int doSomeFoo();
}

Затем внутренний класс определяется как защищенный в открытом классе:

package foo;
public class MyFoo implements SomePublicFoo {
    // public stuff
    protected class ProtectedFoo implements SomeProtectedFoo {
        public int doSomeFoo() { ... }
    }
    protected ProtectedFoo pFoo;
    protected ProtectedFoo gimmeFoo() {
        return new ProtectedFoo();
    }
}

Затем вы можете получить доступ к защищенному методу только из других классов в одном пакете, так как мой тестовый код был показан:

package foo;
public class FooTest {
    MyFoo myFoo = new MyFoo();
    void doProtectedFoo() {
        myFoo.pFoo = myFoo.gimmeFoo();
        myFoo.pFoo.doSomeFoo();
    }
}

Немного поздно для оригинального плаката, но эй, я просто нашел его.: D

Ответ 8

Вы можете использовать инкапсуляцию вместо наследования.

То есть, создайте свой класс (который ничего не наследует) и в нем не будет иметь экземпляр объекта, который вы хотите расширить.

Затем вы можете выставить только то, что хотите.

Очевидным недостатком этого является то, что вы должны явно передавать сквозные методы для всего, что вам нужно. И это не будет подкласс...

Ответ 9

Я бы просто создал абстрактный класс. В этом нет вреда.

Ответ 10

С интерфейсом вы хотите определить методы, которые могут быть представлены множеством реализующих классов. Наличие интерфейса с защищенными методами просто не помогло бы этой цели.

Я предполагаю, что ваша проблема может быть решена путем перестройки иерархии классов.

Ответ 11

Один из способов обойти это (в зависимости от ситуации) - сделать анонимный внутренний класс, реализующий интерфейс с областью protected или private. Например:

public class Foo {
    interface Callback {
        void hiddenMethod();
    }

    public Foo(Callback callback) {
    }
}

Затем пользователь Foo:

public class Bar {
    private Foo.Callback callback = new Foo.Callback() { 
        @Override public void hiddenMethod() { ... }
    };
    private Foo foo = new Foo(callback);
}

Это избавит вас от следующего:

public class Bar implements Foo.Callback {
    private Foo foo = new Foo(this);

    // uh-oh! the method is public!
    @Override public void hiddenMethod() { ... }
}

Ответ 12

Я думаю, что вы можете использовать его сейчас с выпуском Java 9. Из примечаний openJdk для Java 9,

Поддержка частных методов в интерфейсах была кратко рассмотрена для включения в Java SE 8 в рамках усилий по добавлению поддержки для Lambda Expressions, но был отозван, чтобы лучше сосредоточиться на более высоких приоритетных задач для Java SE 8. В настоящее время предлагается, чтобы поддержка методы частного интерфейса, что позволяет не абстрактно методы интерфейса для совместного использования кода между ними.

обратитесь https://bugs.openjdk.java.net/browse/JDK-8071453