Consider the following program:
import java.util.List;
import java.util.ArrayList;
public class TypeTest {
public static class TypeTestA extends TypeTest {
}
public static class TypeTestB extends TypeTest {
}
public static final class Printer {
public void print(TypeTest t) {
System.out.println("T");
}
public void print(TypeTestA t) {
System.out.println("A");
}
public void print(TypeTestB t) {
System.out.println("B");
}
public <T extends TypeTest> void print(List<T> t) {
for (T tt : t) {
print(normalize(tt.getClass(), tt));
}
}
private static <T> T normalize(Class<T> clz, Object o) {
return clz.cast(o);
}
}
public static void main(String[] args) {
Printer printer = new Printer();
TypeTest t1 = new TypeTest();
printer.print(t1);
TypeTestA t2 = new TypeTestA();
printer.print(t2);
TypeTestB t3 = new TypeTestB();
printer.print(t3);
System.out.println("....................");
List<TypeTestB> tb1 = new ArrayList<TypeTestB>();
tb1.add(t3);
printer.print(tb1);
}
}
The main method now prints:
T
A
B
....................
T
What should I do to make it print the followings?
T
A
B
....................
B
I'd like to avoid writing a loop such as the following for each of the type that can be printed:
public void printTypeTestB(List<TypeTestB> t) {
for (TypeTestB tt : t) {
print(tt);
}
}
The root of your problem is that Java method overloads are resolved at compile time based on the declared type of the method argument expressions. Your program seems to be trying to use runtime dispatching to different method overloads. That simply doesn't work in Java.
The fact that you are using generics in your example is a bit of a red herring. You would have the same problem if you replaced the type parameter <T> with TypeTest.
Concider creating a visitor interface which knows about all relevant subtypes.
public class TypeTestFoo {
interface TypeTestVisitor {
void visit(TypeTestA t);
void visit(TypeTestB t);
void visit(TypeTest t);
}
interface TypeTest {
void accept(TypeTestVisitor visitor);
}
public static class TypeTestA implements TypeTest {
public void accept(TypeTestVisitor visitor) {
visitor.visit(this);
}
}
public static class TypeTestB implements TypeTest {
public void accept(TypeTestVisitor visitor) {
visitor.visit(this);
}
}
public static final class Printer implements TypeTestVisitor {
public void visit(TypeTestA t) {
System.out.println("A");
}
public void visit(TypeTestB t) {
System.out.println("B");
}
public void visit(TypeTest t) {
System.out.println("T");
}
}
public static void main(String[] args) {
Printer printer = new Printer();
TypeTest t1 = new TypeTest() {
public void accept(TypeTestVisitor visitor) {
visitor.visit(this);
}};
t1.accept(printer);
TypeTestA t2 = new TypeTestA();
t2.accept(printer);
TypeTestB t3 = new TypeTestB();
t3.accept(printer);
System.out.println("....................");
List<TypeTestB> tb1 = new ArrayList<TypeTestB>();
tb1.add(t3);
for (TypeTestB each : tb1) {
each.accept(printer);
}
}
}
This should print out what you wanted:
T
A
B
....................
B
The types are listed in the interface which allows for compile-time overloading. On the other hand, this is a single point where you have put the subtypes for which you wan't to parameterize behavior. Java is not a very dynamic language... :)
candidate for the convoluted "visitor pattern".
or simply move print() method from Printer to TypeTest
Related
I am trying to compile the code below:
class Good{
Good(){}
public void getJoke(){
System.out.println("Good joke: ...");
}
}
class Joke<T>
{
T obj;
Joke() { this.obj = new T(); }
public void getThisJoke() { this.obj.getJoke(); }
}
class GoodJoke extends Joke<Good>
{
GoodJoke(){
super();
}
}
class Main
{
public static void main (String[] args)
{
GoodJoke j = new GoodJoke();
j.getThisJoke();
}
}
But I am getting the error:
T extends Object declared in class Joke
prog.java:12: error: cannot find symbol
public T getThisJoke() { return this.obj.getJoke(); }
How can I tell Java that the generic type 'T' has a method called 'getJoke'?
Introduce an interface
interface Comedian {
void getJoke();
}
Make Good implement it
class Good implements Comedian {
//.. same
Make Joke take T as an parameter. There is no way it can instantiate it itself. Add a constraint that T must implement the interface.
class Joke<T extends Comedian>
{
T obj;
Joke(T obj) { this.obj = obj; }
public void getThisJoke() { this.obj.getJoke(); }
}
Pass Good as an argument to GoodJoke
public static void main (String[] args)
{
GoodJoke j = new GoodJoke(new Good());
Now it compiles https://ideone.com/lDhvdC
I'm new in java, I want to call method class from implemented Class with interface without know class name "ClassA", which only know Object c and I have 2 file.
File (1) CobaInterface.java
package cobainterface;
public class CobaInterface {
public static void main(String[] args) {
ImplementedClass implementedClass = new ImplementedClass();
ClassA clsA = new ClassA();
implementedClass.myMethodFromClassA(clsA);
}
}
class ClassA{
public Integer getTwo(){
return 2;
}
}
interface MyInterface {
public void myMethod();
//here interface
public void myMethodFromClassA(Object c);
}
File (2) : ImpementedClass.java
package cobainterface;
public class ImplementedClass extends CobaInterface {
public void myMethodFromClassA(Object c) {
//System.out.println(c.getTwo()); <- wrong when call method c.getTwo()
}
}
How about if I want to call method getTwo() from ClassA without know Class Name, which only know Object c from file (2) as describe in code above. Thanks for advance.
You should use generic types so the implementation knows what the object will be,
interface MyInterface<T> {
public void myMethod();
//here interface
public void myMethodFromClassA(T c);
}
The impl becomes,
package cobainterface;
public class ImplementedClass Implements MyInterface<ClassA> {
public void myMethodFromClassA(ClassA c) {
//System.out.println(c.getTwo()); <- wrong when call method c.getTwo()
}
}
All together,
class Scratch {
public static void main(String[] args) {
ImplementedClass implementedClass = new ImplementedClass();
ClassA clsA = new ClassA();
implementedClass.myMethodFromClassA(clsA);
}
}
class ImplementedClass implements MyInterface<ClassA> {
#Override
public void myMethod() {
}
#Override
public void myMethodFromClassA(ClassA c) {
System.out.println(c.getTwo());
}
}
class ClassA {
public Integer getTwo() {
return 2;
}
}
interface MyInterface<T> {
void myMethod();
void myMethodFromClassA(T c);
}
You could also do a cast
System.out.println((MyClass)c.getTwo());
but you will lose all benefit of type saftey.
I have the following need and please help me to write good and abstract class.
Different types of operations is needed based on the type
I have a abstract class,
abstract public class FileHelper{
//Template method
//This method defines a generic structure for parsing data
public void parseDataAndGenerateFile(String fileDownloadType)
{
createHeader(fileDownloadType);
generateFile();
}
//We have to write output in a excel file so this step will be same for all subclasses
public void createHeader(String fileDownloadType)
{
System.out.println('Creating HEADER in EXCEL');
}
public void generateFile(String fileDownloadType)
{
System.out.println('Output generated,writing to XLX');
}
}
public class ExcelDataParser extends FileHelper {
String fileDownloadType="";
}
public class TemplateMethodMain {
public static void main(String[] args) {
String fileDownloadType="expired";
ExcelDataParser csvDataParser=new ExcelDataParser();
csvDataParser.parseDataAndGenerateFile(fileDownloadType);
}
}
Please help me and correct me to have a good way of doing this.
If you want to use an abstract base class, you better should declare an abstract method String getDownloadType() in your abstract base class. These method must be overridden by the derived classes and the type could be fix in the derived class.
For example:
abstract public class FileHelper {
abstract String getFileDownloadType();
public void parseDataAndGenerateFile() {
createHeader();
generateFile();
}
public void createHeader() {
if ("expired".equals(getFileDownloadType())) {
} else {
}
}
public void generateFile() {
if ("expired".equals(getFileDownloadType())) {
} else {
}
}
}
public class ExcelDataParser extends FileHelper {
#Override
String getFileDownloadType() {
return "expired";
}
}
public class TemplateMethodMain {
public static void main(String[] args) {
ExcelDataParser csvDataParser = new ExcelDataParser();
csvDataParser.parseDataAndGenerateFile();
}
}
But if you don't need a class for every type, you also could make the type a variable inside a single class and passing the type to the contructor
For example:
public class CsvFileHelper {
private final String fileDownloadType;
public CsvFileHelper(String type) {
fileDownloadType = type;
}
public void parseDataAndGenerateFile() {
createHeader();
generateFile();
}
public void createHeader() {
if ("expired".equals(fileDownloadType)) {
} else {
}
}
public void generateFile() {
if ("expired".equals(fileDownloadType)) {
} else {
}
}
}
public class TemplateMethodMain {
public static void main(String[] args) {
CsvFileHelper csvDataParser = new CsvFileHelper("expired");
csvDataParser.parseDataAndGenerateFile();
}
}
Please help resolve an issue regarding generics. I tried many ways but it's still not working.
Problem is:
public static void main(String[] args) {
Utils.execute(new TestAction(), new TestCallBack());
}
Compiler show error:
The method execute(Action<?>, CallBack<?,Action<?>>) in the type Utils is not applicable for the arguments (ImplementClass.TestAction, ImplementClass.TestCallBack)
My classes is:
Action class:
public abstract class Action<R> {
public R getResult() {
return null;
}
}
TestAction class is:
class TestAction extends Action<String> {
#Override
public String getResult() {
return super.getResult();
}
}
Callback class is:
public interface CallBack<R, A extends Action<R>> {
public void onCall(A action);}
TestCallback class is:
class TestCallBack implements CallBack<String, TestAction> {
#Override
public void onCall(TestAction action) {
}
}
And Utils class is:
public class Utils {
public static void execute(Action<?> action, CallBack<?, Action<?>> callback) {
}
}
Thanks a lot.
The second parameter of the execute method is CallBack<?, Action<?>>, and Action there means the Action class itself, subclass of it is not allowed. What you need there is - ? extends Action<?>, which means either Action or some subclass of it.
Try changing the method signature -
public static void execute(Action<?> action, CallBack<?, ? extends Action<?>> callback) {
Note:
Generics are not co-variant. Take for example a method as follows -
static void method(List<Object> l) {}
And an invocation as follows is not allowed -
method(new ArrayList<String>());
You need to change two things,
TestCallBack should be like this -
public static class TestCallBack implements CallBack<String, Action<String>> {
#Override
public void onCall(Action<String> action) {
}
}
and, Utils should be like this -
public static class Utils {
// You need to ensure the same type, not just try and accept anything.
public static <T> void execute(Action<T> action, CallBack<?, Action<T>> callback) {
}
}
or using inner classes of a class called Question -
public abstract class Action<R> {
public R getResult() {
return null;
}
}
public class TestAction extends Action<String> {
#Override
public String getResult() {
return super.getResult();
}
}
public interface CallBack<R, A extends Action<R>> {
public void onCall(A action);
}
public class TestCallBack implements CallBack<String, TestAction> {
#Override
public void onCall(TestAction action) {
}
}
public class Utils {
public void execute(Action<?> action, CallBack<?, ? extends Action<?>> callback) {
}
}
public static void main(String[] args) {
Question question = new Question();
question.new Utils().execute(question.new TestAction(), question.new TestCallBack());
}
Code base is littered with code like this:
BaseRecord record = // some BaseRecord
switch(record.source()) {
case FOO:
return process((FooRecord)record);
case BAR:
return process((BarRecord)record);
case QUUX:
return process((QuuxRecord)record);
.
. // ~25 more cases
.
}
and then
private SomeClass process(BarRecord record) { }
private SomeClass process(FooRecord record) { }
private SomeClass process(QuuxRecord record) { }
It makes me terribly sad. Then, every time a new class is derived from BaseRecord, we have to chase all over our code base updating these case statements and adding new process methods. This kind of logic is repeated everywhere, I think too many to add a method for each and override in the classes. How can I improve this?
First solution: good old polymorphism.
Simply add an abstract process() method to the BaseRecord class, and override it in every subclass. The code will thus become:
BaseRecord record = ...;
record.process();
If you can't add the process() method into the BaseRecord class (and its subclasses), then implement the visitor pattern. It will leave the process method outside of the BaseRecord class, but each time you add a new subclass, you'll be forced to modify the Visitor interface, and all its implementations. The compiler will thus check for you that you haven't forgotten a case somwhere in a switch.
public interface RecordVisitor<T> {
T visitFoo(FooRecord foo);
T visitBar(BarRecord foo);
...
}
public abstract class BaseRecord {
public abstract <T> T accept(RecordVisitor<T> visitor);
}
public class FooRecord extends BaseRecord {
#Override
public <T> T accept(RecordVisitor<T> visitor) {
return visitor.visitFoo(this);
}
}
public class BarRecord extends BaseRecord {
#Override
public <T> T accept(RecordVisitor<T> visitor) {
return visitor.visitBar(this);
}
}
Now you simply have to implement RecordVisitor for each block of logic described in the question:
RecordVisitor<Void> visitor = new ProcessRecordVisitor();
record.accept(visitor);
Both Visitor Pattern and Strategy pattern can be put in use here. http://en.wikipedia.org/wiki/Strategy_pattern and http://en.wikipedia.org/wiki/Visitor_pattern
I think this is instructive:
package classplay;
public class ClassPlay
{
public void say(String msg) { System.out.println(msg); }
public static void main(String[] args)
{
ClassPlay cp = new ClassPlay();
cp.go();
}
public void go()
{
A someClass = new C();
say("calling process with double dispatch");
someClass.dueProcess(this);
say("now calling process directly");
process(someClass);
}
public void process(A a)
{
say("processing A");
a.id();
}
public void process(B b)
{
say("processing B");
b.id();
}
public void process(C c)
{
say("processing C");
c.id();
}
abstract class A
{
abstract public void id(); // { System.out.println("Class A"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
class B extends A
{
public void id() { System.out.println("Class B"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
class C extends A
{
public void id() { System.out.println("class C"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
}