How can ImmutableMap builder create instance of abstract class? - java

I am learning to use guava library and referred to this I see use of builder to construct an instance of immutable map. How is the builder constructor able to create an abstract class instance?
static final ImmutableMap<String, Integer> WORD_TO_INT =
new ImmutableMap.Builder<String, Integer>()
.put("one", 1)
.put("two", 2)
.put("three", 3)
.build();

I does not, the Builder creates an implementation of an ImmutableMap (a class that extends the ImmutableMap).
To understand clearly, start here before working with Guava.
Update: see comment by #Louis Wasserman. Indeed an essential comment.

ImmutableMap (Guava: Google Core Libraries for Java 21.0-SNAPSHOT API) states that it is "a Map whose contents will never change, with many other important properties detailed at ImmutableCollection".
The "other important properties detailed at ImmutableCollection" include the following guarantees:
Each makes the following guarantees:
Shallow immutability. Elements can never be added, removed or replaced in this collection. This is a stronger guarantee than that of Collections.unmodifiableCollection(java.util.Collection<? extends T>), whose contents change whenever the wrapped collection is modified.
Null-hostility. This collection will never contain a null element.
Deterministic iteration. The iteration order is always well-defined, depending on how the collection was created (see the appropriate factory method for details). View collections such as Multiset.elementSet() iterate in the same order as the parent, except as noted.
Thread safety. It is safe to access this collection concurrently from multiple threads.
Integrity. This type cannot be subclassed outside this package (which would allow these guarantees to be violated).
The last guarantee, integrety, alludes to the fact that internally Guava has concrete implementations (non-abstract) of ImmutableMap and other immutable objects which is what is actually returned by these builders.
Furthermore, the source is open; you can go find out for yourself how the builder is able to do it (e.g. you might start here).

It is not the constructor of the builder class that returns an instance of an immutable map.
You are first creating the builder by calling new ImmutableMap.Builder<String, Integer>() and then you are calling methods in a chain on this ImmutableMap.Builder instance - three times the put method and then the build method.
The build method is what is called last, and that is what creates and returns the instance of ImmutableMap.
The "trick" here is that the put method of ImmutableMap.Builder returns the builder itself (it has a statement return this; at the end) so that you can chain method calls like this.
And, indeed, the build method returns an instance of a subclass of ImmutableMap because class ImmutableMap is abstract, so it cannot be directly instantiated.

Related

What class instance does Map.of() return?

I'm currently learning about collections and I noticed that the factory method Map.of returns an object of type Map<>. However since Map is only an interface what class does the Map class reference actually point to?
It is not guaranteed to return an instance of any specific class, so your code should not depend on that. However, for the sake of learning, OpenJDK 11 returns an instance of ImmutableCollections.Map1, one of several lightweight special-purpose classes written specifically for the Map.of overloads.
It won't be the same depending on the Map size and you should not rely on the value returned as per the answer by #chrylis -cautiouslyoptimistic-.
If you are interested on the value of any Map instance your code uses just print map.getClass(), here are a few examples:
System.out.println(Map.of().getClass());
System.out.println(Map.of(1,2).getClass());
System.out.println(Map.of(1,2,3,4,5,6).getClass());
Which (in JDK17) prints:
class java.util.ImmutableCollections$MapN
class java.util.ImmutableCollections$Map1
class java.util.ImmutableCollections$MapN
It returns an Immutable Map from the ImmutableCollections class.
This class is not part of the public API, but it extends AbstractMap which supplies implementations for all of the basic methods needed for a Map.
The important takeaway is that the Map returned by Map.of() is immutable so you can't add to or change it after it is created. Immutable collections are more secure, are thread safe, and can be more efficient.

Effective Java: Safety of Forwarding Classes

Effective Java 3rd Edition, Item 18: Favor composition over inheritance describes an issue with using inheritance to add behavior to a class:
A related cause of fragility in subclasses is that their superclass can acquire new methods in subsequent releases. Suppose a program depends for its security on the fact that all elements inserted into some collection satisfy some predicate. This can be guaranteed by subclassing the collection and overriding each method capable of adding an element to ensure that the predicate is satisfied before adding the element. This works fine until a new method capable of inserting an element is added to the superclass in a subsequent release. Once this happens, it becomes possible to add an "illegal" element merely by invoking the new method, which is not overridden in the subclass.
The recommended solution:
Instead of extending an existing class, give your new class a private field that references an instance of the existing class... Each instance method in the new class invokes the corresponding method on the contained instance of the existing class and returns the results. This is known as forwarding, and the methods in the new class are known as forwarding methods... adding new methods to the existing class will have no impact on the new class... It's tedious to write forwarding methods, but you have to write the reusable forwarding class for each interface only once, and forwarding classes may be provided for you. For example, Guava provides forwarding classes for all of the collection interfaces.
My question is, doesn't the risk remain that methods could also be added to the forwarding class, thereby breaking the invariants of the subclass? How could an external library like Guava ever incorporate newer methods in forwarding classes without risking the integrity of its clients?
The tacit assumption seems to be that you are the one writing the forwarding class, therefore you are in control of whether anything gets added to it. That's the common way of using composition over inheritance, anyway.
The Guava example seems to refer to the Forwarding Decorators, which are explicitly designed to be inherited from. But they are just helpers to make it simpler to create these forwarding classes without having to define every method in the interface; they explicitly don't shield you from any methods being added in the future that you might need to override as well:
Remember, by default, all methods forward directly to the delegate, so overriding ForwardingMap.put will not change the behavior of ForwardingMap.putAll. Be careful to override every method whose behavior must be changed, and make sure that your decorated collection satisfies its contract.
So, if I understood all this correctly, Guava is not such a great example.
doesn't the risk remain that methods could also be added to the forwarding class, thereby breaking the invariants of the subclass?
Composition is an alternative to inheritance, so when you use composition, there is no sub-class. If you add new public methods to the forwarding class (which may access methods of the contained instance), that means you want these methods to be used.
Because you are the owner of the forwarding class, only you can add new methods to it, thus maintaining the invariant.

Can a Java constructor return already existing object of same type?

Whenever we call a constructor in Java, it creates a new object and returns its reference in the end (of newly created object).
Is there any possibility that a Java constructor does not create a new object but return the reference to an already created object?
// Is it possible that myObject is not a new object, its already existing object
MyClass myObject = new MyClass();
I have a list of objects of some class, and based on few parameters in constructor sometimes it more efficient that I don't create a new object, instead I pick up an already existing object. Is there is any other way?
No. Constructors by definition run when a new object is created to initialize it. If the constructor is run, a new object has already come into existence, and there's nothing you can do about it.
What you could do is make a static method which either creates a new object, or returns an existing one. This is the standard approach in such cases.
Say, Boolean.valueOf(boolean value) in the standard library exists for the purpose of avoiding creation of extra objects. You can create them using new Boolean(value), but it is much better to call this method because it will return the same object for the same values.
you cannot do this using constructors but you could use one of the patterns mentioned below.
If you only ever need 1 object then use the Singleton pattern.
If your might have a few variations then use Flyweight pattern as duffymo mentioned.
As duffymo mentions in his comment below - if you using any of these patterns then its important from a concurrency perspective to understand that these objects will be global state - you should therefore ensure they are immutable, and if you cannot make them immutable then you may want to rethink your approach.
No, this is not possible.
JLS section 15.9:
Unqualified class instance creation expressions begin with the keyword new.
An unqualified class instance creation expression may be used to create an instance of a class, regardless of whether the class is a top level (§7.6), member (§8.5, §9.5), local (§14.3), or anonymous class (§15.9.5).
and JLS section 12.5:
A new class instance is explicitly created when evaluation of a class instance creation expression (§15.9) causes a class to be instantiated.
...
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure: [...]
Notice that this clearly mentions creation of objects and not a possibe re-utilization.
On the other hand, you could create a static factory for your object that uses a pool. You could take a look at the implementation of Integer.valueOf(i) for example. Refer to this answer for example.
You cannot achieve this with just a constructor in Java.
If required, such a behaviour is achieved by using either static method inside the class (like Integer.valueOf(0)) or the whole dedicated object of the different class (like DocumentBuilderFactory) to return the instances. This provides enough control to substitute the existing object instead of always creating a new one.
As a rule, such objects should be immutable and thread safe to be easily shareable. Also, instance reuse and sometimes caching is implemented along these lines.
No. Class provides the blueprint for objects, when using the new operator it is followed by a call to a constructor, which initializes new object.
Source.
If you wish to reuse objects for any reasons you may want considering implement the Flyweight pattern as well as the Factory pattern into your project for best result.
No it's not possible. Create a static method to create objects based on required logic and don't forget to make constructor private.

How to get all classes that "participate" in a given object?

I have a java object, an instance of class Object - that's all I know about it. Now I need to create a list of Class-es that took participation in its creation, including its own class, all parent classes, all classes of its properties and methods. For example:
List obj = new ArrayList();
obj.add(new Integer(4));
obj.add(new Foo());
System.out.println(allRelatedClasses(obj));
Should output something like this:
Object, List, Collection, Iterable, Serializable, Cloneable, RandomAccess,
ArrayList, Integer, Foo
Is it possible at all?
The Reflections library can handle quite a bit of that.
In terms of "what took part in its creation", you'll need to pull that out of the bytecode. There are several libraries that can help with this, like ASM and BCEL. If you just need all dependencies, DepFind might be enough.
If you need to limit yourself to what you said, "what's involved in its creation", then you'd only want the classes involved in the ctor and methods the ctor calls.
If a class uses any reflection, however, all bets are off--those types of dependencies are difficult to track down, and it's difficult/impossible to identify what's actually used.
Sure, you can do it using reflection. obj.getClass() returns your own class, obj.getClass().getParent() returns its parent. Then you can call getParent() in loop until you arrive to Object.
The same is with interfaces, fields, methods, annotations. Just do not forget that you should call getDeclaredMethods() and getDeclaredFields() to get all methods and fields including private. And you have to call setAccessible(true) to deal with private members.
1 hour of work and you are done. Go! Good luck.

What's the difference between these two java variable declarations?

public class SomeClass {
private HashSet<SomeObject> contents = new HashSet<SomeObject>();
private Set<SomeObject> contents2 = new HashSet<SomeObject>();
}
What's the difference? In the end they are both a HashSet isn't it? The second one looks just wrong to me, but I have seen it frequently used, accepted and working.
Set is an interface, and HashSet is a class that implements the Set interface.
Declaring the variable as type HashSet means that no other implementation of Set may be used. You may want this if you need specific functionality of HashSet.
If you do not need any specific functionality from HashSet, it is better to declare the variable as type Set. This leaves the exact implementation open to change later. You may find that for the data you are using, a different implementation works better. By using the interface, you can make this change later if needed.
You can see more details here: When should I use an interface in java?
Set is a collection interface that HashSet implements.
The second option is usually the ideal choice as it's more generic.
Since the HashSet class implements the Set interface, its legal to assign a HashSet to a Set variable. You could not go the other way however (assign a Set to a more specific HashSet variable).
Set is an interface that HashSet implements, so if you do this:
Set<E> mySet = new HashSet<E>();
You will still have access to the functionality of HashSet, but you also have the flexibility to replace the concrete instance with an instance of another Set class in the future, such as LinkedHashSet or TreeSet, or another implementation.
The first method uses a concrete class, allowing you to replace the class with an instance of itself or a subclass, but with less flexibility. For example, TreeSet could not be used if your variable type was HashSet.
This is Item 52 from Joshua Bloch's Effective Java, 2nd Edition.
Refer to Objects by their interfaces
... You should favor the use of interfaces rather than classes to refer to objects. If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface types. The only time you really need to refer to an object's class is when you're creating it with a constructor...
// Usually Good - uses interface as type
List<T> tlist = new Vector<T>();
// Typically Bad - uses concrete class as type!
Vector<T> vec = new Vector<T>();
This practice does carry some caveats - if the implementation you want has special behavior not guaranteed by the generic interface, then you have to document your requirements accordingly.
For example, Vector<T> is synchronized, whereas ArrayList<T> (also an implementer of List<T>) does not, so if you required synchronized containers in your design (or not), you would need to document that.
One thing worth to mention, is that interface vs. concrete class rule is most important for types exposed in API, eg. method parameter or return type. For private fields and variables it only ensures you aren't using any methods from concrete implementation (i.e. HashSet), but then it's private, so doesn't really matter.
Another thing is that adding another type reference will slightly increase size of your compiled class. Most people won't care, but these things adds up.

Categories