Reputation: 175
Let's say I have a ParkingMeter
class and a ParkingSlip
class. ParkingSlips should only be created from within the ParkingMeter
class, but ParkingSlips
should be accessible by an external class called Car
(so you can check if each car has paid for parking).
Is there a way to ensure ParkingSlips
can only be created from within ParkingMeter but is still accessible to other classes?
Upvotes: 4
Views: 938
Reputation: 15706
Actually there is a way to check who called a constructor or method:
by examining the current stack trace.
Not that I'd recommend it, but hey, it works:
public ParkingSlip() {
// get the current stack trace
// element 0: java.lang.Thread.getStackTrace
// element 1: this constructor
// element 2: the class/method calling this constructor
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// verify that it was indeed the ParkingMeter who invoked the constructor
if (!ParkingMeter.class.getName().equals(stackTrace[2].getClassName())) {
throw new IllegalAccessError("Restricted access, only ParkingMeter is allowed to create instances");
}
}
A cleaner solution, which resticts constructor access at compile time (the solution above only checks at runtime) is to
ParkingMeter
and ParkingSlip
(only those two) in a dedicated package public
ParkingSlip
'friendly' (neither private
, nor protected
, nor public
)This ensures that the ParkingSlip
constructors can only be accessed by classes in the same package, and as ParkingMeter
is the only other class in that package, you've got what you want.
public class ParkingSlip {
// 'friendly' constructor
ParkingSlip() {
}
}
Upvotes: 1
Reputation: 425043
The safest way is to make ParkingSlip public inner static class of ParkingMeter and give it a private constructor.
public class ParkingMeter {
public static class ParkingSlip {
private ParkingSlip() {
}
}
}
A less safe, but more useable, way is to give default (aka "package") visibility to the constructor and have ParkingMeter in the same package, but any other class from the same package - even from a different project - will have access to the constructor.
Note that whichever way you go, reflection can circumvent it.
Upvotes: 3
Reputation: 361645
If you don't want to make ParkingSlip
an inner class, put the two classes in the same package and make ParkingSlip
's constructor package-private. It won't stop other classes in the same package from creating parking slips, but it will stop evildoers in other packages.
package parking;
public class ParkingSlip {
ParkingSlip() {
}
}
public class ParkingMeter {
public ParkingSlip getSlip() {
return new ParkingSlip();
}
}
Upvotes: 2