Access attribute of a subclass [duplicate] - java

This question already has answers here:
Check attribute of a subclass
(3 answers)
Closed 9 years ago.
I stumbled across that situation but I don't know how to handle it the right way:
class Coffee { }
class CoffeeMix extends Coffee {
public boolean shaken;
}
I'm saving the coffee items in an array list:
ArrayList<Coffee> coffees = new ArrayList<Coffee>();
So in this array list exist normal coffee objects and coffee mix objects. Now I want to display all coffee mix objects, that are shaken:
for(Coffee c : coffees) {
//here is the same problem as above
}
As I read in some answers on stackoverflow: instanceof seems to be a bad idea, because it screws the idea behind oo up. So how to handle this?

First of all, when we talk about OO we shouldn't use public fields.
I understand why you want to avoid to use instance of.
In this case you can use polymorphism and dynamic binding. You can add abstract isShaken method to the base class, make shaken as private at CoffeeMix and override isShaken (return shaken)

You should indeed use polymorphism. That is the best way to go here. But you want you can also use getclass en check if it equals the class that referring to.

You could use the Visitor pattern.
Here's an example how it could be applied to your case:
interface CoffeeElement {
void accept(CoffeeVisitor visitor);
}
interface CoffeeVisitor {
void visit(Coffee coffee);
void visit(CoffeeMix coffee);
}
class Coffee implements CoffeeElement {
private final String name;
public Coffee(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public void accept(CoffeeVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return "Coffee [name=" + getName() + "]";
}
}
class CoffeeMix extends Coffee {
public CoffeeMix(String name) {
super(name);
}
#Override
public void accept(CoffeeVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return "CoffeeMix [name=" + getName() + "]";
}
}
class PrintingCoffeeVisitor implements CoffeeVisitor {
#Override
public void visit(Coffee coffee) {
// ignore regular coffee
}
#Override
public void visit(CoffeeMix mix) {
System.out.println(mix);
}
}
class CoffeeTest {
public static void main(String[] args) {
List<Coffee> coffee = new ArrayList<Coffee>();
coffee.add(new Coffee("Java"));
coffee.add(new Coffee("Molokai"));
coffee.add(new CoffeeMix("Season Blend"));
CoffeeVisitor v = new PrintingCoffeeVisitor();
for (Coffee c : coffee) {
c.accept(v);
}
}
}
You can also read this explanation of the Visitor pattern. I found it very useful.
https://stackoverflow.com/a/2604798/467874

instanceof seems appropriate here, but if you really don't want to use it, you could try something ugly:
for (Coffee c : coffees) {
try {
CoffeeMix blend = (CoffeeMix) c;
//whatever you want to do with CoffeeMix objects
} catch (ClassCastException cce) {
//whatever you want to do with Coffee objects
}
}
This seems like a situation in which the cure is worse than the disease, but so long as CoffeeMix objects have some fields or properties which are unavailable to Coffee objects, the exception should be thrown, and you will have accomplished your class-wise sorting without having used instanceof at great cost to proper technique.

Related

How to pass multiple Types that implement the same interface?

Firstly apologies about the not so great title, I am new to Java and wasn't sure how to title this.
I have a interface class "TestInterface":
ublic interface TestInterface {
String getForename();
void setForename(String forename);
String getSurname();
void setSurname(String surname);
}
"TestImpl" implements "TestInterface":
public class TestImpl implements TestInterface{
private String forename;
private String surname;
#Override
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
#Override
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
Then I have a call called "ExtendTest" which extends "TestImpl":
public class ExtendTest extends TestImpl{
private String firstLineAddress;
public String getFirstLineAddress() {
return firstLineAddress;
}
public void setFirstLineAddress(String firstLineAddress) {
this.firstLineAddress = firstLineAddress;
}
}
I then have this "Entity" class:
import java.util.List;
public class Entity {
private List<TestInterface> testInterfaces;
private List<ExtendTest> extendTests;
public List<TestInterface> getTestInterfaces() {
return testInterfaces;
}
public void setTestInterfaces(List<TestInterface> testInterfaces) {
this.testInterfaces = testInterfaces;
}
public List<ExtendTest> getExtendTests() {
return extendTests;
}
public void setExtendTests(List<ExtendTest> extendTests) {
this.extendTests = extendTests;
}
}
and finally this "DoStuff" class where the dostuff method accepts a parameter of type List
import java.util.List;
public class DoStuff {
public void doStuff(List<TestInterface> testData) {
}
}
I try to test this like so:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
DoStuff doStuff = new DoStuff();
Entity entity = new Entity();
// Works
doStuff.doStuff(entity.getTestInterfaces());
// Does not work
doStuff.doStuff(entity.getExtendTests());
}
}
However where the comment is "Does not work" their is an error
Required type:
List<TestInterface>
Provided:
List<ExtendTest>
My question is how do I make it so that I can pass it in. My understanding was that becase they all implement TestInterface that it would work but I think I am wrong with this.
Thanks for any help and learnings here :)
You've run afoul of PECS. I recommend reading the linked answer for a more detailed explanation, but here's the bits specific to your use case.
When you have a generic type (List, in your case), if you only read from it, you should write List<? extends MyInterface>. If you only write to it, you should write List<? super MyInterface>. If you do both, then you want List<MyInterface>. Why do we do this? Well, look at your code.
public void doStuff(List<TestInterface> testData) { ... }
This function takes a List<TestInterface>. The List interface has a ton of capability. You can add and remove things to it in addition to just reading from it. And doStuff expects a list of TestInterface. So it's entirely fair game for the implementation of doStuff to do
testData.add(new ClassIJustMadeUp());
assuming ClassIJustMadeUp implements TestInterface. So we definitely can't pass this function a List<ExtendTest>, since that list type can't contain ClassIJustMadeUp.
However, if your function does only read from the list and isn't planning to add anything to it, you can write the signature as
public void doStuff(List<? extends TestInterface> testData) { ... }
and now you can pass a List of any type which extends TestInterface. It's fine to read from this list, since any type which extends TestInterface clearly can be upcast safely to TestInterface. But if we try to add a list element, that's a compiler error since the list doesn't necessarily support that particular type.

java generic wildcard not working as expected

The code shown below was given to explain generic wildcard usage.
I have a Student parent class and Dayscholar child class. I have Record<Student> class that maintains a list of Student/Dayscholar objects and a method named display that accepts a parameter of Record<? extends Student> and displays the list. This works with either Record<Student> or Record<Dayscholar>. And according to what I understood from the course the wildcard is required. Meaning if declaration of display method is changed to display(Record<Student>) the method will not accept the parameter Record<Dayscholar> and will issue a compile time error.
But declaring display method as display(Record<Student> somename) worked just as fine with record of type Student or of type Dayscholar. I am confused. What would be best example to demonstrate generic wildcard?
class Record<Student>//<Number>
{
List<Student> record =new ArrayList<>();
#Override
public String toString() {
return "Record [record=" + record + "]";
}
public void add(Student e)
{
record.add(e);
}
public void display(Record< Student> record) {
System.out.println("student record:"+record);
}
}
class Student
{
int id;
String name;
public Student(int id,String name)
{
this.id=id;
this.name=name;
}
#Override
public String toString()
{
return "Id = "+id+" Name = "+name;
}
}
class Dayscholar extends Student
{
float stipend;
public Dayscholar(int id,String name,float stipend)
{
super(id,name);
this.stipend=stipend;
}
#Override
public String toString()
{
return "Id = "+id+" Name = "+name+" Stipend = "+stipend;
}
}
class WildcardsDemo
{
public static void main(String[] args)
{
Record<Student> studentrecord = new Record<>();
studentrecord.add(new Student(9999,"hassan"));
studentrecord.display(studentrecord);
Record<Dayscholar> dayscholar = new Record<>();
dayscholar.add(new Dayscholar(2222,"Sam",900));
dayscholar.display(dayscholar);
}
}
Everything in my post was correct until few hours ago (now it is 11pm US ET) when I ran the code/s again. I ran the code in play ground of training course and wild card proved to be holding to my surprise. I don't know how explain this. Is it my laptop / is it that the browser was caching previous good runs? I hope this will not be considered as a point against me.

My System.out.println(); keeps printing null instead of the text it should print

I started Java a while ago and I am now busy with abstract classes. I've been busy with this code for two days now and I can't find out how to fix this. The methods names might not be in English, sorry for that but I think it wouldn't be too big of a problem.
I don't know why the output is as following:
null null null null
null null null null
null null null null
null null null null
I hope you guys can help me out. I would appreciate any help! Thanks in advance.
Main class, which is also abstract:
public abstract class Boek {
public String isbn;
public String auteur;
public String paginas;
public String titel;
public abstract void setIsbn(String isbn);
public abstract void getIsbn();
public abstract void setAuteur(String auteur);
public abstract void getAuteur();
public abstract void setPaginas(int paginas);
public abstract void getPaginas();
public abstract void setTitel(String titel);
public abstract void getTitel();
public static void main(String[] args) {
Studieboek sb = new Studieboek();
Roman ro = new Roman();
Dichtbundel db = new Dichtbundel();
sb.setAuteur("J.K. Rowling");
sb.setIsbn("547896587412");
sb.setPaginas(251);
sb.setTitel("Harry Potter");
sb.addNAuteur("R.K. Dale");
sb.addOndertitel("Exactly");
sb.printSB();
ro.setAuteur("Suzanne Vermeer");
ro.setIsbn("9632589632574");
ro.setPaginas(311);
ro.setTitel("De Zwarte Piste");
ro.printRO();
db.setAuteur("A.Y. Lmao");
db.setIsbn("5781236985478");
db.setPaginas(171);
db.setTitel("Rijmen kreng");
db.addGedicht("Rijmpje");
db.printDB();
}
}
First subclass:
public class Studieboek extends Boek {
private String ondertitel;
private String nAuteur;
#Override
public void setIsbn(String isbn) {
}
#Override
public void getIsbn() {
}
#Override
public void setAuteur(String auteur) {
}
#Override
public void getAuteur() {
}
#Override
public void setPaginas(int paginas) {
}
#Override
public void getPaginas() {
}
#Override
public void setTitel(String titel) {
}
#Override
public void getTitel() {
}
public void printSB() {
System.out.println(titel + " " + auteur + " " + paginas + " " + isbn + " " + ondertitel + " " + nAuteur);
}
public void addOndertitel(String ondertitel) {
}
public void addNAuteur(String nAuteur) {
}
I have two more subclasses after this but I don't think it is necessary for the code to work, because the code in both other subclasses are exactly the same and give the exact same output.
Again, any help is appreciated. Thanks in advance.
Sincerely,
Double
Your setters aren't doing anything.
A correct way to implement e.g. your setter for isbn would be:
#Override
public void setIsbn(String isbn) {
this.isbn = isbn;
}
Note the part where it actually sets something.
Your getters are equally wrong. A getter should return something, i.e. not be declared as void and have a return statement:
#Override
public String getIsbn() {
return this.isbn;
}
I know they should contain a return value, but the return value gives an error and whenever I leave it empty it seems fine.
(from the comments)
I'm guessing the error is something along "a void method cannot return anything" and yes, it will be fine - unless you try something like
System.out.println(sb.getIsbn()); // Will also print "null"
I'll leave the rest up to you.
Bonus 1: If you have an abstract parent class anyway, you can move the common getters and setters to Boek instead of just declaring them as abstract. This will save you from having to re-implement them in each of your subclasses again.
Bonus 2: public fields (as in public String isbn;) are usually discouraged. You already have the getters and setters, so make them protected (see also: encapsulation).
Bonus 3: As already pointed out by Mike 'Pomax' Kamermans in the comments: You don't want to have your main method in your Boek class. Create a separate "application" class with only the main method to start up your application.
Bonus 4: I believe the standard way of what you want to achieve with your printSB, printRO and printDB methods would be to override the toString() method. Although this might be different for your special use case.
Use it as following:
public class Studieboek extends Boek {
...
#Override
public String toString() {
return this.isbn + " " + this.auteur; // Plus the others
}
}
And
// No need to call an additional method, toString will be invoked automatically
System.out.println(db);
Your set and get methods are empty. You need to set a value in the setters and return the value in the getters.
Right now you are trying to print a variable that has not yet been set - so yes, it is going to print null.
public class FooClass{
private String foo;
public void setFoo(String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
}
You are printing the variable, whose values have not set. You have set the variable values in setter methods in order to print the values. Setter methods to set the values. And getter methods to return the values.
#Override
public void setTitel(String titel) {
this.titel=titel;
}
#Override
public String getTitel() {
return titel;
}

Interface Segregation Principle

I'm learning SOLID principles with Java and I'm trying to implement two classes with this. My problem is about ISP. I have some methods that is present in one class but not in the other and I also have to refer both classes with the same interface.
This is the first class:
public final class Complex implements Number {
#Override
public String polarForm() {
//This class needs to implement this method
}
#Override
public String rectangularForm() {
//This class needs to implement this method
}
}
Here is the second one:
public final class Real implements Number {
#Override
public String polarForm() {
//This class does not need this method!
}
#Override
public String rectangularForm() {
//This class does not need this method!
}
}
Finally I have to refer to the classes something like this:
public static void main(String[] args) {
Number c = new Complex();
Number r = new Real();
Number n = c.add(r);
System.out.println(c.polarForm());
System.out.println(n);
}
How can I refer to both classes with the same interface without implementing unnecessary methods?
An alternate solution to approach this problem would be to use Composition instead of Inhertiance in conjunction to the interface segregation principle.
Number class
public class Number {
private RectangleForm rectangleForm;
private PolarForm polarForm;
private BigDecimal value;
public Number(RectangleForm rectangleForm, PolarForm polarForm,BigDecimal value) {
this.rectangleForm = rectangleForm;
this.polarForm = polarForm;
this.value = value;
}
public String polarForm() {
return polarForm.transform(this.value);
}
public String rectangleForm() {
return rectangleForm.transform(this.value);
}
//other methods such as add and subtract
}
PolarForm interface
public interface PolarForm {
public String transform(BigDecimal number);
}
RectangularForm interface
public interface RectangleForm {
public String transform(BigDecimal number);
}
RectangleForm implementation for real numbers
public class RectangleFormReal implements RectangleForm {
#Override
public String transform(BigDecimal number) {
String transformed = "";
//transfromed = logic to transform to rectangle form
return transformed;
}
}
PolarForm implementation for Real numbers
public class PolarFormReal implements PolarForm {
#Override
public String transform(BigDecimal number) {
//return the number as is without any transformation
return number.toString();
}
}
Putting the pieces together
public class NumberTest {
public static void main(String[] args) {
RectangleForm rf = new RectangleFormReal();
PolarForm pf = new PolarFormReal();
Number number = new Number(rf, pf,new BigDecimal(10));
String rectangleForm = number.rectangleForm();
String polarForm = number.polarForm();
}
}
You can create the PolarFormComplex and RectangleFormComplex implementations and wire theNumber instance in a similar fashion. The advantage of this approach is that your code will always rely on the interface of the Number class (by interface I mean the public APIs) and you can chose the transformation strategy by injecting the corresponding PolarForm or RectangleForm instances into your Number instance at compile time as shown above or at runtime (via a factory)
Break your Number interface (or base class) into multiple interfaces. The standard operations (add, subtract, etc) are in one; let's say INumber. polarForm and rectangularForm are part of another; let's say IComplex.
Real would implement INumber; Complex would implement INumber and Icomplex. You could then treat both as INumber.
If necessary, you could also create another interface that implements both.

How can you call a class that is implementing a certain interface without knowing its name?

So I'm building a game engine and I need to be able to call methods from a class that implements a certain interface(I only want to call methods implemented by the interface).
My problem is that I don't know what the class name will be implementing it.
So how does, for instance, Java call the run() method in all classes that implement Runnable without knowing the class name?
Really, you're asking about the Factory pattern or a dependency injection container such as Spring.
Of course you can call the methods on an interface, the question is how you get the instance. That of course has to be specified, coded or configured somewhere. Configuration is preferable if there could ever be more than one in the future.
Thus, more of a real example:
public interface MovementStrategy {
public Move selectMove (Actor actor, ActorSituation theirSituation);
}
public class MonsterTypes {
public static MonsterType GOBLIN = new MonsterType( "goblin", new AttackMover(1.2));
public static MonsterType TROLL = new MonsterType( "troll", new AttackMover(0.45));
public static MonsterType DEER = new MonsterType( "deer", new FleeMover(2.0));
// useful to have, also.
public static List<MonsterType> getAllRegisteredTypes();
public static class MonsterType {
protected String name;
protected MovementStrategy moveStrategy;
// TODO -- getters & setters for all properties.
// constructor.
public MonsterType (String name, MovementStrategy moveStrategy) {
this.name = name;
this.moveStrategy = moveStrategy;
}
}
}
public class AttackMover implements MovementStrategy {
// SPEC: generally move towards/attack PC, with varying speeds.
}
public class FleeMover implements MovementStrategy {
// SPEC: generally run away from PCs.
}
This isn't probably a perfect design -- it conflates "movement" (aka goal-seeking) with the actor's turn/actions overall -- but hopefully it gives you some more idea.
If you only want to call methods from the interface (good!), then you usually don't need to now the name of the implementor.
getRunnableFromSomewhere().run();
always works and calls the run() method on the instance that is returned by that method.
If you want to now the class name at runtime, simpy call getClass().getName() on the instance:
System.out.println(getRunnableFromSomewhere().getClass().getName());
A simple example with the Number interface:
public class NumberExample {
public static void main(String[] args) {
MagicNumber magic = MagicNumberProvider.get(); // a random implementation
System.out.println(magic.getMagicNumber().doubleValue()); // We know nothing about the implementations
}
}
class MagicNumberProvider {
public static MagicNumber get() {
return Math.random() > 0.5d ? new ItsMagicOne() : new ItsMagicTwo();
}
}
interface MagicNumber {
public Number getMagicNumber();
}
class ItsMagicOne implements MagicNumber {
#Override
public Number getMagicNumber() {return new Long(1);}
}
class ItsMagicTwo implements MagicNumber {
#Override
public Number getMagicNumber() {return new Double(2.5);}
}
It only calls interface methods and we have, from the perspective of the main method, no idea, which implementation of MagicNumber is used (it's random) and on which implementation of Number we actually call the doubleValue() method.
Service Provide Interface
You can use java SPI (Service Provider Interface) by which later implementing jars declare the same service in the manifest. A using app can do a lookup, iterate over them and pick one.
An example is the different XML parser implementations.
Parameter
For your case it might suffice to have a run method:
class GameRunner {
public static void mainEntry(MyGameInterface mgi) {
}
}
And the implementors may do
cöass ThirdPartyGame implements MyGameInterface {
}
GameRunner.mainEntry(new ThirdPartyGame());
Plugin with java reflection
You can make your ad-hoc, self-define plugin emchanism, and use java reflection to instantiate the class. The third party jar must be placed at some location, that is in the class path, as defined in your jar's manifest. The class somewhere defined:
String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();
If I understood your question correctly it seems you have slightly misunderstood polymorphism, you don't need to know the type that implements the interface.
See the following example, there is only one class that directly knows the types of each enemy, the initializing class.
import java.util.ArrayList;
import java.util.List;
public class SO18671999 {
public static interface Enemy {
public void Attack(Enemy other);
public String getName();
}
public static class Dragon implements Enemy {
String name = "Onyxia";
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for 10 dmg!");
}
public String getName() {
return this.name;
}
}
public static class Cerberus implements Enemy {
private String name;
private int dmg;
public Cerberus(String name, int dmg) {
this.name = name;
this.dmg = dmg;
}
#Override
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for " + this.dmg + " dmg!");
}
#Override
public String getName() {
return this.name;
}
}
public static class EnemyInitializer {
private List<Enemy> enemies;
public EnemyInitializer() {
enemies = new ArrayList<>();
enemies.add(new Dragon());
enemies.add(new Cerberus("CerberusHeadLeft", 10));
enemies.add(new Cerberus("CerberusHeadRight", 10));
enemies.add(new Cerberus("CerberusHeadCenter", 20));
}
public List<Enemy> getEnemies() {
return enemies;
}
}
public static class EnemyAttacker {
private EnemyInitializer eI = new EnemyInitializer();
public void startAttacking() {
List<Enemy> enemies = eI.getEnemies();
for (Enemy one : enemies) {
for (Enemy two : enemies) {
if (one == two)
continue;
one.Attack(two);
}
}
}
}
public static void main(String[] args) {
EnemyAttacker eAttacker = new EnemyAttacker();
eAttacker.startAttacking();
}
}

Categories

Resources