Cast to instance's type automatically - java

I have a function that should take an instance of anything extending Object, and just pass the casted instance to a function. I don't want to use a switch, as the function can accept a huge number of object types, so it would become a very big method.
public void attachBufferData(ContextConstant bufferType, Object<T> data, ContextConstant usage) {
glBufferData(bufferType.getGLType(), (T) data, usage.getGLType());
}
The code above doesn't work (as Object isn't a generic type), but it should get across what I'm trying to do.
----- EDIT -----
Ok, I tried this:
public void attachBufferData(ContextConstant bufferType, Object data, Class<?> dataType, ContextConstant usage) {
glBufferData(bufferType.getGLType(), dataType.cast(data), usage.getGLType());
}
But I get a compile error glBufferData(int, long, int) is not applicable for arguments (int, capture#1-of ?, int). I guess it's a massive switch statement then :(

You can't do it like this, I'm afraid. There are three things to consider. I think (2) is the one you really want, but I'm not absolutely certain, so I've left all three issues in there for you to think about.
What signature does glBufferData() have (if it's not overloaded)? If its second parameter is of type Object, then whatever you pass will end up being viewed as an Object there, even if it's a subclass, so you wouldn't achieve anything by having it cast. You might as well just have the type of data as the same type as the second parameter to glBufferData().
If glBufferData() is an overloaded method, and you want to be calling the right one, then you can't do it dynamically: you need some code to test the real type of the class at runtime, and then you choose the right version to call. Choice of overloaded method gets resolved at compile time, not runtime, so you can't just pass it a specific instance you don't know about at compile time and then have it select the right version.
If glBufferData() is a non-overloaded method you've written, contained within your class, then you do have another and better option, which is to make your class generic. If your class takes a type parameter of T, then you can have T data as the second parameter of attachBufferData(), and you can have T data as the second parameter of glBufferData(), so that the types match up.
The point about method overloading is that it's not nearly as clever as it looks. As far as the compiler is concerned, there's really no difference between these two cases.
Case 1:
public void f(int x);
public void f(String s);
Case 2:
public void f(int x);
public void g(String s);
Although we think of case 1 as having just one overloaded method, and case 2 as having two separate methods, as far as the compiler's concerned, in each case there are two distinct methods, and they're distinct because they have distinct signatures (ignoring return type). In both cases, the compiler can choose the right method to call based on the code you write, because it can look at the type of the arguments and the name of the method you've asked for, and find one that matches. The fact that two have the same name is of no more significance than having two methods with different names but the same parameter types.
There's no mechanism for choosing which method to call at runtime in case 1, any more than there is in case 2.

You can declare the type at class level and reuse it wherever required, below is an example.
public class ExceptionHolder<T>
{
private List<T> errors = new ArrayList<T>();
public void addError( T t )
{
errors.add( t );
}
public void addError( List<T> t )
{
errors.addAll( t );
}
}
In the calling code
ExceptionHolder<String> exHolder = new ExceptionHolder<String>();
String can be substitued for any object as needed.

Related

Java: implicit type conversion, or implicit toString() invocation

In my Java application I created methods that return Either<String, T> objects.
This is because in some places I invoke these methods as the parameter of (3rd party) methods that expect a String parameter as input.
While in other places I invoke these methods as the parameter of (3rd party) methods that expect some other parameter type (T) as input.
So depending on the place where I invoke the methods that I created, the code looks like:
their.thirdPartyExpectsString(my.calculateEither().getLeft());
their.thirdPartyExpectsString(my.calculateEither() + "");
or
their.thirdPartyExpectsDouble(my.calculateEither().getRight());
(I defined Either.toString() as Either.getLeft()).
Pay attention, I cannot change the 3rd party code (anyway not without bytecode manipulation), and I would like to keep my design in which I return Either from my methods.
Is there a way to simplify my code and make it look like
their.thirdPartyExpectsString(my.calculateEither());
their.thirdPartyExpectsDouble(my.calculateEither());
I.e., not having to add the getLeft()/getRight() or + "" all the time?
Actually, it does not bother me much if I will have to do
their.thirdPartyExpectsDouble(my.calculateEither().getRight());
because I don't have to do it often. But I would like to get rid of the need to call getLeft() or + "" when my.calculateEither() returns a Left (a String).
Given an either, it's not hard to see if it represents Right or Left, simply by checking which side has a null.
But the problem is with the type conversion, i.e. the compilation error when thirdPartyExpectsString() expects a String but gets an Either.
I was able to catch the return value of my.calculateEither() by AspectJ but I could not see a way how to use something like #AfterReturning advice to make the compiler understand that I want to return my.calculateEither().getLeft(), i.e a String....
Any ideas?
Add the following method to your implementation of the Either class:
#SuppressWarnings("unchecked")
public <T> T whichever() {
return (T) (isLeft() ? getLeft() : getRight());
}
Note that I'm purposefully ignoring the warning about the unchecked cast, and indeed will cause a ClassCastException if you use it in a place where the external API you interface with expects a left value but you invoke it on an Either instance which contains a right value. This method will do an implicit cast based on where you use it. It will cast to a T type where you pass it to another method which expects an argument of type T or you try to assign the method return value to a variable of type T.
So the following demo code:
Either<String, Double> containsString = Either.<String, Double>left("first");
Either<String, Double> containsDouble = Either.<String, Double>right(2d);
their.expectsString(containsString.whichever());
their.expectsDouble(containsDouble.whichever());
their.expectsDouble(containsString.whichever());
will work well in the first invocation and will cause a ClassCastException in the third invocation, just an one would expect, because we consider it as an illegal use case.
In conclusion, it's nice to know that it will work in all places where the T type to which we are implicitly casting is assignable to the actual value contained by the Either object. Unfortunately, you will only find out at run time, should this not be the case.
Add a helper method. Since you cannot add new methods to their, you have to add a static to a class of your own.
Pseudo-code:
public static void thirdParty(Their their, Either either) {
if (either.isLeft())
their.thirdPartyExpectsString(either.getLeft());
else
their.thirdPartyExpectsDouble(either.getRight());
}
You can now call:
MyHelper.thirdParty(their, my.calculateEither())

How do I make a function accept any type (not necessarily an object)?

I have a function
boolean isValid(/* what goes in here? */) {
//do stuff
}
In the function signature, what do I have to enter in the parameter list in order for the method to accept a single parameter that may be of any type (primitive or object)?
I have searched around on this site and google, but I could only find situations where the return type is unknown.
If you have the function accept the generic object type, Java will create an object version of any primitive data type (i.e. Integer for int).
Reading the question and the comments, it seems like your perception of how compiled languages work may be a bit off.
If you make your function accept only one type (e.g. String), then it will fail to compile if the caller does not pass an object that is an instance of that type. "Not compiling" means they will not even be able to run the program without fixing the error. The compiler enforces this type safety for you, so you don't have to worry about this.
After reading through the comments it seems like you have a business need to valid any object people pass to you, and possibly, you will have to support more types as time goes on.
The simplest solution is like what jtoomey said, make a method like public boolean isValid(Object val). However, think about how much if statements you have to write, and how hard is it to modify the code when new type validation are needed.
To me, I would probably do something bit more complicated than just providing a single method. I would leverage factory to create validator base on class type like:
public interface Validator<T> {
public boolean isValid(T val) {
}
}
public class ValidatorFactory {
public static ValidatorFactory create(String configFile) {
/*read config and create new instance */
}
public Validator<T> createValidator(Class<T> clazz) {
/* base on config and create validator base on type*/
}
}
public class Application {
public static ValidatorFactory vFactory = ValidatorFactory.create()
public static void main(String[] args) {
Object val = Arguments.getVal(); //assume this exists
Validator<Object> validator = vFactory.create(val.class);
if (validator == null) {
System.out.println("not valid");
return;
}
System.out.println(validator.isValid());
}
}
Note that personally I feel this is a terrible solution, because you are throwing away the type safe feature of Java. But if you really must, having a configurable factory would be better than just a method that takes in any type. Having the Validator interface allows you to know the type when you are writing validation code.
I think you are a bit confused.
I will try to clarify some things:
You probably know that the return type of a method is the value that will be pass to the part of the code that called that method(aka know as client). Every method/function in Java can only return only one type(I assume you are familiar with basic polymorphism and you know what an IS A relationships is...). Here is the first clarification, you can return only one type, but one or many objects(There are data structure types).
Arguments are the values that the caller/client of the method/function can pass into the it for processing. Arguments can have zero or many parameters, this mean that you can pass as many objects as you want.
Parameters are exactly the same as arguments it is just a terminology difference nothing else. I you want to be accurate with the terms, you can say that parameters are the brackets when you define the method and argument are those brackets when you call the method.
In either the return type or in the parameters/arguments, the 2 types of types you can pass are Objects or primitive types.
If you use something of type Object, this will allow you to return any object(Object is the super class of all classes). But primitive types are not objects, so a type Object in a signature will not allow you to pass a number, but there is one little trick...
In Java there are special types of Objects known as primitive wrappers(Integer,Double...) this objects are object representations of primitives, sometimes they are used because they have some inbuilt functions that help programmers to easily manipulate the data(That is not the main point, keep reading...),every wrapper that represents a numerical primitive type, extends a class called Number and because of one feature that Java have known as autoboxing, you can pass primitives into Wrappers automatically.
Anyway, I don't know if this is the trick you were looking for, but in any case I want just to advice you, that there is no reason at all to do what you are trying, It sounds really strange and I don't think that such thing is really needed in real life programming.
Have a look at this code :
public static void main( String[] args )
{
App app = new App();
app.method(5);
}
public void method(Number number) {
System.out.print(number);
}
Another alternative:
Another example that I can think about in order to make a parameter universal is by the use of generics. So just for ending this answer to prove my point, here a method that will allow you pass anything you want, no mater if is primitive or object:
public class App
{
public static void main( String[] args )
{
App app = new App();
app.method(5);
app.someMethod(9);
app.someMethod("Whatever");
app.someMethod(true);
}
public void method(Number number) {
System.out.println(number);
}
public <T> void someMethod(T t) {
System.out.println(t);
}
}
I hope you find this useful, but I insist that I doubt that you will never do something like this in real life.

Can I work with generic types from a calling class?

I'm currently brushing up my Java and reading up on Generics. Since they were not treated extensively in my Java class, I'm still having some trouble wrapping my mind about it, so please keep that in mind when answering.
First of all, I'm pretty sure that what I'm trying to is not possible. However, I'd like to find out where my thinking is wrong and how I should go about achieving what I want.
What I'm trying to do is manipulating an object that implements a generic interface from another class that has no knowledge about the instantiated type. Thus, I have something like the following classes:
public interface CalledInterface<E> {
public E get() { ... }
public set(E e) { ... }
}
public class Called implements CalledInterface<String> {
...
}
Now what I want to do is:
public class Caller {
protected CalledInterface<?> c;
public Caller (CalledInterface<?> arg) {
c = arg;
}
public void run(){
// I can do this:
c.set(c.get());
// But I'd want to be able to do something like:
<?> element = c.get();
c.set(element);
}
}
What is the fundamental flaw in my thinking, if there is one? And what approach should I rather be taking?
First of all, keep in mind that generics is a compile time thing not a runtime.
Now in your Caller you defined Called c. Called is defined to implement CalledInterface<String>, so automatically, Called has the following methods generated at compile time:
String get();
void set(String e); //i assume you wanted to return void
So essentially this doesn't really make sense:
<?> element = c.get();
The Caller class isn't even aware Called is using generics internally, for it, Called just deals with strings.
UPDATE
Based on your comment, since you don't want Caller to use Called directly but use CalledInterface first thing you have to do is change the type of c to that. In this case you should not use generics, because the whole point of generics is that the same class is used in different scenarios with different types (again determined at compile time), enforcing types without having repeated code.
If I understand correctly you don't want to restrict Caller to use String, so what you have to do is change CalledInterface to not use generics, and change the methods to:
Object get();
void set(Object o);
This is how we used to do things before Generics in Java 1.4. You obviously run the risk of not having type safety, so think through whether what you want really makes design sense, because it probably does not because you have to do instanceof anyway to check the type to use the Object in a useful way (i.e. to access its methods).
If on the other hand you just change the c member (and the constructor argument of Caller) to:
CalledInterface<String> c;
Your Caller will be interacting with the CalledInterface rather than the implementation and at the same time still be type safe. So you can still pass an instance of Called and set it to c.
After your edit:
// I can do this:
c.set(c.get());
No you can't. It won't compile with c being CalledInterface<?>. (Have you even tried it?)
To do this, you can use a "capture helper":
private static <T> void helper(CalledInterface<T> c) {
c.set(c.get());
}
public void run(){
helper(c);
}
Which also solves your second problem:
private static <T> void helper(CalledInterface<T> c) {
T element = c.get();
c.set(element);
}
public void run(){
helper(c);
}
There are a few minor mistakes in your code:
protected Called c;
public Caller (CalledInterface arg) {
c = arg;
}
You are not allowed to assign arg here, because the type CalledInterface is not a subtype of Called (it is the other way around)
Also you should give type information when using CalledInterface (it is allowed to leave it out, but only for legacy purposes).
Now to the part you are wondering about. For the type Called, the compiler knows get() returns a String, if you are not interested in that, you can of course always use Object as the type of element. The compiler also knows that set() takes a String as argument, so it requires you to give one. In generics is essentially the same as using Object in a case without generics (even though it isn't allowed on the location you use it, because it doesn't make sense). This means that you would be telling the compiler to forget the type on the first line (calling get()) and to unforget it on the line below.

Java Generics methods - using for the first time

I am trying to use a generic method for the first time and am somewhat confused. I created a simple example to demonstrate that I am probably going about this the wrong way and need straightening out. I am using Eclipse 3.6.1. I was under the impression that the compiler determined the argument types through inference, but am not sure why it is forcing me use casting in the generic method. This is a simple example.
class Test1
{
Test1 () {};
public String getX () {return "Test1"};
};
class Test2
{
Test2 () {};
public String getX () {return "Test2"};
};
my main method:
public static void main(String args[])
{
Test1 tst1 = new Test1();
Test2 tst2 = new Test2();
System.out.println("result: " + displayTest(tst1, tst2));
}
static <T,S> boolean displayTest(T x, S y)
{
System.out.println("X: " + ((Test1) x).getX());
System.out.println("Y: " + ((Test2) y).getX());
if (((Test1) x).getX().equals(((Test2) y).getX()))
return true;
else
return false;
}
I thought the compiler would know that T in this case was an instance of Test1 and S was Test2, yet in Eclipse, getX is not a valid method. In order to get this to compile, it forces me to cast the objects to the correct type, which seems to me to be against the general principles of a generic method.
Obviously, I am not getting this and am doing something wrong. How does the compiler know what the types are in the generic method then ? How should something like this be done ? In my large system where I am trying to implement this, I have several methods that operate on different types of objects and am trying to make them generic. i.e. Method 1 calls Method 2 (which uses the generic type), which in turn calls Method 3 (again passing the generic types). I was hoping only the start of the function calls (calling of method 1 in this case) needed to know what type the objects were and all subsequent methods were just generic methods.
Many thanks.
The compiler does not know the types inside the method. They can be anything.
If you use <T extends Y>, where Y is an interface defining getY(), it would work.
The point of generics is to ensure compile-time safety. They are mainly a compile-time notion. For example:
public static <T> T instantiate(Class<T> clazz) throws Exception {
return clazz.newInstance();
}
This method can be used, without any cases, like this:
Foo foo = instantiate(Foo.class);
Bar bar = instantiate(Bar.class);
Another example, from the Collections framework. There is Collections.enumeration(collection), which is generic. So:
Enumeration<String> enumeration1 =
Collections.enumeration(new ArrayList<String>(..));
Enumeration<Integer> enumeration2 =
Collections.enumeration(new ArrayList<Integer>(..));
No casts, but you are certain that these will be the types. And then the nextElement() method will return either String or Integer, without the need to cast:
String s = enumeration1.nextElement();
Integer i = enumeration2.nextElement();
Without generics, you would need to use casts in these examples, and if you have passed the wrong argument, you would get a runtime exception (most likely a ClassCastException). With generics you get the exception at compile-time.
The compiler actually adds these casts on your behalf, but only after it is certain that the cast can't go wrong.
The problem is that at compile time the compiler does not know the concrete type of T and S. Your main method calls displayTest with concrete instances of Test1 and Test2, but there's nothing stopping you from calling it with, say, a String and an Integer.
This means that you can't call getX on x because you can't guarantee that T is a subclass of Test1.
You can constrain the type of T and S with captures:
boolean <T extends Test1, S extends Test2> displayTest(T x, S y)
This tells the compiler that T must be a Test1 (or a subclass of Test1) which means you don't need to cast.
Why would the compiler know that T and S are Test1 and Test2? You can call displayTest from anywhere in your code, any number of times with any number of different object types. What is it supposed to do there?
Also, eclipse != compiler. Eclipse's code completion doesn't "compile" anything. The compiler knows exactly what types are being put in there, but only for each CALL to that function. That's why it's called generic. It can take any generic type.
When you say the compiler determines the argument types through inference, it means something different than what you are thinking.
Since displayMethod is a generic method, the "proper" way to call the method is to tell the compiler what T and S stand for in this particular method call by calling it as
ClassName.<Test1,Test2>displayMethod(tst1,tst2)
But since java is smart, the compiler can infer w/o you telling it exactly what T and S, that T and S are going to be Test1 and Test2 if you just do,
ClassName.displayMethod(tst1, tst2)
Also, like cameron skinner said, you can fix your code by making T extend Test1 and S extend Test2. Another fix that you can do is leave <T, S> as it is, and renaming your getX() method to the override the toString() method. Since toString() is a member of the Object class, the generic classes T and S will have access to it and you won't need to restrict your method to only accept arguments which are of type Test1 and Test2

Java: which is faster overloading or if/else

I have child classes, each carries a different type of value along with other members. There may be a LongObject, IntObject, StringObject, etc.
I will be given a value, which can be a long, int, string, etc., and I have to create a LongObject, IntObject, StringObject, etc., respectively.
Would it be faster to overload a method as shown below (a) or just use a elseif as shown below (b)?
It may not be a noticeable performance difference. It may be that the overloaded methods are implemented in a similar manner to the if/else anyway. I don't know.
I can also hear some of you saying to just test it. Sure, I ought to. I would also like to know how this type of overloading is handled under the hood, if anyone knows.
Please let me know what you think.
Thanks,
jbu
a)
BaseObject getObject(long l)
{
return new LongObject(l);
}
BaseObject getObject(int i)
{
return new IntObject(i);
}
BaseObject getObject(String s)
{
return new StringObject(s);
}
...
b)
BaseObject getObject(Object x)
{
if(value is a long)
return new LongObject((Long)x);
else if(value is an int)
return new IntObject((Int)x);
else if(value is a String)
return new StringObject((String)x);
...
}
edit: I guess I didn't completely add all the details, some of you caught it. For both choices, I still have to get an object/value and from the value determine what type it is. Therefore, I still have to do an if/else of some sort to even use the overloaded methods.
There's a massive discrepancy here: overloads are chosen at compile-time whereas your "if (value is a long)" would be an execution-time test.
If you know the type at compile-time, I strongly suggest you use that information. If you don't, then the overloading option isn't really feasible anyway.
EDIT: The comment suggests I elaborate a bit about overloads being chosen at compile-time.
The compiler picks which method signature is called based on compile-time information about the arguments. This is unlike overriding where the method implementation to use is determined by the type of the actual target of the method.
Here's an example:
public class Test
{
public static void main(String[] args)
{
Object x = "I'm a string";
foo(x);
}
public static void foo(String x)
{
System.out.println("foo(String)");
}
public static void foo(Object x)
{
System.out.println("foo(Object)");
}
}
This prints foo(Object) because the compile-time type of x is Object, not String. The fact that the execution-time type of the object that x refers to is String doesn't mean that foo(String) is called.
The overloading solution is much faster (and better) because it is resolved at compile time.
Basically the compiler figure out which method to invoke when you pass a value to it. When you call getObject("abc"), the compiler will emit calls to method:
BaseObject getObject(String s)
{
return new StringObject(s);
}
rather than trying to go through your if ... else state and evaluate the object type (which is a slow activity) at run time.
Dont worry about, unless the condition is tested millions of times a second it doesnt matter.
a) (overloading) will be faster as it gives the just in time compiler a chance to optimize. It could decide to inline the new object creation.
Any time you have to evaluate type information at run-time, it's liable to be a relatively slow operation. When you have a choice, it's nearly always preferable to write code that does so at compile time.
This is often referred to as "early binding" versus "late binding."
Cascading conditionals is bad karma in OO programming, and really ugly when testing the type of an object. The language already provides that king of test, with polymorphism.
Also, as a non-java guy, I'd use getLong(l), getInt(i), getString(s).
I find method overloading more confusing than not (imho static types shouldn't influence the program execution (other than optimization-wise (and despite appearances I'm not a Lisper :) )))
Most importantly, getObj(int), getObj(string), etc. - will fail at compile time, if you try to pass something not expected.
If you allow any object to be passed into the method, you might have an instance where the app tries to pass in something that the method can't deal with, and you wind up with an ugly runtime error.

Categories

Resources