I am not familiar with "Generics". Is it a correct use of "<T extends SuperClass>" ? And do you agree that the codes after using generics are better?
Before using Generics
=================================================
public abstract class SuperSample {
public void getSomething(boolean isProcessA) {
doProcessX();
if(isProcessA){
doProcessY(new SubASample());
}else{
doProcessY(new SubBSample());
}
}
protected abstract void doProcessX();
protected void doProcessY(SubASample subASample) {
// Nothing to do
}
protected void doProcessY(SubBSample subBSample) {
// Nothing to do
}
}
public class SubASample extends SuperSample {
#Override
protected void doProcessX() {
System.out.println("doProcessX in SubASample");
}
#Override
protected void doProcessY(SubASample subASample) {
System.out.println("doProcessY in SubASample");
}
}
public class Sample {
public static void main(String[] args) {
SubASample subASample = new SubASample();
subASample.getSomething(true);
}
}
After using Generics
=================================================
public abstract class SuperSample {
public void getSomething(boolean isProcessA) {
doProcessX();
if(isProcessA){
doProcessY(new SubASample());
}else{
doProcessY(new SubBSample());
}
}
protected abstract void doProcessX();
protected abstract <T extends SuperSample> void doProcessY(T subSample);
}
public class SubASample extends SuperSample {
#Override
protected void doProcessX() {
System.out.println("doProcessX in SubASample");
}
#Override
protected <T extends SuperSample> void doProcessY(T subSample) {
System.out.println("doProcessY in SubASample");
}
}
public class Sample {
public static void main(String[] args) {
SubASample subASample = new SubASample();
subASample.getSomething(true);
}
}
If you want to do what I think you want to do, I don't think that this is the right way (*). If you want that every subclass needs to implement a method that processes it's own type, then you can use the CRTP trick:
abstract class Super<S extends Super<S>> {
abstract void process(S s);
}
class SubA extends Super<SubA> {
void process(SubA s){ /* do something */ }
}
class SubB extends Super<SubB> {
void process(SubB s){ /* do something */ }
}
Note that this pattern enforces the generic signature of the subclasses, e.g. class SubA extends Super<SubB> wouldn't compile.
Java itself uses that trick in java.lang.Enum, by the way.
(*)If this is not the behavior you want to enforce, please clarify.
it's correct to use . It means that you restrict type T to be subclass of SuperSample. And for second answer, yes I think code with generecis is better because it keeps you from wrong casting of classes for example with containers (List ...). But in fact generics in Java are only syntax suger and so they are erased during runtime.
Related
public abstract class CommonClass {
abstract void send(<what should i put here???>) {}
}
public class ClassA extends CommonClass {
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass {
void send(List<Post> postList) {
// do stuff
}
}
I am new to OODP, I am trying to have a method that is able to take in any kind of List data so that I can abstract things out. How can i do this?
You could make it generic on some type T. Like,
public abstract class CommonClass<T> {
abstract void send(List<T> al);
}
And then, to implement it - use the generic. Like,
public class ClassA extends CommonClass<Comments> {
#Override
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
Also, as discussed in the comments, your class names could be improved to be more intuitive; something like,
public abstract class AbstractSender<T> {
abstract void send(List<T> al);
}
and then
public class CommentSender extends AbstractSender<Comment> {
#Override
void send(List<Comment> commentsList) {
// do stuff
}
}
public class PostSender extends AbstractSender<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
That has the advantage(s) of being more readable and easier to reason about (I can tell what a PostSender does by reading the name, ClassB not so much).
Finally, this looks like a case where an interface would work since your abstract class is purely virtual (and should be preferred since you can implement multiple interface, but can only extend from a single parent class);
public interface ISender<T> {
void send(List<T> al);
}
public class CommentSender implements ISender<Comment> {
#Override
void send(List<Comment> commentsList) {
// do stuff
}
}
public class PostSender implements ISender<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
In order to achieve this, you can take multiple approaches, I would suggest looking into Generics: https://docs.oracle.com/javase/tutorial/java/generics/index.html
With that said, there is one approach that is the most elegant and simple: you can supply a List<T> where T is a generic type.
public abstract class CommonClass<T> {
abstract void send(List<T>) {}
}
public class ClassA extends CommonClass<Comment> {
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass<Post> {
void send(List<Post> postList) {
// do stuff
}
}
You can do that with the help of generics. https://www.tutorialspoint.com/java/java_generics.htm
Example
The abstract class
public abstract class CommonClass {
public abstract <T> void send(List<T> data);
}
Its child
public class Child extends CommonClass {
public <T> void send(List<T> data) {
// code here
}
}
Retrieving the list's contents
Retrieving the generified list's contents is similar to retrieving any list's contents. In the scope of the method, "T" is a type of object contained in the list.
for (T t : data) {
// to check if t is a string
if (t instanceof String) {
// code
}
}
You can also use lambdas to retrieve every element in the list.
I have the following situation:
abstract class Base {
int data = 0;
void baseMethod() {
System.out.println("baseMethod:" + data);
}
}
class DerivedA extends Base {
void DerivedBMethodA() {
}
void usefulMethod(Something something) {
something.doSomething(this);
}
interface Something {
void doSomething(DerivedA deriv);
}
}
class DerivedB extends Base {
void DerivedMethodB() {
}
}
public class Temp {
public static void main() {
DerivedA a = new DerivedA();
a.usefulMethod(new DerivedA.Something() {
#Override
public void doSomething(DerivedA deriv) {
deriv.DerivedBMethodA();
}
});
}
}
I want to push usefulMethod and Something upto the Base class so that DerivedB can leverage it. And I want implementations of Something.doSomething to be able to use a derived type, so that it can access derived functionality.
How do I do that?
Attempts
I've tried the following:
abstract class Base {
int data = 0;
void baseMethod() {
System.out.println("baseMethod:" + data);
}
void usefulMethod(Something something) {
something.doSomething(this);
}
interface Something {
void doSomething(Base deriv);
}
}
class DerivedA extends Base {
void DerivedBMethodA() {
}
}
class DerivedB extends Base {
void DerivedMethodB() {
}
}
public class Temp {
public static void main() {
DerivedA a = new DerivedA();
a.usefulMethod(new Base.Something() {
#Override
public void doSomething(DerivedA deriv) {
deriv.DerivedBMethodA();
}
});
}
}
but that fails as my anonymous Something doesn't implement doSomething(Base). So trying to use generics:
I tried:
interface Something {
void doSomething(<? extends Base> deriv);
}
but that won't compile due to: "Wildcards may be used only as reference parameters"
I tried:
interface Something {
<T extends Base> void doSomething(T deriv);
}
but that requires me to implement the interface as so:
a.usefulMethod(new Base.Something() {
#Override
public <T extends Base> void doSomething(T deriv) {
}
});
which obviously doesn't allow me access to the derived type?
There are ways I can make it "work" but they're undesirable:
This:
interface Something {
void doSomething(Base deriv);
}
a.usefulMethod(new Base.Something() {
#Override
public void doSomething(Base deriv) {
DerivedA a1 = (DerivedA) deriv;
a1.DerivedBMethodA();
}
});
But that requires me to cast in each implementation, which seems wasteful.
And this:
package com.miurasample.ui.info;
abstract class Base {
int data = 0;
void baseMethod() {
System.out.println("baseMethod:" + data);
}
void usefulMethod(Something something) {
something.doSomething(this);
}
interface Something<T extends Base> {
void doSomething(T deriv);
}
}
public class Temp {
public static void main() {
DerivedA a = new DerivedA();
a.usefulMethod(new Base.Something<DerivedA>() {
#Override
public void doSomething(DerivedA deriv) {
}
});
}
}
but that results in a warning/IDE highlight in usefulMethod of:
"Unchecked call to doSomething(T) as a member of raw type Base.Something"
What's the tersest and "cleanest" way to do this? Is that I'm doing even sane?
It is difficult to say if your design is wrong or not. We dont have full scope of your requirements to assert that, but here is clean non cast approach to what you are trying to do. It does require extra method in your derived classes:
public static void main(String... args) {
DerivedA a = new DerivedA();
a.usefulMethod( new Base.Something<DerivedA>() {
#Override
public void doSomething(DerivedA deriv) {
deriv.DerivedBMethodA();
}
} );
}
public abstract static class Base< T extends Base<T> > {
int data = 0;
protected abstract T getThis();
void baseMethod() {
System.out.println("baseMethod:" + data);
}
void usefulMethod(Something<T> something) {
something.doSomething( getThis() );
}
interface Something< T extends Base<T> > {
void doSomething(T deriv);
}
}
public static class DerivedA extends Base<DerivedA> {
protected DerivedA getThis(){
return this;
}
void DerivedBMethodA() {}
}
public static class DerivedB extends Base<DerivedB> {
protected DerivedB getThis(){
return this;
}
void DerivedMethodB() {}
}
I've been wondering about the getThis() trick, and the alternative of the unsafe cast from a self-bounded type to its type parameter.
public abstract class SelfBound<T extends SelfBound<T>> {
protected abstract T getThis();
public void doSomething(T instance) { ... }
public final void doSomethingWithThis() { doSomething(getThis()); }
public final void doSomethingWithThisUnsafe() { doSomething((T) this); }
}
Is it possible to subclass SelfBound such that doSomethingWithThisUnsafe() throws a ClassCastException? (Is it possible to do this without subclassing SelfBound?)
Surely it's possible to have ClassCastException with subclassing. Here's a simple example:
public abstract class SelfBound<T extends SelfBound<T>> {
protected abstract T getThis();
public void doSomething(T instance) { }
public final void doSomethingWithThis() { doSomething(getThis()); }
public final void doSomethingWithThisUnsafe() { doSomething((T) this); }
public static class A extends SelfBound<A> {
#Override
protected A getThis() {
return this;
}
}
public static class B extends SelfBound<A> {
#Override
public void doSomething(A instance) {
super.doSomething(instance);
}
#Override
protected A getThis() {
return null;
}
}
public static void main(String[] args) {
new B().doSomethingWithThisUnsafe();
}
}
Output:
Exception in thread "main" java.lang.ClassCastException: SelfBound$B cannot be cast to SelfBound$A
at SelfBound$B.doSomething(SelfBound.java:1)
at SelfBound.doSomethingWithThisUnsafe(SelfBound.java:6)
at SelfBound.main(SelfBound.java:28)
It's not so clear what do you mean by "without subclassing SelfBound". As SelfBound is an abstract class, you cannot call its methods without subclassing it, thus you cannot have any exception when calling its methods.
I created something like below:
ConcreteObserver1 is the subclass of IObserver
Interfaces definitions:
public interface ISubject<T,O extends IObserver<T>> {
public void addObserver(O observer);
public void removeObserver(O observer);
public void updateAllSubjects(T value);
}
public interface IObserver<T> {
public void update(T value);
}
public class ConcreteObserver1<T> implements IObserver<T> {
Concrete Subject class containing IObserver
public class ConcreteSubject<T, O extends IObserver<T>> implements
ISubject<T,O> {
public ConcreteSubject() {
addObserver(new ConcreteObserver1<T>());
}
ConcurrentSkipListSet<O> observersList = new ConcurrentSkipListSet<O>();
public void addObserver(O observer) {
observersList.add(observer);
addObserver(new ConcreteObserver1<T>()); not working.
It complains as below
The method addObserver(O) in the type ConcreteSubject is not applicable for the arguments (ConcreteObserver1)
Why ?
I told O extends IObserver<T> in ConcreteSubject type parameter definition, which says O is a sub-type of IObserver which is ConcreteObserver1
Why it is complaining.
The type parameter O is defined to be a subtype of IObserver<T>, this is correct. But it may stand for any subtype. You don't say anywhere that it stands for ConcreteObserver1. It could also stand for ConcreteObserver42 or something else.
From what you posted so far, it does not seem like you really have to define O as a type parameter of ConcreteSubject. You could specifically say that ConcreteSubject always uses a ConcreteObserver1. If this is not the case, you should probably explain your intention more clearly (and possibly, in a more readable form).
(Edited based on the comments)
interface ISubject<T,O extends IObserver<T>>
{
void addObserver(O observer);
void removeObserver(O observer);
void updateAllSubjects(T value);
}
interface IObserver<T>
{
void update(T value);
}
class ConcreteObserver1<T> implements IObserver<T>
{
#Override
public void update(T value) {}
}
class ConcreteObserver2<T> implements IObserver<T>
{
#Override
public void update(T value) {}
}
class ConcreteObserver3<T> implements IObserver<T>
{
#Override
public void update(T value) {}
}
class ConcreteSubject<T> implements ISubject<T,IObserver<T>>
{
ConcurrentSkipListSet<IObserver<T>> observersList =
new ConcurrentSkipListSet<IObserver<T>>();
public ConcreteSubject()
{
addObserver(new ConcreteObserver1<T>());
addObserver(new ConcreteObserver2<T>());
addObserver(new ConcreteObserver3<T>());
}
#Override
public void addObserver(IObserver<T> observer)
{
observersList.add(observer);
}
#Override
public void removeObserver(IObserver<T> observer)
{
observersList.remove(observer);
}
#Override
public void updateAllSubjects(T value)
{
for (IObserver<T> observer : observersList)
{
observer.update(value);
}
}
}
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());
}