I'm trying to study the difference between deep copy and shallow copy in Java. I created an example where I use a generic class OrganizedGroup to manage Enterprizes,Music groups and others. Then, I create a container with different groups of type OrganizedGroup.
import java.util.ArrayList;
interface Leader {
public void command();
}
class Singer implements Leader {
#Override
public void command() {
System.out.println("I'm a singer");
}
}
class Boss implements Leader {
#Override
public void command() {
System.out.println("I'm a boss");
}
}
class OrganizedGroup<T extends Leader> {
private T mandador;
public OrganizedGroup(T m) {
mandador = m;
}
public void posturaOficial() {
mandador.command();
}
public void setLeader(T m){
mandador = m;
}
}
class MusicGroup extends OrganizedGroup<Singer> {
public MusicGroup(Singer c) {
super(c);
}
public void playMusica() {
System.out.println("Playing music....");
}
}
class Enterprize extends OrganizedGroup<Boss> {
public Enterprize(Boss j) {
super(j);
}
public void makeDeal() {
System.out.println("Making a deal....");
}
}
public class Pruebas {
public static void main(String[] args) {
ArrayList<OrganizedGroup<? extends Leader>> go = new ArrayList();
OrganizedGroup<? extends Leader> g = new MusicGroup(new Singer());
go.add(g);
g = new Enterprize(new Boss());
go.add(g);
for (OrganizedGroup j : go) {
j.posturaOficial();
}
OrganizedGroup< ? extends Leader> t = go.get(0);
t.setLeader(new Singer()); //compile error
}
}
On the last line I try to modify the leader of the first group ( I need to do that in order to see the difference between shallow copy and deep copy (say I cloned go into go2)) however it gives the following compile error:
Singer cannot be converted to CAP#1 where CAP#1 is a fresh
type-variable: CAP#1 extends Leader from capture of ? extends Leader
I need answer to solve this problem, not an explanation of the compile error but more importantly of what is conceptually wrong, what should be change and why.
Please,don't focus on bad design matters I actually made a different implementation of this (OrganizedGroup being abstract) but I need to solve this problem to practise with generics.
There is no need to write:
OrganizedGroup< ? extends Leader> t = go.get(0);
Instead I wrote just:
OrganizedGroup t = go.get(0)
and the same can be done in all main's sentences. No compile error.
Related
I have two classes A and B and they both have a common field in them, and I want to create a function in which if I pass Class A object then I want to set that common field value to the passed value and if I pass Class B object then I want to set that common field value to the passed value. Can anyone please tell me how can I do this, I am new to Java Generic Classes.
Otherwise I would have to make two different functions OR I would have to make an if and else which would decide that passed object belongs to which class ??
Class A
public class A{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class B
public class B{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class D
public class D{
public void change_footer(T generic_param, int value) {
generic_param.setFooter(value);
}
}
Class HelloWorld
public class HelloWorld{
public static void main(String []args){
Here I want to call
A a = new A();
new D().change_footer(a, 5);
B b = new B();
new D().change_footer(b, 5)
}
}
Thank You
And if I got all of the question wrong, and nor A nor B are generic, AND the type of field is fixed.
then you mean something like:
class D {
/*public <T extends Super> would be muuuch nicer here as well!*/
public /*static*/ <T> void change_footer(T obj, int data) {
//otherwise, you could just cast to Super...and set dat field.
if (obj instanceof A) {
((A) obj).setField(data);
} else if (obj instanceof B) {
((B) obj).setField(data);
} // else ... ?
}
}
Original answer:
Easy peasy (the "straight forward" implementation produces the desired results.):
class A<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
class B<T> extends A {//empty
}
class Test {
public static void main(String... args) {
B<Object> testB1 = new B<>(); //
testB1.setField(new Object());
System.out.println(testB1.getField());
B<String> testB2 = new B<>();
testB2.setField("blah blah");
System.out.println(testB2.getField());
B<Integer> testB3 = new B<>();
testB3.setField(42);
System.out.println(testB3.getField());
}
}
System.out:
java.lang.Object#6d06d69c
blah blah
42
It get's (little) more complicated, when you want to instantiate Ts ...but still possible/other question. :)
Edit to your comment:
If there's only one common field, then why not:
/*abstract */class Super<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
? ...and:
class A<T> extends Super { ... }
class B<T> extends Super { ... }
Currently have an issue getting a specific object in an arraylist. So I have multiple classes that implements the same interface, and I create objects of the different classes. The problem is that I don't know how to differentiate the classes in the arraylist.
ArrayList<Interface> arraylist = new ArrayList<>();
public static void main(String[] args) {
addInterface(new interfaceA());
addInterface(new interfaceB());
addInterface(new interfaceC());
}
public static void addInterface(Interface foo) {
arraylist.add(foo);
}
Let say that I want to get interfaceA(), I could call it by arraylist.get(0) but I don't want to hardcode it. Each class has the same methods but the code is different.
I would use a Map instead of a List. In this case an IdentityHashMap is a good fit.
interface Thing {
}
IdentityHashMap<Class<? extends Thing>, Thing> things = new IdentityHashMap<>();
class ThingA implements Thing {
#Override
public String toString() {
return "ThingA{}";
}
}
class ThingB implements Thing {
#Override
public String toString() {
return "ThingB{}";
}
}
class ThingC implements Thing {
#Override
public String toString() {
return "ThingC{}";
}
}
public void registerThing(Thing thing) {
things.put(thing.getClass(), thing);
}
public void test(String[] args) {
registerThing(new ThingA());
registerThing(new ThingB());
registerThing(new ThingC());
System.out.println(things.get(ThingB.class));
}
You could filter using a predicate, by checking runtime classes:
List<Interface> interfaceAList = arraylist.stream()
.filter(e -> InterfaceA.class.isInstance(e))
.collect(Collectors.toList());
public Interface getInterfaceA(List<Interface> interfaces) {
for (Interface i : interfaces) {
if (i instanceof InterfaceA)
return i;
}
return null;
}
I've been banging my head on this problem for the last few days and searching everything I could think of to no avail.
I have a class interacting with another through an interface. I'm getting some type mismatch errors with code that seems simple enough to me.
public class FooBar {
Foo<? extends Bar> X = new Y();
public void test(){
if X.isA(X.B()){
//do something; type mismatch here
}
}
}
Interface:
public interface Foo<T extends Bar> {
public T B();
public boolean isA(T t);
}
Implementation:
public class Y implements Foo<T extends Bar> {
public int B(){
return 5;
}
public boolean isA(int num){
int A = 10;
return (A == num) ? true : false;
}
My point of issue is the method test(). I'm getting a number through the interface, then testing it with the same instance of the implementation class, but this is giving me a capture/type mismatch error.
CAP#1 extends Bar from capture of ? extends Bar
CAP#2 extends Bar from capture of ? extends Bar
I've tried a number of things that I've found in my searches, but none of them have worked. Generics and interfaces are new to me and I'm still learning them. Thank you for any help in advance!
I have updated your classes (and added the missing Bar class for clarity).
You can now run the FooBar.main() method and get the results you expect:
public class FooBar {
Foo x = new Y();
public void test(){
if(x.isA(x.B())){
System.out.println("x.isA!");
}
}
public static void main(String... args){
FooBar fb = new FooBar();
fb.test();
}
}
public interface Foo<T extends Bar> {
T B();
boolean isA(T t);
}
public class Bar {}
public class ExtendsBar extends Bar {
#Override
public String toString(){
return "Yes I extend Bar";
}
}
public class Y implements Foo<ExtendsBar> {
public ExtendsBar B() {
return new ExtendsBar();
}
public boolean isA(ExtendsBar num) {
return (num instanceof Bar);
}
}
I'm java virgin. I've made really simple code like below.
class TreeData implements Comparable<TreeData> {
private String sixString;
private ArrayList<Integer> stringNum = new ArrayList<Integer>();
private ArrayList<Integer> charNum = new ArrayList<Integer>();
public TreeData(String sixString, int stringNum, int charNum){
this.sixString = sixString;
(this.stringNum).add(stringNum);
(this.charNum).add(charNum);
}
public int compareTo(TreeData other) {
return sixString.compareTo(other.getSixString());
}
public String getSixString(){
return sixString;
}
}
class Child<T extends Comparable<T>>{
public void print(T data){
//error : String a = data.getSixString();
System.out.println("hi");
}
}
public class Test {
public static void main(String[] args) {
Child<TreeData> child = new Child<TreeData>();
TreeData td = new TreeData("sixString", 8, 2);
child.print(td);
}
}
I had a problem in 'print' method in the Child class. When I tried calling the getSixString() method of data(passed as argument), it occurs error. I don't know why I can't using public method in the argument 'data'. Is it related with Generic? Thanks, in advance.
In your Child class, you only define T to be extending Comparable. Yet you expect it to have the method getSixString which Comparable doesn't have. What you probably want it for it to be extending TreeData:
class Child<T extends TreeData>{
public void print(T data){
String a = data.getSixString();
//should work now since T defines getSixString()
}
}
Or better yet if all you want is for T to be TreeData, you don't need any generic class. I'm assuming your real intention was:
class Child extends TreeData {
public void print(){
String a = getSixString();
}
}
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.