I have following two classes:
public Class A{
String name;
Integer age;
//setters and getters
}
And
public Class B{
String name;
Integer age;
Integer height;
//setters and getters
}
and following method
public String getMyName(B b){
return b.getName()+" "+b.getAge()+" "+b.getHeight();
}
Is it possible to refactor this method to use generics which will allow me to call it for objects of those two different classes?
E.g
public <T> String getMyName(T t){
return t.getName()+" "+t.getAge()+( t instanceof B ? " "+t.getHeight() : "");
}
Of course it doesn't work since t doesn't know methods getName, getAge and getHeight.
Classes are not in any relation( I know that they can inherit from one common class and use <T extends C> but they don't have superclass or common interface)
No, without using a common interface or superclass this is not possible with generics. You could use reflection but I'd advice against that and suggest providing a common interface instead.
As others said, there would be other ways to handle that case (e.g. method overloading or passing Object and using instanceof and casts) but if you can use a common interface, I'd still go that way.
Note that Java generics are unlinke C++ generics/templates which would allow what you want to do - and there are good reasons for that difference.
This is the place where people shout the line Programming with interfaces.
Take a an interface and add common methods to it and create a generic method which takes that interface as a argument.
That makes your life easy.
You can use instanceof to check whether is compatible type and if it is, cast object to your type and call methods. It is not elegant way, but still. So this way, you can use your method as generic. :)
You can dynamically adapt them on the fly - something like:
public class A {
String name;
Integer age;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
public class B {
String name;
Integer age;
Integer height;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Integer getHeight() {
return height;
}
}
// Create a common interface.
public interface AorB {
public String getName();
public Integer getAge();
// Use Java 8 to implant a default getHeight if it is missing.
default Integer getHeight() {
return 0;
}
}
// Dynamicaly adapt each type.
public String getMyName(A a) {
// Adapt it on the fly.
return getMyName(new AorB() {
#Override
public String getName() {
return a.getName();
}
#Override
public Integer getAge() {
return a.getAge();
}
});
}
public String getMyName(B b) {
// Adapt it on the fly.
return getMyName(new AorB() {
#Override
public String getName() {
return b.getName();
}
#Override
public Integer getAge() {
return b.getAge();
}
#Override
public Integer getHeight() {
return b.getHeight();
}
});
}
// Your method almost untouched.
public String getMyName(AorB ab) {
return ab.getName() + " " + ab.getAge() + " " + ab.getHeight();
}
public void test() {
A a = new A();
a.name = "A";
a.age = 10;
B b = new B();
b.name = "B";
b.age = 10;
b.height = 12;
System.out.println("A:" + getMyName(a));
System.out.println("B:" + getMyName(b));
}
I am using Java-8 default here to implement a default getHeight but it would not take much effort to eliminate that - you would need to implement a getHeight for the getMyName(A) method.
Sadly - of course - this is not using generics in the solution so you may see this as not an answer to your question but it is an alternate solution to your problem so I chose to post.
Related
I want to have Classes extending a Superclass where only the Variables differ, the Methods stay the same. This is for an example of a Decorator Pattern. The Superclass implements an Interface, which forces the Methods to be overridden, but the Methods require variables that should be changed. The Code is the Following:
interface wearable{
int getItemColdResistance();
String getItemName();
}
abstract class BaseWearable implements wearable{
boolean addsColdResistance = true; //This is just because I need an Example of a Base-Decorator
}
class Underwear extends BaseWearable{
String name = "Underwear";
int itemColdResistance = 1;
#Override
public String getItemName() {
return name;
}
#Override
public int getItemColdResistance() {
return itemColdResistance;
}
}
class Shirt extends BaseWearable{
String name = "Shirt";
int itemColdResistance = 2;
#Override
public String getItemName() {
return name;
}
#Override
public int getItemColdResistance() {
return itemColdResistance;
}
}
So the Variables name and itemCodeResistance differ and must be defined in each Subclass, but the Methods stay exactly the same. How can I write general Methods in the Superclass and change the Variables needed in those Methods in the Subclasses? Is that even possible?
Looks like you want something like that:
interface Wearable{
int getItemColdResistance();
String getItemName();
}
abstract class BaseWearable implements Wearable{
boolean addsColdResistance = true; //This is just because I need an Example of a Base-Decorator
private String name;
private int itemColdResistance;
BaseWearable(String name, int itemColdResistance) {
this.name=name;
this.itemColdResistance = itemColdResistance;
}
#Override
public String getItemName() {
return name;
}
#Override
public int getItemColdResistance() {
return itemColdResistance;
}
}
class Underwear extends BaseWearable{
Underwear() {
super("Underwear",1);
}
}
class Shirt extends BaseWearable{
Shirt() {
super("Underwear",2);
}
}
BTW: The interface name should start with uppercase character
No it is not possible.
But it is not at all clear why you need different variables and don't just set the variables to different values.
There is no way.
Neither should there be. The variables are not part of the visible interface. (Or rather: Should never be.)
I'm just wondering if there is any way to create two classes that aren't related but have the same implementation of method. I know there are interfaces and static methods but it seems like they are good only when you have static field in class. Is this possible to do that kind of thing when method uses field that is specific to exact object?
I know it's a bad practice writing code like this but I'm just curious.
EDIT:
I mean something like this:
public class Person implements MakingOlder {
private int age;
}
public class Cat implements MakingOlder {
private int age;
}
public interface MakingOlder {
public static void makeOlder() {
this.age += 2;
}
}
I don't want to make common base class for Person and Cat and interface is not working. I'm trying to avoid writing the same implementation twice and copying the code.
Sure, it's called "composition + delegation", and it's often a good practice to replace inheritance by this :
https://en.wikipedia.org/wiki/Composition_over_inheritance
public class Person implements AgingObject {
private int age;
private AgingBehavior agingBehavior;
void makeOlder() {
agingBehavior.makeOlder(this);
}
//(...)
}
public class Cat implements AgingObject {
private int age;
private AgingBehavior agingBehavior;
void makeOlder() {
agingBehavior.makeOlder(this);
}
//(...)
}
public class AgingBehavior {
void makeOlder(AgingObject agingObject) {
agingObject.setAge(agingObject.getAge() + 2);
}
}
public interface AgingObject {
int getAge();
void setAge(int age);
}
...or you can use default implementation in Java 8+...
public interface MakingOlder {
public default void makeOlder() {
setAge(getAge() + 2);
}
int getAge();
void setAge(int age);
}
and of course your Person and Cat implements MakingOlder...
Probably your interface is not working because you are trying to implement a method within the interface:
public static void makeOlder() {
this.age += 2;
}
In order to make it work, try to add the default keyword so that it looks like:
default Integer makeOlder(Integer age) {
age += 2;
return age;
}
Then the class, which implements that interface, will just need to contain something like:
public class Dummy implements AA {
Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
To test the result you can call something like:
Dummy d = new Dummy();
d.setAge(d.makeOlder(7));
System.out.println(d.getAge());
d.setAge(d.makeOlder(d.getAge()));
System.out.println(d.getAge());
I have a case where all instances of subclasses should return the same value.
Since there will be a lot of instances I want to reduce the amount of memory the use.
I made the following experiment:
1) Using fields and implementing the methods once. (This implementation uses 24 bytes)
private abstract class A{
private String string;
private int i;
public A(String string, int i) {
this.string = string;
this.i = i;
}
public String getName() {
return string;
}
public int getAge() {
return i;
}
}
private class B extends A{
public B() {
super("B",10);
}
}
2) Reimplementing methods for each class. (This implementation uses 16 bytes)
private abstract class A{
public abstract String getName();
public abstract int getAge();
}
private class B extends A{
#Override
public String getName() {
return "B";
}
#Override
public int getAge() {
return 10;
}
}
I read the object size using VisualVm.
Does anyone see a way I could implement the methods only once while reducing the amount of memory used?
Thank you in advance.
EDIT:
Since my question got downvoted a few times please let me know how I can improve it.
It is more subtle. In fact you want to have every child class to have its specific class (static) constant. A non-static method is used for that, as Java seems to offer no other means.
Though less neat-looking, the second solution seems more adequate. What is hard on my sense of nice code style.
I propose collecting all constants in an immutable class, and use either method, the second being nicer, though needing a method.
However one could do it following both intent of using a class static constant,
and optimal memory resp. not copying same data in every field:
class MetaData {
public final String string;
public final int i;
MetaData(String string, int i) {
this.string = string;
this.i = i;
}
}
Just one instance per child class. In fact one could consider not using child classes but a factory and delegation in class A.
private abstract class A {
protected final MetaData metaData;
public A(MetaData metaData) {
this.metaData = metaData;
}
public String getName() {
return metaData.string;
}
public int getAge() {
return metaData.i;
}
public MetaData getMetaData() {
return metaData;
}
}
private class B extends A {
private static final MetaData b = new MetaData("B", 10);
public B() {
super(b);
}
}
Of course instead of constructor+super field, one could better make
protected abstract MetaData getMetaData();
#Override
protected MetaData getMetaData() {
return b;
}
The advantage would be when later an extra constant has to be added in the hierarchy.
I have my Pet super class which then has a Dog subclass, and a particular method in my super class is getSpecies(). In my subclass I want to be able to return super.getSpecies(), but also return another variable (in this case, smell) inside that method as well.
Super class:
public class Pet {
protected int lifeSpan;
protected String species, name, interaction;
public Pet(){
}
public Pet(int lifeSpan, String species, String name){
this.lifeSpan = lifeSpan;
this.species = species;
this.name = name;
}
public final float costs(float cost){
return cost;
}
public void setSpecies(String species){
this.species = species;
}
public String getSpecies(){
return this.species;
}
}
Subclass "Dog":
public class Dog extends Pet{
protected String smell;
private String species;
public Dog(String smell){
super(15, "Dog", "Rex");
this.smell = smell;
}
public Dog(){
}
public void setSmell(String smell){
this.smell = smell;
}
public String getSpecies(){
super.getSpecies();
smell = "high"; //Meant to deliberately set it to "High". How am I to return this?
}
public String getSmell(){
return this.smell;
}
}
You cannot return two values in a single function. What you have to do is use your getter for the smell member variable instead.
public class Dog extends Pet{
protected String smell;
private String species;
public Dog(String smell){
super(15, "Dog", "Rex");
this.smell = smell;
}
public Dog(){
}
public void setSmell(String smell){
this.smell = smell;
}
public String getSpecies(){
super.getSpecies();
}
public String getSmell(){
return this.smell;
}
}
Then let's say you want both species and smell, you have to check if the pet is in fact a dog, and if it is, you can safely cast it as a dog and use the specific methods of the Dog class.
if ( pet instanceof Dog ) {
String species = pet.getSpecies();
String smell = (Dog)pet.getSmell();
}
First things first: When calling super.getSpecies() you should save or hand over it's return value somewhere. Then you might consider concatenating this return string an your second return value (high) like this:
public String getSpecies(){
return "high " + super.getSpecies();
}
But:
the return of that high dog doesn't make much sense IMO.
a getter is expected to return only one value, the one it's name comes from.
There is no ather way to return multiple values except for passing objects that take the results as arguements. But that solution would be far away from a simple getter.
You should consider (like Pilibobby pointed out in his comment below) using two different getters in your case, getSpecies() and getSmell(), and combine their results at the place you are calling them from.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Java Reflection: Getting fields and methods in declaration order
Java. Get declared methods in order they apear in source code
Suppose I have this class
Is possible take the getters methods in order?
public class ClassA {
private String name;
private Integer number;
private Boolean bool;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public Boolean getBool() {
return bool;
}
public void setBool(Boolean bool) {
this.bool = bool;
}
}
I have try this..
for (Method method : ClassA.class.getDeclaredMethods()) {
if (!(method.getReturnType().toString().equals("void"))) {
method.invoke(obj, new Object[0])));
}
}
I got this from documentation
...The elements in array returned are not sorted and are not in any particular order...
So.. is just that? Exists some alternative or I just have to implement something?
You can add to each method your own #annotation, which contains a number. Then get all the getter methods, and use your custom sorter to sort them depending on the number you passed to the annotation using Collections.sort().
Eg:
#SortedMethod(100)
public String getName()
{
return name;
}
#SortedMethod(200)
public String getNumber()
{
return number;
}