midnite
midnite

Reputation: 5286

What about public method returns private class instance?

I am trying to test the following situation:

  1. There is a main. (city.Main)
  2. There is a package. (package castle)
  3. Within the package, there is a public class (castle.Guard), and a package-private class (castle.Princess).
  4. What if, the public class is returning an instance of the private class?

Here is my code:

Main.java

package city;

import castle.Guard;

public class Main {

    public static void main(String[] args) {
        Princess princess = Guard.getPrincessStatic();
        // Error: Princess cannot be resolved to a type
        
        Guard.getPrincessStatic().sayHi();
        // Error: The type Princess is not visible
        
        Guard guard = new Guard();
        guard.getPrincess().sayHi();
        // Error: The type Princess is not visible
        
        guard.getPrincessMember().sayHi();
        // Error: The type Princess is not visible
    }

}

Guard.java

package castle;

public class Guard {

    public Princess getPrincess() {
        return new Princess();
    }

    public static Princess getPrincessStatic() {
        return new Princess();
    }
    
    private Princess m_princess = new Princess();
    
    public Princess getPrincessMember() {
        return m_princess;
    }
}

Princess.java

package castle;

class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

Notice all the 4 statements in main() are having errors.

I have done some research too. In fact i want to mimic this answer. But i don't why my codes throw errors.

Thanks for any explanations!


Edit:

I intend to make the castle-Princess package-private. I know that, by returning a package-private class out of its package, I should be prepared for errors. But why that answer works, while mine doesn't?

Upvotes: 4

Views: 4202

Answers (5)

AllTooSir
AllTooSir

Reputation: 49372

Princess class is default scoped to castle package , so its invisible within city package . To circumvent that :

(We can do one of the following three approaches.)

1) Make Princess class public and use it .

package castle;

// added public modifier
public class Princess {
     public void sayHi() { System.out.println("Hi world"); }
}

2) Or, Define a public interface and let Princess implement it and use the interface reference instead of the class reference . I would prefer this .

castle \ IPrincess.java

// Interface definition
package castle;

public interface IPrincess {
    public void sayHi();
}

castle \ Princess.java

// Implement the interface in Princess class
package castle;

class Princess implements IPrincess {
    public void sayHi() { System.out.println("Hi world"); }
}

castle \ Guard.java

// Modify the Guard class
package castle;

public class Guard {
    public IPrincess getPrincess() {
        return new Princess();
    }
    public static IPrincess getPrincessStatic() {
        return new Princess();
    }

    // for here i use Princess instead of IPrincess. (@midnite)
    private Princess m_princess = new Princess();
    public IPrincess getPrincessMember() {
        return m_princess;
    }
}

city \ Main.java

// Modify the main class
  package city;

  import castle.Guard;
  import castle.IPrincess;

  public class Main {

  public static void main(String[] args) {

     IPrincess princess = Guard.getPrincessStatic();

     Guard.getPrincessStatic().sayHi();

     Guard guard = new Guard();
     guard.getPrincess().sayHi();

     guard.getPrincessMember().sayHi();
   }
}

3) Or, Put all the classes in same package .

Upvotes: 5

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136022

Your example is different because your classes are in different packages and Guard and Princess are not visible from Main.

But public method can return an instance of a private class. JDK is full of examples, here is one from java.util.Arrays

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
...
private static class ArrayList<E> extends AbstractList<E>  {
...

it is what you ask. The trick is that the method's return type is a public interface which the private class implements. You could do something similar.

Upvotes: 0

acdcjunior
acdcjunior

Reputation: 135762

The answer you are trying to mimic works because all the classes are inside the same package.

If you put UntrustworthyFriend and Friend in different packages (as your scenario), the same problems will arise.

Princess can only be visible outsite it's package if public:

Princess.java

package castle;

public class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

Also, make sure to import it in Main.

Upvotes: 1

Matthew Cox
Matthew Cox

Reputation: 13672

You are not going to be able to return a type that is privately scoped within a class. How can any external sources know what that type even IS if it's privately scope inside of another class?

This design won't even compile.

Edit:

The simple solution is to make it public and then you can use it externally outside of the package.

Upvotes: 1

ApproachingDarknessFish
ApproachingDarknessFish

Reputation: 14313

The problem lies in a very small error in the definition of your Princess class:

package castle;

class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

All looks fine at first, but you're missing a public modifier before the class name:

package castle;

//here!
public class Princess {
    public void sayHi() { System.out.println("Hi world"); }
}

Without the public modifier, the princess class cannot be accessed outside of the file in which it is declared.

Upvotes: 0

Related Questions