简体   繁体   English

包私有类中的公共方法

[英]public methods in package-private classes

Does it make a difference to mark methods as public in package-private classes?在包私有类中将方法标记为public有什么不同吗?

class SomePackagePrivateClass
{
    void foo();          // package private method

    public void bar();   // public method
}

Is there any practical difference in visibility between foo and bar here?这里的foobar之间的可见性有什么实际区别吗?

Example using inheritance:使用继承的示例:

A.java爪哇

package pkg1

class A {
  void foo();
  public void bar() {};
}

B.java B.java

package pkg1

public class B extends A{

}

C.java C.java

package pkg2

public class C {
  public void doSomething() {
   B b = new B();
   b.bar(); //ok
   b.foo(); //won't work, since foo() is not visible outside of package 'pkg1'

   A a = new A(); //won't work since A is not visible outside of package 'pkg1'
   a.bar(); //won't work, since a cannot be created
  }
}

If the class is not going to be extended by another, more visible subclass*, the only difference is clarity of intent .如果该类不会被另一个更可见的子类*扩展,唯一的区别是意图的清晰性 Declaring all methods package private makes it more difficult for future readers to determine which of the methods are meant to be called by other classes in the same package.将所有方法声明为包私有会使未来的读者更难确定哪些方法应该由同一包中的其他类调用。

* which would not make much sense as a design solution to me, but technically is possible nevertheless. *这对我来说作为一种设计解决方案没有多大意义,但在技术上仍然是可能的。

Another case where the method has to be public is when you are creating a package private implementation of some public class or interface.方法必须是公共的另一种情况是当您创建某个公共类或接口的包私有实现时。 Since you are not allowed to reduce the visibility of overridden methods, these have to be public.由于不允许您降低覆盖方法的可见性,因此这些方法必须是公开的。

Well... i had this doubt also (that's why i searched for this thread).嗯......我也有这个疑问(这就是我搜索这个线程的原因)。 This might be a good question.这可能是个好问题。

But ...但 ...

After a second thought, things are really simpler than we thought.转念一想,事情真的比我们想象的要简单。

A package-private method, is a package-private method.包私有方法,是包私有方法。

Seems nonsense?好像是废话? But ...但 ...

A package-private method, even if its class is inherited, it is still a package-private method.一个包私有方法,即使它的类被继承,它仍然是一个包私有方法。

Does it make more sense now?现在更有意义了吗? For a more verbose explanation:更详细的解释:

A package-private method, even if its class is inherited by a more visible subclass, it is still a package-private method.一个包私有方法,即使它的类被更可见的子类继承,它仍然是一个包私有方法。

If the subclass is of the same package, those package-private methods are also inherited, but they are still package-private .如果子类属于同一个包,那些包私有的方法也会被继承,但它们仍然是包私有的

If the subclass is of the different package (of here, we need the parent class to be public, with some package-private methods), those package-private methods are not inherited (because they are not visible at all).如果子类属于不同的包(在这里,我们需要父类是公共的,带有一些包私有方法),那些包私有方法不会被继承(因为它们根本不可见)。

A point to note, which may be the cause of this doubt, that a package-private method in a public class is not visible outside its package also.需要注意的一点,这可能是造成这种疑问的原因,公共类中的包私有方法在其包之外也是不可见的。


The above explains about the package-private method.上面解释了 package-private 方法。 And the case of the public-method is just the same. public-method 的情况也是如此。

When a package-private class is inherited by a pubic subclass (of the same package, this is a must), its public methods are inherited as public methods, and thus they become public methods in a pubic class.当一个包私有类被公共子类(同一个包,这是必须的)继承时,它的公共方法作为公共方法被继承,因此它们成为公共类中的公共方法。

In the OP example, as foo() and bar() are both in a package-private class, their visibilities are limited to package-private at this moment, until further codes are added (eg inheritance).在 OP 示例中,由于foo()bar()都在包私有类中,因此它们的可见性目前仅限于包私有,直到添加更多代码(例如继承)。

Hope this is clear (and simple) enough.希望这足够清楚(和简单)。

PS the Java access control table PS Java访问控制表

Yes.是的。 public methods in a package-private class can be useful (although they are rare).包私有类中的public方法可能很有用(尽管它们很少见)。 Illustrative example from the java library (and taken from the classic book "effective java"):来自 java 库的说明性示例(取自经典书籍“有效的 java”):

Have you ever seen the java.util.JumboEnumSet, java.util.RegularEnumSet ??你见过java.util.JumboEnumSet, java.util.RegularEnumSet吗? Probably not, because they are private, and are not mentioned in the documentation.可能不是,因为它们是私有的,并且在文档中没有提到。

Have you ever used them??你用过它们吗?? Probably yes.大概是。 They are returned by the static method of java.util.EnumSet.noneOf(...) .它们由java.util.EnumSet.noneOf(...)的静态方法返回。 Although you can't construct them yourself, you can use their public methods when they are returned from this method.虽然你不能自己构造它们,但是当它们从这个方法返回时,你可以使用它们的公共方法。

The good thing about that is that you don't know which one you are using, or even that they exist.这样做的好处是你不知道你正在使用哪一个,甚至不知道它们的存在。 Java decides which one is more efficient depending on the arguments, and might use a different on in a newer version. Java 根据参数决定哪个更有效,并且可能在较新的版本中使用不同的 on。 You only access their functionality by referring to them through their common interface (which is a good practice anyway!!)您只能通过它们的通用界面引用它们来访问它们的功能(无论如何这是一个好习惯!!)

It makes very little difference, unless the class is extended by a public (or protected nested) class.除非该类由公共(或受保护的嵌套)类扩展,否则几乎没有什么区别。

As a matter of consistency, I'd go for public .作为一致性问题,我会选择public It should be rare for methods to be anything other than public or private .除了publicprivate之外,方法应该很少见。

There are a number of examples of public methods in the package private java.lang.AbstractStringBuilder class.包私有java.lang.AbstractStringBuilder类中有许多公共方法的示例。 For instance length() is public in AbstractStringBuilder and is exposed in the public class StringBuilder (overridden in StringBuffer to add synchronisation).例如length()AbstractStringBuilder中是公共的,并在公共类StringBuilder中公开(在StringBuffer中重写以添加同步)。

One good utilization for that is when you want to restrict your class to your package but still want to use proxy-generated stuff, such as the @Transactional right above the following a method.一个很好的用途是当你想将你的类限制在你的包中,但仍然想使用代理生成的东西,比如@Transactional就在下面一个方法的正上方。

@Service
class SomeService {

   @Transactional
   public void someTxStuff() {
     /// very complicated code here
   }
}

If someTxStuff were package-private, @Transactional annotation wouldn't have any effect.如果someTxStuff是包私有的,@ @Transactional注释不会有任何效果。

There is a difference when you make reflective access to the method: jdk.internal.reflect.Reflection.verifyMemberAccess() will decline access to the method when you try to call it from a class which is not in the same package as your package-private class even if it is a method which is an overridden method of a public class/interface.当您对方法进行反射访问时会有所不同:当您尝试从与您的包不在同一个包中的类中调用该方法时, jdk.internal.reflect.Reflection.verifyMemberAccess()将拒绝访问该方法-私有类,即使它是公共类/接口的重写方法。 Consider following example:考虑以下示例:

package pkg1;
public interface PublicInterface {
    int i();
}
package pkg2;
import pkg1.PublicInterface;
class PackagePrivateImpl implements PublicInterface {
    @Override public int i() {
        return 42;
    }
}
package pkg2;
import pkg1.PublicInterface;
public class ImplFactory {
    public static PublicInterface impl() {
        return new PackagePrivateImpl();
    }
}
package pkg1;
import java.lang.reflect.Method;
import pkg2.ImplFactory;
public class ReflectiveFail {
    public static void main(String... args) throws Exception {
        PublicInterface impl = ImplFactory.impl();
        System.out.println(impl.i()); // 42
        Method interfaceMethod = PublicInterface.class.getMethod("i");
        System.out.println(interfaceMethod.invoke(impl)); // 42
        Method implMethod = impl.getClass().getMethod("i");
        System.out.println(implMethod.invoke(impl)); // IllegalAcessException
    }
}

The last call to implMethod.invoke() will throw an IllegalAccessException with the following message:最后一次调用implMethod.invoke()将抛出IllegalAccessException并显示以下消息:

Exception in thread "main" java.lang.IllegalAccessException: class pkg1.ReflectiveFail cannot access a member of class pkg2.PackagePrivateImpl with modifiers "public"

foo具有default package visibility ,而bar具有public可见性

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM