6

I've seen some discussions in StackOverflow about this subject, but I didn't see something that helped me understand the following point:

I'm coming from C++ background and lately I started to learn Java. In C++ when protected is used only a subclass can access the member (the analog to Field in Java).

In C++ there is also the "friend" classes that can have access to private/protected mambers of the class that giving "friendship". This is little bit analogous to "package" field modifier in Java (default field modifier), except that in C++ a friendship gives access to all private members, but in Java the access from classes in the same package is specific for a class field.

What I couldn't understand is, assuming that I want to give access only to subclasses, this is something I can do in C++ by declaring the members protected in a class that doesn't "give" friendships.

But in Java, I don't know how can I do it, since by using "protected" field modifier - I also give access to all classes in the package. The only way that I find to do it is to declare the field protected and have the class isolated in its package.

From here, what I conclude is that the grouping of classes in one package must be done on basis of "friendship" between the classes. Is this indeed the leading consideration in package grouping?

Another thing I don't understand, In Java, assuming I have two fields in the class A: b,c. I want to give B access to b but not to c, and I want to give C access to c but not to b. and to the "World" I want b,c to be hiden. How can it be done? I guess B,C should be both in the same package as A. but by declaring b,c with package modifier I let B,C access both to b and c. Is there a way in Java to do it?

Hope for some explanation of this subject

Day_Dreamer
  • 3,311
  • 7
  • 34
  • 61
  • 11
    A better question if less useful to you would be narrower and more specific. The general question of "everything about privacy in Java and C++ and how they differ" is more than a bit too broad. Can you generate a more specific question about a more specific problem? – Yakk - Adam Nevraumont Mar 04 '15 at 16:38
  • 2
    I suggest removing the C++ tag, since your question is more about the Java language than the C++ language. – Thomas Matthews Mar 04 '15 at 16:50
  • [This table](http://stackoverflow.com/a/33627846/276052) clearly illustrates the scopes of the various access levels in Java. – aioobe Nov 13 '15 at 12:36

4 Answers4

3

In C++ when protected is used only a subclass can access the member (the analog to Field in Java).

Access specifiers are also for member functions / methods, not just member variables / fields.

In C++ there is also the "friend" classes that can have access to private/protected mambers of the class that giving "friendship". This is little bit analogous to "package" field modifier in Java (default field modifier), except that in C++ a friendship gives access to all private members, but in Java the access from classes in the same package is specific for a class field.

There are not only friend classes but also functions.

It's true that Java's package-private access is similar, but it's not a complete replacement. A better way to put it would be that those two features have a subset of problems they solve. There are problems that can be solved by friend but not by package-private, and vice versa.

What I couldn't understand is, assuming that I want to give access only to subclasses, this is something I can do in C++ by declaring the members protected in a class that doesn't "give" friendships.

But in Java, I don't know how can I do it,

The answer is: You cannot.

since by using "protected" field modifier - I also give access to all classes in the package.

Exactly.

The only way that I find to do it is to declare the field protected and have the class isolated in its package.

Technically, yes. But this creates other problems. Your class will no longer be able to access package-private elements of its previous package. Let's say your BaseClass used to be in com.example.one. You move it to com.example.two. Now it will no longer be able to access other package-private classes of com.example.one.

Is this indeed the leading consideration in package grouping?

Yes, Java is designed like this. You can try to fight the language rules, but that's a losing battle in any programming language.

Another thing I don't understand, In Java, assuming I have two fields in the class A: b,c. I want to give B access to b but not to c, and I want to give C access to c but not to b. and to the "World" I want b,c to be hiden. How can it be done?

It cannot be done in a clean way (by clean I mean: without any hacks that would require you to inspect the call stack at runtime and throw exceptions).

If you are concerned about this scenario because you are designing a public API, a low-tech solution which usually works perfectly is to create one or more *.internal packages and clearly document the fact that those are not supposed to be used in client code.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
1

Those are quite a bunch of questions together...

But in Java, I don't know how can I do it, since by using "protected" field modifier - I also give access to all classes in the package.

True, there's no way to give access only to subclasses but not to classes in the same package. It was a design decision taken ages ago...

The only way that I find to do it is to declare the field protected and have the class isolated in its package.

This is technically correct, though it would be of little usage. Packaging of classes is meant to be used for grouping related classes, where 'related' means "classes that fulfil a specific relation", i.e. they belong to the same use case, belong to the same architectural layer, are in charged of the same entity, etc.

From here, what I conclude is that the grouping of classes in one package must be done on basis of "friendship" between the classes. Is this indeed the leading consideration in package grouping?

I believe I have already answered this in the preceding paragraph: packaging is meant to group related classes according to some specific criteria.

For your A, B and C classes example with attributes:

I guess B,C should be both in the same package as A. but by declaring b,c with package modifier I let B,C access both to b and c. Is there a way in Java to do it?

The answer is no, there's no simple, clean way to do it. You could achieve it with some hack or some more advanced techiques, but, again, this was part of the decisions taken by language designers ages ago...

fps
  • 33,623
  • 8
  • 55
  • 110
1

It is implicitly assumed that all classes in a package "know" each other (because they were written by the same person/company/organization). So they either don't access protected fields, or, if they do, they know how to do it properly.

The assumption is that classes in the same package are more related to each other than a parent is to a derived class, because the derived class might virtually be written by anyone else. So they decided private protected is more restricted than protected.

So, I think you should not worry about the way classes in the same package can access each others' fields. In general, I just don't use this feature, except when I write iterators.

If you have two fields, you might make them internal classes, so that they have access to private fields (again, the logic is: if a class is inside another class, it knows about the semantic of that class) and can expose this access to their derived classes via protected methods.

Of course, you can invent some complex token exchange protocol to only make that field accessible to instances of B/C, but it'd be a remarkable overhead, and another object can still use reflection to gain access to all private members, unless you disable it via security policies, which isn't usually the case, but again, security policies are ultimately decided by the owner of the JVM.

So, in the end, the preferred way to do what you say in Java is to either put them in the same package or write B and C as internal classes of A, so that they can directly access private members of A and expose them to their derived classes.

public class A {
  public static abstract class B {
    protected Whatever getWhatever(A a) { return a.b; }
    protected void setWhatever(A a, Whatever value) { a.b = value; }
  }
  public static abstract class C {
    protected Whatever getWhatever(A a) { return a.c; }
    protected void setWhatever(A a, Whatever value) { a.c = value; }
  }
  private Whatever b;
  private Whatever c;
}

again, you always assume classes in the same package will never do anything bad.

Giulio Franco
  • 3,170
  • 15
  • 18
0

Short answer: there's no way to do it.

If you're worried about intrusion from clients injecting a class in your package to gain illegal access, you can move the sensitive code in a separate package, and make the package sealed in the jar you deliver it in: http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html

GeertPt
  • 16,398
  • 2
  • 37
  • 61