generics calling constructor - java

I am trying to do something I would not normally do, it is a bit odd, but I'd like to make it work. Essentially I have a factory that has to create objects by calling the constructor with different types of data (A and B take different types in the code below). I seem to have gotten my self stuck going down the generics route (I do need the code to be as compile time typesafe as possible). I am not opposed to writing the code differently (I'd like to keep the idea of the factory if possible, and I do not want to have to add in casts - so the "data" parameter cannot be an "Object").
Any thoughts on how to fix the code with generics or an alternative way of doing it that meets my requirements?
(Technically this is homework, but I am the instructor trying out something new... so it isn't really homework :-)
public class Main2
{
public static void main(String[] args)
{
X<?> x;
x = XFactory.makeX(0, "Hello");
x.foo();
x = XFactory.makeX(1, Integer.valueOf(42));
x.foo();
}
}
class XFactory
{
public static <T> X<T> makeX(final int i,
final T data)
{
final X<T> x;
if(i == 0)
{
// compiler error: cannot find symbol constructor A(T)
x = new A(data);
}
else
{
// compiler error: cannot find symbol constructor B(T)
x = new B(data);
}
return (x);
}
}
interface X<T>
{
void foo();
}
class A
implements X<String>
{
A(final String s)
{
}
public void foo()
{
System.out.println("A.foo");
}
}
class B
implements X<Integer>
{
B(final Integer i)
{
}
public void foo()
{
System.out.println("B.foo");
}
}

I don't see a way to make it work. I don't really think it should work either. When calling your makeX() function the calling code needs to know what integer parameter corresponds to what type of data to pass in. IOW, your abstraction is very leaky in the first place, and what you're really implementing is a rudimentary form of polymorphism, which you might as well use method overloading for, i.e.:
X makeX(String data) {
return new A(data);
}
X makeX(Integer data) {
return new B(data);
}
Of course it's a toy problem and all that. One way to make it work would be to make the client aware of implementation classes and add a Class<T> argument that you instantiate through reflection. But I suppose that would be kind of defeating the purpose.

I don't think what you're trying to do is possible without casting.
With casting, you have two options
if(i == 0)
{
x = new A((Integer)data);
}
else
{
x = new B((String)data);
}
}
or
class A
implements X<String>
{
A(final Object s)
{
}
}
...
class B
implements X<Integer>
{
B(final Object i)
{
}
}

Probably the closest thing you could get whilst retaining static type safety and having lazy construction is:
public static void main(String[] args) {
X<?> x;
x = aFactory("Hello").makeX();
x.foo();
x = bFactory(42).makeX();
x.foo();
}
private static XFactory aFactory(final String value) {
return new XFactory() { public X<?> makeX() {
return new A(value);
}};
}
public static XFactory bFactory(final Integer value) {
return new XFactory() { public X<?> makeX() {
return new B(value);
}};
}
interface XFactory() {
X<?> makeX();
}
So we create an instance of an abstract factory that creates the appropriate instance with the appropriate argument. As a factory, the product is only constructed on demand.
Clearly something had to give. What would you expect XFactory.makeX(1, "Hello") to do?

This is not possible without casting. As I have said elsewhere - generics don't remove the need for casting, but they mean that you can do all the casting in one place.
In the setup you describe, the factory method is exactly where all the under-the-hood work takes place. It's the spot where your code tells the compiler "I know you don't know what these types are, but I do, so relax.
It's entirely legit for your factory method to know that if i==1, then the data must be be of type Integer, and to check/enforce this with casting.

Related

How does the 'this' keyword play a role in overloading? [duplicate]

I have a collection (or list or array list) in which I want to put both String values and double values. I decided to make it a collection of objects and using overloading ond polymorphism, but I did something wrong.
I run a little test:
public class OOP {
void prova(Object o){
System.out.println("object");
}
void prova(Integer i){
System.out.println("integer");
}
void prova(String s){
System.out.println("string");
}
void test(){
Object o = new String(" ");
this.prova(o); // Prints 'object'!!! Why?!?!?
}
public static void main(String[] args) {
OOP oop = new OOP();
oop.test(); // Prints 'object'!!! Why?!?!?
}
}
In the test seems like the argument type is decided at compile time and not at runtime. Why is that?
This question is related to:
Polymorphism vs Overriding vs Overloading
Try to describe polymorphism as easy as you can
EDIT:
Ok the method to be called is decided at compile time. Is there a workaround to avoid using the instanceof operator?
This post seconds voo's answer, and gives details about/alternatives to late binding.
General JVMs only use single dispatch: the runtime type is only considered for the receiver object; for the method's parameters, the static type is considered. An efficient implementation with optimizations is quite easy using method tables (which are similar to C++'s virtual tables). You can find details e.g. in the HotSpot Wiki.
If you want multiple dispatch for your parameters, take a look at
groovy. But to my latest knowledge, that has an outdated, slow multiple dispatch implementation (see e.g. this performance comparison), e.g. without caching.
clojure, but that is quite different to Java.
MultiJava, which offers multiple dispatch for Java. Additionally, you can use
this.resend(...) instead of super(...) to invoke the most-specific overridden method of the enclosing method;
value dispatching (code example below).
If you want to stick with Java, you can
redesign your application by moving overloaded methods over a finer grained class hierarchy. An example is given in Josh Bloch's Effective Java, Item 41 (Use overloading judiciously);
use some design patterns, such as Strategy, Visitor, Observer. These can often solve the same problems as multiple dispatch (i.e. in those situations you have trivial solutions for those patterns using multiple dispatch).
Value dispatching:
class C {
static final int INITIALIZED = 0;
static final int RUNNING = 1;
static final int STOPPED = 2;
void m(int i) {
// the default method
}
void m(int##INITIALIZED i) {
// handle the case when we're in the initialized `state'
}
void m(int##RUNNING i) {
// handle the case when we're in the running `state'
}
void m(int##STOPPED i) {
// handle the case when we're in the stopped `state'
}
}
What you want is double or more general multiple dispatch, something that is actually implemented in other languages (common lisp comes to mind)
Presumably the main reason java doesn't have it, is because it comes at a performance penalty because overload resolution has to be done at runtime and not compile time. The usual way around this is the visitor pattern - pretty ugly, but that's how it is.
Old question but no answer provides a concrete solution in Java to solve the issue in a clean way.
In fact, not easy but very interesting question. Here is my contribution.
Ok the method to be called is decided at compile time. Is there a
workaround to avoid using the instanceof operator?
As said in the excellent #DaveFar answer, Java supports only the single-dispatch method.
In this dispatching mode, the compiler bounds the method to invoke as soon as the compilation by relying on the declared types of the parameters and not their runtime types.
I have a collection (or list or array list) in which I want to put
both String values and double values.
To solve the answer in a clean way and use a double dispatch, we have to bring abstraction for the manipulated data.
Why ?
Here a naive visitor approach to illustrate the issue :
public class DisplayVisitor {
void visit(Object o) {
System.out.println("object"));
}
void visit(Integer i) {
System.out.println("integer");
}
void visit(String s) {
System.out.println("string"));
}
}
Now, question : how visited classes may invoke the visit() method ?
The second dispatch of the double dispatch implementation relies on the "this" context of the class that accepts to be visited.
So we need to have a accept() method in Integer, String and Object classes to perform this second dispatch :
public void accept(DisplayVisitor visitor){
visitor.visit(this);
}
But impossible ! Visited classes are built-in classes : String, Integer, Object.
So we have no way to add this method.
And anyway, we don't want to add that.
So to implement the double dispatch, we have to be able to modify the classes that we want to pass as parameter in the second dispatch.
So instead of manipulating Object and List<Object> as declared type, we will manipulate Foo and List<Foo> where the Foo class is a wrapper holding the user value.
Here is the Foo interface :
public interface Foo {
void accept(DisplayVisitor v);
Object getValue();
}
getValue() returns the user value.
It specifies Object as return type but Java supports covariance returns (since the 1.5 version), so we could define a more specific type for each subclass to avoid downcasts.
ObjectFoo
public class ObjectFoo implements Foo {
private Object value;
public ObjectFoo(Object value) {
this.value = value;
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
#Override
public Object getValue() {
return value;
}
}
StringFoo
public class StringFoo implements Foo {
private String value;
public StringFoo(String string) {
this.value = string;
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
#Override
public String getValue() {
return value;
}
}
IntegerFoo
public class IntegerFoo implements Foo {
private Integer value;
public IntegerFoo(Integer integer) {
this.value = integer;
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
#Override
public Integer getValue() {
return value;
}
}
Here is the DisplayVisitor class visiting Foo subclasses :
public class DisplayVisitor {
void visit(ObjectFoo f) {
System.out.println("object=" + f.getValue());
}
void visit(IntegerFoo f) {
System.out.println("integer=" + f.getValue());
}
void visit(StringFoo f) {
System.out.println("string=" + f.getValue());
}
}
And here is a sample code to test the implementation :
public class OOP {
void test() {
List<Foo> foos = Arrays.asList(new StringFoo("a String"),
new StringFoo("another String"),
new IntegerFoo(1),
new ObjectFoo(new AtomicInteger(100)));
DisplayVisitor visitor = new DisplayVisitor();
for (Foo foo : foos) {
foo.accept(visitor);
}
}
public static void main(String[] args) {
OOP oop = new OOP();
oop.test();
}
}
Output :
string=a String
string=another String
integer=1
object=100
Improving the implementation
The actual implementation requires the introduction of a specific wrapper class for each buit-in type we want to wrap.
As discussed, we don't have the choice to operate a double dispatch.
But note that the repeated code in Foo subclasses could be avoided :
private Integer value; // or String or Object
#Override
public Object getValue() {
return value;
}
We could indeed introduce a abstract generic class that holds the user value and provides an accessor to :
public abstract class Foo<T> {
private T value;
public Foo(T value) {
this.value = value;
}
public abstract void accept(DisplayVisitor v);
public T getValue() {
return value;
}
}
Now Foo sublasses are lighter to declare :
public class IntegerFoo extends Foo<Integer> {
public IntegerFoo(Integer integer) {
super(integer);
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
}
public class StringFoo extends Foo<String> {
public StringFoo(String string) {
super(string);
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
}
public class ObjectFoo extends Foo<Object> {
public ObjectFoo(Object value) {
super(value);
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
}
And the test() method should be modified to declare a wildcard type (?) for the Foo type in the List<Foo> declaration.
void test() {
List<Foo<?>> foos = Arrays.asList(new StringFoo("a String object"),
new StringFoo("anoter String object"),
new IntegerFoo(1),
new ObjectFoo(new AtomicInteger(100)));
DisplayVisitor visitor = new DisplayVisitor();
for (Foo<?> foo : foos) {
foo.accept(visitor);
}
}
In fact, if really needed, we could simplify further Foo subclasses by introducing java code generation.
Declaring this subclass :
public class StringFoo extends Foo<String> {
public StringFoo(String string) {
super(string);
}
#Override
public void accept(DisplayVisitor v) {
v.visit(this);
}
}
could as simple as declaring a class and adding an annotation on:
#Foo(String.class)
public class StringFoo { }
Where Foo is a custom annotation processed at compile time.
When calling a method that is overloaded, Java picks the most restrictive type based on the type of the variable passed to the function. It does not use the type of the actual instance.
this isn't polymoprhism, you've simply overloaded a method and called it with parameter of object type
Everything in Java is an Object/object (except primitive types). You store strings and integers as objects, and then as you call the prove method they are still referred to as objects. You should have a look at the instanceof keyword. Check this link
void prove(Object o){
if (o instanceof String)
System.out.println("String");
....
}

Generic array with Polymorphism

I have created a base interface which is implemented by some objects and I also have an array of interfaces which given a string return the objects mentioned. (a bit difficult to explain, better look the code :D) Then I want to pass this to the global object through some overloaded methods (at the beginning looked super clever, but it now seems technically impossible) Could I get any closer to what I want?
interface Stats { }
public class ObjectA implements Subscriber.Stats { // MORE THINGS }
public class ObjectB implements Subscriber.Stats { // MORE THINGS }
// MORE OBJECTS
This is the second interface which transforms a String into one of the classes from above
public interface Parser<T extends Stats> {
T parse(String data);
}
Now I have an array of implementations of the this interface I want to give me different results (ObjectA, ObjectB, ObjectC ..)
private final Parser<Stats>[] parsers = new Parser[] {
new Parser() {
#Override
public Stats parse(String data) {
return new ObjectA();
}
},
new Parser() {
#Override
public Stats parse(String data) {
return new ObjectB();
}
}
};
Now comes the "clever" part where I want to make something that may not be possible.
If I loop the array of parsers and each position gives me ObjectA, ObjectB due to Polymorphism I could call an overloaded method of a class with a signature like push(ObjectA) push(ObjectB), right??... Well this obviously doesn't work but is there any strategies I could use to accomplish this?
The loop would be:
for (int i = 0; i < operations.length; i++) {
dataHolder.push(parsers[i].parse(operations[i].getResult()));
}
EDITED
The problem is the method T parse (String value) is treated as if it returns Stats and not T extends Stats therefore when I call push it says there is no push(Stats) method
If I got it correctly, your dataHolder interface looks like this:
public interface DataHolder {
void push(ObjectA a);
void push(ObjectB b);
}
In that case really your loop cannot benefit from the overloaded methods, because at cimpile time, it only knows about parsers of Stats.
To achieve your goal you need to use the visitor pattern, and update your Stats hierarchy like this:
public interface Stats {
void accept(DataHolder holder);
}
public class ObjectA implements Stats {
void accept(DataHolder holder) {
holder.push(this); // this is ObjectA, so push(ObjectA) is used
}
}
public class ObjectB implements Stats {
void accept(DataHolder holder) {
holder.push(this); // this is ObjectB, so push(ObjectB) is used
}
}
Now if you do:
new Parser<Stat>().parse(input).accept(dataHandler);
It will use the propper overloaded push method (I didn't rewrite your loop, because I'm not sure if I unerstadt it properly, bu hopefully you can apply it yourself).
Sounds reasonable to me. Just try it.
String dataToParse = "wklhbglbwbgiwegbuwegbwe";
for(Parser p : parsers){
//The definition of each parser will be called and everything works.
System.out.println(p.parse(dataToParse));
}
Also you can just:
public void push(Object obj){
System.out.println(obj.getClass().getCardionalName());
//Or anything else you want to do with it.
}

How to override a method depending on a constructor?

Okay, so I'm not sure if this question already exists because I don't know how to format it, but here's the problem: can a same method produce different result depending on a constructor? (I apologize if I'm repeating the question or if it's a stupid question.)
For example, let's say that I have an interface MyInterface with function public void foo();. Let's say we have class:
public class MyClass implements MyInterface {
public MyClass() {
// I want foo() to print "Empty constructor" with sysout.
}
public MyClass(int x) {
// I want foo() to print "Constructor with int" with sysout.
}
}
So now, if create two references MyClass mc1 = new MyClass(); and MyClass mc2 = new MyClass(5); and then call mc1.foo(); and mc2.foo();, the result should be:
Empty constructor.
Constructor with int.
I tried with new MyInterface { #Override public void foo() { ... } } inside constructors but doesn't seem to work.
Yes. Store the variable and check it in the foo method.
public class MyClass implements MyInterface {
private int x;
public MyClass() {
// I want foo() to print "Empty constructor" with sysout.
}
public MyClass(int x) {
// I want foo() to print "Constructor with int" with sysout.
this.x = x;
}
public void foo(){
if(x > 0)
System.out.println("Constructor with int");
else
System.out.println("Empty constructor");
}
}
To answer the question: Not to my knowledge. Or at least not directly, you could start to read byte code and change it during run time, make it adapt-- so again, the answer is no.
Now the weird parts are the override and depending on constructor. It is not in the scope of overriding.
A method doing different things depending on the state of the Class is not too odd. However, making the method unique of how the class was instantiated I've never heard of. That being said, here is a fairly ugly solution to it.
public class Test
{
private final boolean intConstructorUsed;
public Test () {
intConstructorUsed = false;
}
public Test (int x) {
intConstructorUsed = true;
}
public void foo () {
if (intConstructorUsed == true) {
// do this
} else {
// do that
}
}
}
The foo method isn't that weird. The weird part is that you basically have to different implementations of foo depending on which constructor, you are sure you do not want an abstract class behind, with all shared methods except for one abstract void foo () that you override? Sure the classes will almost look identical, however they are not, as they do not share their foo ().
Yes, it's what's multiple constructors are designed to allow for - variation via object creation.
public class MyClass implements MyInterface {
private final String message;
public MyClass() {
message = "Empty constructor";
}
public MyClass(int x) {
message = "Constructor with int";
}
#Override
public void foo() {
System.out.println(message);
}
}
It's even threadsafe.
The thing to note here is that the implementation of the method is exactly the same, the variation is in the constructor. And it's the constructor which is called differently depending on what the caller wants to happen.

Java Generics, why is it illegal to use inheritance in generics?

I have this structure:
///Creep.java///
public interface Creep extends Movable<Position2D> {
...
}
///Movable.java///
public interface Movable<T extends Position2D> {
...
void setMovementStrategy(MovementStrategy<Movable<T>> movementStrategy);
MovementStrategy<Movable<T>> getMovementStrategy();
}
///MovementStrategy.java///
public interface MovementStrategy<T extends Movable<? extends Position2D>> {
void executeMovement(T movable);
}
///CreepImpl.java///
public class CreepImpl implements Creep {
...
#Override
public void setMovementStrategy(MovementStrategy<Creep> movementStrategy) {
// TODO Auto-generated method stub
}
#Override
public MovementStrategy<Creep> getMovementStrategy() {
return null;
}
}
My problem is that generics doesn't like MovementStrategy<Creep> but it does accept MovementStrategy<Movable<Position2D>> Which i think is strange as Creep extends Movable<Position2D>. This in the context of the methods public MovementStrategy<Creep> getMovementStrategy() and public MovementStrategy<Creep> getMovementStrategy()
Isn't this possible? or maybe im doing something wrong?
Any help is appreciated!
EDIT
Forgot to include MovementStrategy source.. doh!
Probably you don't even need generics with MovementStrategy. Try not to create that much generics complexity.
Original answer: You can use the extends keyword: MovementStrategy<? extends Movable>
This is needed to preserve compile-time safety.
Imagine the following was possible: Creep extends Movable, Wind extends Movable
MovementStrategy<Movable> strategy = new MovementStrategy<Wind>();
strategy.setTargetObject(new Creep()); //fails
The 2nd like fails at runtime, because it expects Wind, but you give it a Creep
Take this sample code:
Movable<Position2D> moveable = new CreepImpl();
MovementStrategy<Movable<Position2D>> strategy=/*some strategy here */;
moveable.setMovementStrategy(strategy);
Since CreepImpl only accepts MovementStrategy<Creep>, the last line should fail, although it is perfectly legal, which means that CreepImpl is not a valid substitute for Moveable<Position2D>
In Java, when B extends or implements A, every Object of type B can also be assigned to a variable of type A, and B may not introduce any constraints to limit A.
Your problem is that Creep implements the interface Movable<Position2D>, and Movable<Position2D> expect the methods setMovementStrategy(MovementStrategy<Movable<Position2D>> movementStrategy) and MovementStrategy<Movable<T>> getMovementStrategy().
Look at this simple non-generic example:
public interface iTest() {
doSomething(Object o);
}
public class Test implements iTest {
#Overide
doSomething(Test t) {
//error
}
}
As you can see, doSomething(Test t) only implements a small part of the iTest interface. If somebody writes the folling code, there is no method in Test to execute it:
public class TestImpl {
public static void main(String[] args) {
iTest t = new Test();
t.doSomething("Hi"); // valid, because iTest.doSomething() expects a Object, and String is a Object.
Test t2 = new Test();
t2.doSomething("Hi"); // invalid, Test does not have a doSomething(String).
}
}
Polymorphism doesn't work for generics like for arrays for exemple.
The JVM doesn't know at runtime the type of the object, this is called type erasure and was done for retrocompatibility.
Only the compiler knows the type of an instance.
Generics were designed mostly for collections... The matter is that you must know that it IS possible to insert a String to a List, if you pass for exemple an ArrayList of integers to a method taking a List
Give a try to the following code that will surprise you:
public static void main(String[] args) {
Set<Integer> set = new HashSet<Integer>();
for ( int i=0 ; i<10 ; i++ ) {
set.add(i);
}
methode(set);
for ( Integer i : set ) {
System.out.println(i);
}
}
public static void methode(Set set) {
set.add("test");
}
It does compile, run and even give some numbers before raising an exception!
Now let's review the following code:
public static void main(String[] args) {
Set<Integer> set = new HashSet<Integer>();
for ( int i=0 ; i<10 ; i++ ) {
set.add(i);
}
methode(set); // NOK
for ( Integer i : set ) {
System.out.println(i);
}
}
public static void methode(Set<Number> set) {
set.add(3f);
}
It's almost the same here, if polymorphism was ok with generics, you could pass a set of integers to a method that takes a set of numbers, and then add a float to the set of integers!
Sun designed generics so that if you do not use legacy non typed code, your collections keep being type safe...
Like Bozho said, in my exemple you could use as argument
Set<? extends Number>
and thus it would be possible to pass a set of integers to the method.
I don't remember exactly, but in this case i think java gives you a warning on the danger of inserting a new item to that list...

Casting to Unknown Type When Class Name as a String

public class ExampleClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
Horse hr1 = new Horse();
Horse hr2 = new Horse();
Horse hr3 = new Horse();
Horse hr4 = new Horse();
Set hrSet = new HashSet();
hrSet.add(hr1);
hrSet.add(hr2);
hrSet.add(hr3);
hrSet.add(hr4);
Horse hr;
String hor = "sher_pkg.Horse";
callHorse(hrSet,hor);
}
public static void callHorse(Set xSet,String clsName){
try {
Class hrt = Class.forName(clsName);
Iterator hritr = xSet.iterator();
while(hritr.hasNext()){
exam(hrt.cast(hritr.next()));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void exam(Object obj){ //I want to use exam(Horse hrr)
System.out.println(obj);
}
}
Here the argument for the exam function is an Object. But I want to have the argument be Horse... so what changes must be done in "exam(hrt.cast(hritr.next()))" method call? I don't want to explicitly use the class name Horse in callHorse()... So what am I supposed to do?
Thanks
Note: Code with sequences of "if (x instanceof MyClass) usually indicates that you are not using polymorphism enough. Code can usually be refactored to get rid of the need to test this. But I'll ignore this for the sake of answering the question asked.
You can do what you are trying to do, but not without some code changes. Method overloading cannot do what you need because in Java, method overloading is decided at compile time. Thus, if you have two methods in a class where both methods have the same name, same return type, but different parameter types, then any code invoking this overloaded method must make explicit which one will be invoked. Your current code does this with the types it provides due to the use of explicit casts but the fully dynamic version does not. If method overloading were decided at runtime, then your code would do what you want. But because it is decided at compile time, your code does not compile.
To solve your problem, you can use generics, or you can restructure your code. First I'll introduce a test harness that shows a very simplified version of what you're starting with:
public class Test {
public void test(Object obj) {
if (obj instanceof Horse) {
Horse c = (Horse) obj;
noise(c);
}
if (obj instanceof Cow) {
Cow c = (Cow) obj;
noise(c);
}
}
public void noise(Horse h) {
System.out.println("Neigh");
}
public void noise(Cow c) {
System.out.println("Moo");
}
public static void main(String[] args) {
Object o1 = new Horse();
Object o2 = new Cow();
Test tester = new Test();
tester.test(o1);
tester.test(o2);
}
}
class Horse {}
class Cow {}
This code runs and does what you would expect. It prints "Neigh" followed by "Moo".
You are trying to replace
if (obj instanceof Horse) {
Horse c = (Horse) obj;
noise(c);
}
with
if (obj instanceof Horse) {
handleNoise(obj, Horse.class);
}
and then adding the method to handle it (simplified):
void handleNoise(Object obj, Class clazz) {
noise(clazz.cast(obj));
}
and as I said before, this doesn't work the overloading of noise is decided at compile time. The compiler sees that you are casting, but does not know at compile time what the type is. So it cannot pick an overloading and compilation fails.
The best way to solve this is by using polymorphism, because polymorphism is decided at runtime. That is, have all of those classes implement some interface and then move the code in question into the individual classes. Here is an example that does this:
public class Test {
public void test(Animal obj) {
obj.noise();
}
public static void main(String[] args) {
Animal o1 = new Horse();
Animal o2 = new Cow();
Test tester = new Test();
tester.test(o1);
tester.test(o2);
}
}
interface Animal {
void noise();
}
class Horse implements Animal {
public void noise() {
System.out.println("Neigh");
}
}
class Cow implements Animal {
public void noise() {
System.out.println("Moo");
}
}
Notice how much simpler the test method is! If you can have each item implement an interface that handles what you call stringProp below, then you can simplify part way:
if (obj instanceof Cust) {
loopOverSet(c.getCustPhonSet());
} else if (obj instanceof Name) {
loopOverSet(c.getCustNameSet());
}
// and so on for the rest...
and then add the method:
void loopOVerSet(Set cxSet) {
if (cxSet != null && cxSet.size() > 0) {
Iterator cxSetIterator = cxSet.iterator();
while (cxSetIterator.hasNext())
{
((StringProp)cxSetIterator.next()).stringProp();
}
}
}
This assumes that the previously-overloaded methods stringProp have been moved into the individual classes CustPhone and CustName and so on and that these classes all implement some interface which I've called StringProp where this interface defines the method stringProp(). Since this code is using overriding instead of overloading it will be decided at runtime.
You might want to take a look at generics.
public static void callHorse(Set<Horse> xSet) {
Iterator<Horse> hritr = xSet.iterator();
while (hritr.hasNext()) {
exam(hritr.next());
}
}
public static void exam(Horse obj) { //I want to use exam(Horse hrr)
System.out.println(obj);
}
Of course in your example you could always just cast the objects. Why you don’t want to do that is beyond me.
When you say:
exam(Horse hrr)
you're telling the compiler that you want it to check all calls to exam() and make sure that each call provides a Horse object as an argument. However, in callHorse(), you're invoking exam() with a dynamically cast argument, and the compiler has no way to check the argument.
It's possible that you could work around this by using reflection and dynamically invoking the exam() method.
You could explicitly cast in the function call -
try {
Class hrt = Class.forName(clsName);
Iterator hritr = xSet.iterator();
while(hritr.hasNext()){
exam((Horse)hrt.cast(hritr.next()));
}
}
but I'm not really sure what you're trying to achieve here - If you're writing code that explicitly references Horses, why do you need to dynamically determine the class type from a string?
First things first,your set should be using either generics or explicitly defined as only holding Horse Objects.
(final Set xSet<Horse>, final String clsName){
...}
Fix that and you have fixed 90% of the issues.
It looks like your design is wrong for Java, and you can't directly do what you are asking for.
Perhaps you need to reshape your code to use the visitor pattern? Failing that, you need to explain your requirement instead of the solution that you want to use. In that way, we can tell you the proper Java solutions to your requirement.
I'm not sure it's possible or desirable to avoid having a reference to "Horse" in the callHorse method. Judging from the printstacktrace after a ClassNotFoundException, you throw a hard error if the class is not found for some reason.
Couldn't you, for the same reason, just cast to "Horse" and then catch the classcastexception if something in the Set is not a Horse?
Can you explain why it exactly is that you need to pass in the classname instead of the class?
Maybe you can also use method overloading, but I'd have to test this, because I'm not entirely sure what the precedence is in this case.
If you are doing a dynamic cast by using Class.cast() with an argument that you're passing to another function, then at compile time nothing is known about the type that you are passing. This is why you cannot use Horse as the argument type where you define the method, but then call the method using reflection in the way that you are. Your cast does very little except verify that -- as long as you don't get an Exception -- the set you pass in is entirely comprised of members of the Class you pass in the name of.
Note that the Class.cast() method was introduced in Java 5, meaning you have access to Generics if you have access to Class.cast(). Generics can help clean things up although they won't solve the problem you are trying to solve.
Using a Java 5 for loop you can rewrite your loop as follows:
public static void callHorse(Set<?> xSet, String clsName) {
try {
Class<?> hrt = Class.forName(clsName);
for (Object x : xSet) {
exam(hrt.cast(x));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
This version is less cluttered and makes your cast more obvious. You are casting to an entirely arbitrary type. The cast may be to any type as long as the class definition can be loaded from the classpath. Thus, if your exam() method takes an argument of Horse then the compiler knows that it cannot guarantee that the call will succeed and the code fails to compile.
Even if you try overloading, it won't work. That is, if you create the methods:
public static void exam(Object obj) {
System.out.println("Object " + obj);
}
public static void exam(Horse obj) {
System.out.println("Horse " + obj);
}
the exam(Object) method will always be the one invoked. Try it.
The bottom line is that what you're trying to do cannot be done. You need to give us more information about exactly what your goal is before we can help you.
Why not write it like this? What exactly are your requirements?
public static void main(String[] args) {
Set<Horse> horses = new HashSet<Horse>();
horses.add(new Horse());
horses.add(new Horse());
horses.add(new Horse());
horses.add(new Horse());
callHorse(horses);
}
public static void callHorse(Set<Horse> horses) {
for (Horse horse : horses) {
exam(horse);
}
}
public static void exam(Horse horse) {
System.out.println(horse);
}
Depending on what you do in the exam() method, it might also make sense to make it an instance method of Horse, like this:
public static void main(String[] args) {
Set<Horse> horses = new HashSet<Horse>();
horses.add(new Horse());
horses.add(new Horse());
horses.add(new Horse());
horses.add(new Horse());
examineHorses(horses);
}
public static void examineHorses(Set<Horse> horses) {
for (Horse horse : horses) {
horse.examine();
}
}
// in Horse.java
public class Horse {
public void examine() {
System.out.println(this);
}
...
}
Is your real goal to have multiple versions of the exam() method, that take different types as parameters, and dynamically select the version needed at runtime?
You can do this explicitly with reflection. Here's an example program.
import java.lang.reflect.*;
public class Test {
public static void exam( Object o ) {
System.out.println( "Object version called" );
}
public static void exam( Test t ) {
System.out.println( "Test version called" );
}
public static void main (String[] args) {
try {
// Create an instance of Test but reference it as an Object
Object untypedTest = new Test();
// Calling exam directly will invoke the Object version
exam( untypedTest );
// But if we use reflection to select the version of exam
// that takes the desired class name, we can invoke it without
// even explicitly casting
String className = "Test";
Class[] examMethodParams = { Class.forName( className ) };
Method examMethod = Test.class.getMethod( "exam", examMethodParams );
Object[] actualParams = { untypedTest };
examMethod.invoke( null, actualParams );
} catch (Exception e) {
e.printStackTrace();
}
}
}
HI,
After searching through i found that dynamic typecast at runtime can't be performed. So what i was trying to figure out seems to be absurd.
I was trying to reduce the cyclomatic complexity of a method1. I was trying to create a method2 which contains the generalized pattern of the repetition pattern found in method1 and calling the method2 from method1 wherever necessary...
the pattern was like this in the first method..
if (obj instanceof Cust)
{
Cust c = (Cust) obj;
Set cxSet = c.getCustPhonSet();
CustPhon cx;
if (cxSet != null && cxSet.size() > 0)
{
Iterator cxSetIterator = cxSet.iterator();
while (cxSetIterator.hasNext())
{
cx = (CustPhon) cxSetIterator.next();
this.stringProp(cx);
}
}
//....pattern continues here... CustPhon is replaced by various classes like CustNam etc... Also getCustPhonSet by getCustNamSet etc...
}
so i thought of writing a generalized method for the above pattern like this::
public void dynamicIteration(Set xlSet, String clsName)
{
if (xSet != null && xSet.size() > 0)
{
try{
Class clsinstance = Class.forName(clsName);
Iterator itr = generalSet.iterator();
while(itr.hasNext())
{
this.stringProp(clsinstance.cast(itr.next()));// See this is wrong.. thats y i posted here by using a simple Horse example
}
}catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
Calling method2 from method 1
//process customer email address
Set cxSet = c.getCustPhonSet();
className = "pkg.CustPhon";
dynamicIteration(cxSet,className);
// Similarly for other patterns
By this way i must be able to reduce the cyclomatic complexity
This is what i was trying to do..
Hey i think this would solve the problem. You need to decide upon which object it is, so that u can call the corresponding operation, right???
Since we use the overriding comcepts the very functionality that s required can be achieved.
What is given by Eddie may be the most appropriate solution for this i guess?
YOu override the method in the respective classes so that on calling it goes the corressponding method.
U got it?

Categories