In Scala, you can define a class as this:
class MyClass[T1[T2]] {
def abc(a1: T1[Double]):T1[Int] = ???
}
In this code, type parameter T1 represents a type that needs one type parameter T2, so we can create an instance like new MyClass[List].
I want to do this in Java, but I don't have any idea.
I wonder if it is possible in Java, and if not, any idea how I can do this thing in Java.
From my understanding, generic type essentially makes a function of types. So if you have a class like List<T>, you can think of the class List a function of type, so List takes a type parameter like Integer, then it will be a concrete type like list of integers(List<Integer>).
MyClass above takes a type parameter T1, but I want this T1 is also a generic type that takes a type parameter T2, so I can create an instance like MyClass<List> and can use type like List<Integer> or List<Double> inside MyClass. In Scala, if you try MyClass[Int] or MyClass[String] will fail because Int or String does not take a type parameter.
Of course, this may not be necessary if I allow to duplicate some codes, but to make a more general code, I think it is indispensable.
The only way for this to work in Java is to have a common interface for T1.
public interface GenericType<T> {
// ...
}
Then you can define your class as:
class MyClass {
public GenericType<Integer> abc(GenericType<Double> a1) {
//...
}
}
Note that you don't need any more type parameters at the class level anymore because of the common interface. Then before invoking MyClass.abc you would need to wrap the instance you are passing in GenericType.
You can also go one abstraction level higher and define
class MyClass<T1,T2> {
public GenericType<T1> abc(GenericType<T2> a1) {
//...
}
}
This would give you some more flexibility in using MyClass. But that is heavily dependent upon how MyClass is actually implemented.
Related
Let's say I've a java base class:
class base {
public Class<? extends base> type;
// ...
}
type stores the classtype of classes which inherit from base
There's another class which stores base objects in a container, it also has a get method which returns objects stored in that container:
class container {
private Vector<base> v;
//...
public <something here> get(int i){
base b=v.get(i);
return b.type.cast(b);
}
How do I implement such a function(container.get), which casts the object to it's correct type before returning it?
It would be nice to be able to program in a cascading style:
JSONObject o;
//...
o.get("nestedObject").get("array").get(3);
You may be misunderstanding what a "cast" is in Java. Except for casts that involve primitive types (such as casting an int to a float), casts don't change objects at all.
One of your instance variables is
private Vector<Base> v;
(Please use the Java convention and start class names with upper-case letters. I've changed base to Base to set a good example.)
The objects that you put in this vector can be of type Base or any subclass of Base. The type of the object is fixed when the object is constructed. Suppose Base has three subclasses, Child1, Child2, and Child3. Those objects can be construted with new Child1(...), new Child2(...), new Child3(...). As soon as you say new Child1(...), you have an object whose type is Child1, and you can't do anything to change that. But since a Child1 is a Base, you can use your Child1 anywhere you can use a Base, such as putting it into your vector v.
Casting just causes the compiler to look at a variable differently. Suppose you say
Base x = v.get(i);
x (if not null) will be a Base or some object of a subclass. The type of x will be whatever you used to construct the object. Now if you say
Child1 y = (Child1)x;
If x is a Child1, y will be a reference to the same object as x. But the compiler will know that y is a Child1, and you can access new methods that are defined in a Child1. (If x isn't a Child1, you get an exception.) But it's important to note that a cast does not create a new object and it does not change the type of anything. It just tells the compiler to look at a variable or expression in a different way.
Given this, you cannot gain anything by trying to write a method that returns a "variable" type. You may as well just write
public Base get(int i){
return v.get(i);
}
The object that it returns could be a Base, Child1, Child2, etc.; it will be the same type as the object was when you put it into the vector. When you call get, if you are expecting the result to be a Child1, you can say
Child1 child = (Child1)container.get(n);
which will throw an exception if the object isn't a child1. Or you can use instanceof to check yourself:
Base child = container.get(n);
if (child instanceof Child1) {
...
}
If this isn't good enough, you'll need to explain more clearly what you want to accomplish and why this won't work.
MORE: After reading your edit, that says you want to do something like this:
JSONObject o;
//...
o.get("nestedObject").get("array").get(3);
You don't need any casting to accomplish this. What you need is an abstract JSONValue base type that represents any kind of value that can be returned from a JSON parser. The subclasses would be things like "object", "array", and whatever scalar types you need (integer, string, etc.). get would return JSONValue. In actuality, it will return an object of one of the other types, but all the compiler needs to know is that it returns JSONValue.
Now a JSONValue will need two get methods, one that takes a String and one that takes an int or Integer. These will be polymorphic methods. Say v is a JSONValue and you say v.get("array"): the method it actually calls may be different based on the actual type of v. So if v is your "object" type, it will call the method you've defined for the object type; if v is an integer type, it will call the method defined for the integer type, and so on. What you want is for the get method that takes a String to look up the field for the JSON "object" type, and throw an exception for everything else. Similarly, for the get method that takes an integer parameter, the method for the JSON "array" type will look up a list or something, and the method for every other subclass of JSONValue will throw an exception. No "casting" is needed for this. Casting is a compile-time concept. At all points, the compiler will know only that it's working with a JSONValue. But at run time, the object's actual type is used to determine which method to call, so the compiler doesn't need to know anything more.
This is a basic concept that all Java programmers need to know (also Javascript, Python, and pretty much every other language these days, although polymorphism is handled differently in interpreted languages like Javascript and Python). The tutorial https://docs.oracle.com/javase/tutorial/java/IandI/index.html covers this and related concepts. There may be better Java tutorials on "polymorphism" out there also.
type stores the classtype of classes which inherit from base
This is equivalent to this.getClass().
How do I implement such a function(container.get), which casts the object to it's correct type before returning it?
Not possible in theory. People will create more subclasses and put it in the container, after the code is compiled and shipped. That's the purpose of have a base class -- so that the other part of your codebase only has to work with a single interface/concept.
So basically what you want to write is just some generic container code.
interface Container<T extends Base> {
public T get(int i);
}
But the real question was How can the container accommodates a set of known subclasses? Just use different method names. Gson does it.
public class Container {
public Base get(int i) { ... }
public SubType1 getAsSubType1(int i) { ... }
public SubType2 getAsSubType2(int i) { ... }
}
And you can add custom cast methods to Base too.
You can't do that. Generics doesn't really work that way. There's no way to know the exact subtype of your object at compile time.
This b.type.cast(b); casting will need to be done on the result of your method public <something here> get(int i) wherever it's called.
If you have designed the system well you won't need to cast the object back to the exact subclass much, if at all.
Otherwise your best bet is to do a instanceof type check where needed.
I think you are referring to Generics
class container<GenericType> {
private Vector<GenericType> v;
//...
public GenericType get(int i){
GenericType b=v.get(i);
return b;
}
}
I am having some (philosophical?) problems with java's generics...
Consider the following
public interface ClassA<I> {}
public class Obj implements ClassA<String> {}
public interface ClassB<I, T extends ClassA<I>> {
public I getSomething();
public T getAnotherThing();
}
This compiles and works ok, if an object of ClassB is instantiated as:
ClassB<String, Obj<String>> o = new ClassB<>();
o.getSomething(); // <-- Returns String
I was wondering if there is a way to avoid instantiating a ClassB object without having to specify the String generic as well, since it's already inside ClassA. More specifically, I'd like to use it as:
public interface ClassB<T extends ClassA<I>> { // <-- Won't compile
public I getSomething();
}
ClassB<Obj> o = new ClassB<>();
o.getSomething(); // <-- Returns String from Obj declaration, which uses ClassA<String>
I know the "problem" can be easily gotten over with the first example, but I wanted to know if there's a way of reference the actual type of the generic in the implementing ClassA object without having to pass it again in ClassB's declaration, and if not, why.
Hope I was clear enough with my dilemma.
Thanks
I think the answer is "No". :)
Java doesn't provide a way to extract a type argument from a type itself, only from an argument having that type.
Eg:
class ClassB<T extends ClassA<?>> {
<I> I getSomething(ClassA<I>) { ... }
}
... works fine and could be passed an instance of T in order to extract I. But to remove the parameter from the method (which is used only to determine the type for I) you'd need a way to determine I from T itself, and there is no such way.
In general, type inference in Java is limited to establishing a relationship between parameter types and/or between parameter and return types.
The other way, then, would be to declare I and T together as part of one generic parameter, as you tried:
public interface ClassB<T extends ClassA<I>>
But then, as you noted, this is not accepted either. Java's syntax would need to be expanded in order to allow this.
I was wondering, aside from syntactic difference, when would one use a generic interface over a method that accepts a generic parameter?
public interface Flight<T>{
void fly(T obj);
}
over
public interface Flight{
void <T> fly(T obj);
}
If you declare a generic method, you always let the caller decide, which type arguments to use for the type parameters. The implementation of the method must be able to deal with all possible types arguments (and it doesn’t even have a way to ask for the actual type arguments).
That said, a method like <T> void fly(T obj); states that the caller may use any type for T while the only thing the implementation can rely on is that the actual type for T will be assignable to Object (like if <T extends Object> had been declared).
So in this specific example, it’s not different to the declaration void fly(Object obj);, which also allows arbitrary objects.
In contrast, a type parameter on an interface is part of the contract and may be specified or restricted by an implementation of the interface:
public interface Flight<T>{
void fly(T obj);
}
allows implementations like
public class X implements Flight<String> {
public void fly(String obj) {
}
}
fixing the type of T on the implementation side. Or
public class NumberFlight<N extends Number> implements Flight<N> {
public void fly(N obj) {
}
}
being still generic but restricting the type.
The signature of an interface is also important when the interface itself is a part of another method signature, e.g.
public void foo(Flight<? super String> f) {
f.fly("some string value");
}
here, the Flight implementation, which you pass to foo, must be capable of consuming a String value, so Flight<String> or Flight<CharSequence> or Flight<Object> are sufficient, but not Flight<Integer>. Declaring such a contract requires type parameters on the interface, not at the interface’s methods.
You should use a generic type when you expect that most of the methods, in the implementations, will perform operations on the type supplied when instantiating the class.
For example, ArrayList<E> is a generic type since most of its operations (add, get, remove etc.) rely on the type specified upon creation of one.
A generic method should be used when only a few methods in the class rely upon the different types.
You can read more about generics in the Java Docs.
Take for example the class java.util.ArrayList<E>. When creating variables of that type, you have to specify a concrete type for T:
ArrayList<String> list = new ArrayList<>();
These concrete types are used, when calling methods from the List interface, that work with the type T. Calling the add method, you can only add String objects to the list. Retrieving elements from the list using get, you will get elements of the concrete type String.
For generic methods, the type T is specified only for this method. And it would make more sense if the methods returns a value of that generic type. You often find code like this:
MyObject obj = SomeClass.staticGenericMethod(MyObject.class)
or
MyObject obj = classInstance.genericMethod(MyObject.class);
And you should start your interface name with a capital letter: Flight<T>
Initial Situation:
I created a factory interface for some other generic interface A<T>:
public interface Factory<T, X extends A<T>> {
public X create();
}
Problem Description:
Now i have the problem that i need to instantiate a factory for every single type T. This becomes very unhandy, especially if some code wants to do some transformation from A<T> to A<T2>, where T2 is some previously unknown type or there are so many different T2, that i do not want to specify hundreds of factories for each special case.
The Goal:
I would like to pass the type T as a generic parameter of the create method. Such that i get something like (Attention, not correct Java :-) ):
public interface Factory<X extends A<?>> {
public <T> X<T> create();
}
An implementation of Factory might then simply do something like:
public class Factory4B implements Factory<B> {
public <T> X<T> create() {
return new B<T>();
}
}
Writing the above version of the interface down gives the error message for the return value of create:
The type X is not generic; it cannot be parameterized with argument
The Question:
Is there some way to realize such a generic factory, or do i need to use a totally different approach? I want to be able to specify X at the class level, such that i can instantiate X easily. I do not want to create a single Factory for every parameter T
Thank you for your time to answer this question in advance.
Rethinking the problems based on the below comments (27.4.15)
Rethinking the problem based on the comments below, my question is not possible to realize as it is not possible to guaranty that the generic parameters are still present in the subclasses of A<T>, or in other words: there is no inheritance of generic parameters.
Example:
Lets think of a class C which is derived from A<String>.
It is not possible to create C<Integer> as C has no type argument.
Therefore, there exist no general Factory, that might create C<Integer>
No, this is not possible with generics alone. Due to "type erasure" the type of T is not there anymore at runtime, so Java doesn't know what constructor to call.
You'll have to find a way to pass the type of T to your class at runtime. In, Java you can use the class Class<S> as a runtime type token. Then your code might look something like this:
public <T> X<T> create(Class<T> classOfT) {
T t = classOfT.newInstance();
return new X<T>(t);
}
Please explain the custom 'T' in the java interface. It is using generics here and of type 'T' i suppose. Then where is the type 'T' defined?
public interface TemplateBuilder<T extends TemplateBuilder>
T is not an actual class. It is determined at compile time depending on the usage of your class TemplateBuilder. Just think of it as a place holder for various possible types, one of which is 'chosen' depending on your circumstances.
For a simpler example, look at the following (adapted from Java's tutorial):
Imagine you want to declare a class Box, which can take a specific type (of the object to hold inside the box), but you wish to reuse this in various circumstances to hold various different types.
So instead of fixing the actual type the Box can take, you declare it as follows:
public class Box<T> {
private T t; // T stands for "Type"
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
When you use it, you then do something like:
Box<Integer> integerBox = new Box<Integer>();
Whats the whole point you might ask? Why not make Box take an Object?
In fact before Java 1.5 this was not possible. This was introduced to have further type-safety in these situations, and was adopted in the Collections framework.
The whole point is that without this mechanism, if instead it used Object, you can't force a specific instance of your Box to hold only Integers. On the other hand, if you made it use specifically Integers, you can't reuse your Box for String, or other objects, and you would need to create another type of Box class.
Before Java 1.5, objects like ArrayList took plain Objects, however there were often cases of type safety broken at runtime, because the program is assuming a list of Integer objects and by mistake somewhere a String is inserted. Generics (through this magic T) force types without restricting what they might be.
In your case T extends TemplateBuilder is going one step further and stating that whatever T is, it must be a class that extends TemplateBuilder. If that wasn't there, it would be any class that extends Object (the universal base class of Java).
T is any Object that extends from TemplateBuilder
T means any Object. for example
List<T> list = new ArrayList<T>();
here T can be Integer, String ...
and <T extends A> means any Object T extends from A
This type is defined when implementing the interface, i.e.
class StringBuilder implements TemplateBuilder<StringBuilder> {}
BTW, see class Enum (the base class of all enums).
My Custom Generics Explanation
Backgorund:
Custom generics are used invariably with data structures e.g. when managing(storing/retrieving) lists of "things"
You do not need to do your own type checking in order for the code to compile as custom generics incorporates the principles of polymorphism.
However, in contrast to the "traditional" OO principles of polymorphism, a class can store a list of things without having any relationship with the "thing(s)" it is storing (The Fundamental Principle of OO where A is a super class of B class is not required)
You do not make separate subclasses for every possible kind of class of "things" you wish to store.
Example 1
As an example consider the following two classes below which are unrelated. This is a very primitive example but nonetheless gives an outline of the principles of custom generics:
/**
*
* Class A is a Custom Generic class that can be 'typed'
* to any kind of class using diamond 'T' syntax.
*
*/
class A<T>
{
// The instance variable of the object type 'T' known at run time
T theI;
// The constructor passing the object type 'T'
A(T anI)
{
this.theI = anI;
}
// Method to return the object 'T'
T getT()
{
return theI;
}
}
Below is the class B which is unrelated to class A i.e. B does not extend A:
/**
*
* Simple class which overrides the toString()
* method from Object's class toString() method
*
*/
class B
{
#Override
public String toString()
{
return "B Object";
}
public static void main(String[] args)
{
A<B> a = new A<>(new B());
System.out.println(a.getT());
}
}
In Main method of class B above:
a.getT() returns the object 'T' which in this example is of type 'B' (This is an example of polymorphism).
a.getT() returns the object 'T', object instance C's method toString() gets IMPLICITLY called, as it is overriding Object's toString() method and prints "B Object".
The interesting aspect to note about Custom Generics and polymorphism is that:
In the context of custom generics, there are no constraints for a relationship among classes in order to execute polymorphism
e.g. Class B is unrelated to A above i.e class B DOES not extend A.
In "traditional" object orientated polymorphism principles, there is invariably a requirement constraint for classes to be related in some way. However, this is not required in custom generics.
Example 2
public interface TemplateBuilder<T extends TemplateBuilder>
The above means that TemplateBuilder interface can be typed to any class that extends TemplateBuilder.
Let's assume SomeClass extends TemplateBuilder then the following is fine:
TemplateBuilder<SomeClass> tbRef = ...
/* Using an Anonymous Inner Class reference to interface TemplateBuilder<SomeClass> */
or
TemplateBuilder<SomeClass> tbRef = .... /* Referencing a concrete class
that implements TemplateBuilder */