I am currently working on designing some system where I'm confused if it will be right to control base class attributes with derived class.
For example:
Class Building {
String name;
String[] facilities;
}
Class OfficeBuilding extends Building{
}
Class ResidentialBuilding extends Building {
}
//Type of Building control attribute like facilities here which is empty by default. Should it be part of Derived classes or it should remain part of Base class and derived classes should just override its values ?
Things to keep in mind:
1). All classes are data classes here.
2). Base class facilities attribute is always empty and controlled by child class.
Thanks.
There is more than one solution. Not knowing your use case I would say name and facilities can be fully managed by parent class, not even directly accessible from child classes (only via constructor / some methods). I would also store facilities as list:
Class Building {
private String name;
private List<String> facilities;
public Building(String name, String... facilities) { // facilities won't be null this way
this.name = name;
this.facilities = new ArrayList<String>(Arrays.asList(facilities));
}
public Building(String name) {
this(name, new String[0]);
}
// Only if this makes sense
public Building() {
this("");
}
public String[] getFacilities() {
return facilities.toArray(new String[facilities.size()]);
}
// if needed you can...
public void addFacility(String facility) { ... }
public void removeFacility(String facility) { ... }
}
Class OfficeBuilding extends Building {
public OfficeBuilding() {
super("Office", "facility1", "facility2");
//...
}
}
Related
I have two similar classes, each with a single field of the same type.
class Fruit {
private final String name;
}
class Vegetable {
private final String name;
}
I'd like to implement hashCode() for each. My problem is that in my case, collisions between names are somewhat more possible than with "apple" and "carrot," and they both might be in the same Map/Set. I'm wondering what's the most clear way of implementing hashCode to handle this.
So far, I've considered Objects.hash(this.getClass(), name), Objects.hash(<some int unique to this class>, name). I like the first just because it's a bit more self-documenting and robust than the second, but it's not a pattern I've seen in the wild. I also considered <some prime int unique to this class> * Objects.hashCode(name), but that felt fragile, especially if a new field gets added.
Assuming the 2 classes extend a common parent class, I solved this by adding a second field that would tell the instances of two different classes apart. This may be regarded as just another way of using the class name suggested by David Ehrmann in his question. But in my case using an additional field looks more appropriate than using a class name. So here's my abstract parent class:
public abstract class NationalDish {
public String dishName;
public String country;
#Override
public int hashCode() {
return Objects.hash(country, dishName);
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof NationalDish)) {
return false;
}
NationalDish other = (NationalDish) obj;
return Objects.equals(dishName, other.dishName)
&& Objects.equals(country, other.country);
}
}
Note how having the fields in the parent class allows to define equals() and hash code() in that same class and keep child classes to the minimum:
public class EnglishDish extends NationalDish {
public EnglishDish(String dishName) {
this.dishName = dishName;
this.country = "England";
}
}
public class AmericanDish extends NationalDish {
public AmericanDish(String dishName) {
this.dishName = dishName;
this.country = "USA";
}
}
Now, with country names (or plant types like in the question) in place we can have same name instances which will look different to Java:
public static void main(String[] args) {
NationalDish englishChips = new EnglishDish("Chips");
NationalDish americanChips = new AmericanDish("Chips");
System.out.println(englishChips.equals(americanChips)); // false
}
there I'm pretty new to Java and have german class and method titles. This Code is meant to give a string output for every class extending "Musiker". I have already looked on SO but my problem is that changing it to static gives an error on the class itself. The main reason why I open a new Question is, that every other class is working as planned. And please don't wonder why the Strings look weird, the Book I copied this from is meant to be humoristic.
public class Proberaum {
public static void main(String[] args) {
try {
Musiker saenger = new Saenger();
Musiker gitarrist = new Gitarrist();
Musiker bassist = new Bassist();
Musiker trompeter = new Trompeter();
Musiker backgroundSaengerin = new BackgroundSaengerin();
machtMusik(saenger, gitarrist, bassist, trompeter, backgroundSaengerin);
} catch(Exception e) {
new Exception().printStackTrace();
}
}
public static void machtMusik(Musiker... gruppe) {
for(Musiker musiker : gruppe) {
musiker.musizieren();
}
}
public class Musiker {
private String name;
private int alter;
private Band band;
public void musizieren() {
System.out.println("OO Mmmmmmmmh, OO Mmmmmmmmh");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAlter() {
return alter;
}
public void setAlter(int alter) {
this.alter = alter;
}
public Band getBand() {
return band;
}
public void setBand(Band band) {
this.band = band;
}
}
public class Band {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Saenger extends Musiker {
#Override
public void musizieren() {
this.singen();
}
public void singen() {
System.out.println("Oh, bäbi, juuuu a mei sannnnscheiiiiin");
}
}
public class BackgroundSaengerin extends Saenger {
}
public class Bassist extends Musiker {
}
public class Gitarrist extends Musiker {
public void musizieren() {
System.out.println("Tschiiiiiingzäääängggggg");
}
}
public class Trompeter extends Musiker {
}
}
Your Saenger class is actually a non-static member of the Proberaum class. Because it's non-static, you actually need to create an instance of Proberaum before you can use any of these classes:
Proberaum proberaumObject = new Proberaum();
Musiker saenger = new proberaumObject.Saenger();
In your case, classes inside classes is probably not what you want to do. If you extract each of your classes into its own file, you should find your problem going away. (If that's not possible for whatever reason, declaring your subclasses as static should work too.)
Like Joe C also mentioned in his answer: the core of the problem is that your classes Saenger, Musiker, etc etc. are all nested classes (nested inside Proberaum), but they are defined as non-static.
In Java, non-static nested classes are called "inner classes". Inner classes have implicit access to their enclosing class members (even private ones), but of course the flipside of this is that there first needs to be an object of that enclosing class for the inner class to reference. That is why the compiler is complaining in your example: you're trying to create an object of class Saenger, which is an inner class of Proberaum, so to create that object it needs to have a reference to an object of type Proberaum. Since you're doing the object creation in the (static) main method, no such object exists.
So, to fix, you have to change your inner classes. Easiest is to declare them all static. Note that you can do this is in addition to be making them public:
public static class Seanger extends Musiker { ...
As also remarked elsewhere however, you really should not put every class in the same file. Learn to work with one class per file, it's the Java Way™.
Instead of declaring the nested classes as static, one can alternatively create objects of nested classes like mentioned below.
Proberaum proberaumObject = new Proberaum();
Musiker saenger = proberaumObject.new Saenger();
This question already has answers here:
Can an abstract class have a constructor?
(22 answers)
Closed 8 years ago.
If you are never going to instantiate an object from that class, when are you going to ever use its constructor? Sorry if I come off as ignorant. I just started a class on Java at my high school.
you can initialize something in parent class , so maybe you need constructor in abstract class.
Because sub classes may use it. For example:
public abstract class Foo {
protected String name;
public Foo(String name) {
this.name = name;
}
}
public class Bar extends Foo {
public Bar(String name) {
super(name); //<-- necessary, otherwise it won't compile
}
public Bar() {
super("default name"); // <-- necessary, otherwise it won't compile
}
}
You have a constructor so subclasses can initialize the state of their parent properly.
public abstract class Parent {
private final String name;
public Parent(String n) { this.name = n; }
public String getName() { return this.name; }
}
public class Child extends Parent {
public Child(String name) { super(name); }
}
There would be no other way to initialize that private final String name attribute in the Parent without a constructor.
Well your parent class or the abstract class stores common variables throught all children classes or subclasses.
This makes it easier to store different objects (with the same parent) into collections such as and ArrayList.
It also allows you to easily manipulate and object without worrying about its details that is contained in the subclass.
You do instantiate the constructor by calling super() within the subclass.
I am trying to implement an interface in Java to use different types of databases for one application.
My though was to create an abstract class with the common interface and two static variables which are then overwritten by the subclasses. I then wanted to add a Class[] List with the classes of all available subclasses to the abstract class as well as a couple of functions that allow the determination of the correct class to be used.
The goal is to first get a list of all available database types and let the user choose one. Afterwards another function should translate the name (which could be localized) to the IDENTIFIER which is specified in the subclass. Finally a third function allows the instantiation of an object by giving such an IDENTIFIER.
My abstract class would look something like this:
public abstract class DataBase {
public static final IDENTIFIER = "";
public static final NAME = "";
private static final Class[] dbTypes = new Class[]{PostgreSQL.class, MySQL.class};
public static String[] getNameList() {
String[] names = new String[dbTypes.length];
for(int i = 0; i < dbTypes.length; i++){
names[i] = dbTypes[i].NAME; //Cannot access the static variable this way.
}
return names;
}
public static String getIdentifierForName(String name) {
for(int i = 0; i < dbTypes.length; i++){
if(name.equals(dbTypes[i].NAME){
return dbTypes[i].IDENTIFIER;
}
}
return "";
}
public static DataBase getInstanceOf(String identifier) {
for(int i = 0; i < dbTypes.length; i++){
if(identifier.equals(dbTypes[i].IDENTIFIER) {
return dbTypes[i].newInstance();
}
}
return null;
}
}
The Child classes would look something like this:
public class MySQL extends DataBase {
public static final IDENTIFIER = "ab.cde.MySQL";
public static final NAME = "MySQL";
...
}
public class PostgreSQL extends DataBase{
public static final IDENTIFIER = "ab.cde.PostgreSQL";
public static final NAME = "PostgreSQL";
...
}
My problem now is, that I cannot access the static variables from the Class object. Obviously the dbTypes list does not contain any typed classes. I tried changing the type of the Array to Class<? extends DataBase>, but I get an error Cannot create a generic array of Class<? extends DataBase> I also tried checking the classes with isAssignableFrom() and then casting the class, but I was still not able to access the static variables.
For now I have two solutions which are working:
Hardcode all existing subclasses into each function if(PostgreSQL.NAME.equals(name)){...}etc.
However, if I add new subclasses, I only want to have to add them at one point in my implementation.
Instead of using a Class[] array, I can use an array of DataBase[] with instances of each class. However, I would think this is bad practice to instantiate each available DataBase subclass, even though I only need one in the end.
Since I have never done such a thing before I might also be approaching the problem completely wrong. Maybe I am missing the correct way in which something like this is usually done?
Thank you for your help.
There are no "abstract properties" in Java. You have to create two astract methods in the DataBase class, like this:
public abstract class DataBase {
// No "abstract propeties"
public abstract String getDBName();
public abstract String getDBIdentifier();
// etc etc...
}
and then, in each subclass:
public class MySQL extends DataBase {
public static final IDENTIFIER = "ab.cde.MySQL";
public static final NAME = "MySQL";
#Override
public String getDBName() {
return NAME;
}
#Override
public String getDBIdentifier() {
return IDENTIFIER;
}
// etc etc...
}
When using the classes, you can just cast to DataBase (not MySQL or PostgreSQL) and call the two abstract methods.
Therefore, in order to solve your "pick a database class" problem, I would create a configuration file that contains the names of the databases and the corresponding class, and instantiate it with reflection (newInstance()) as needed.
As an alternative, you can use reflection to access the static variables like Nikita's answers suggested, or you can just use the name of the class as the identifier of the database it supports, like this (not tested):
public abstract class DataBase {
private static final Class[] dbTypes = new Class[]{PostgreSQL.class, MySQL.class};
public static Class getDBClass(String type) {
for (Class c : dbTypes) {
if (c.getSimpleName().toLowerCase().equals(type.toLowerCase())) {
return c;
}
}
return null;
}
public static Set<String> getSupportedDB() { // <-- you populate a dropdown menu with this
Set<String> supported = new HashSet<String>();
for (Class c : dbTypes) {
supported.add(c.getSimpleName());
}
return supported;
}
// etc etc...
}
However, I don't like this solution and I would not use it.
You can use reflection to get values for each class:
public static String[] getNameList(){
String[] names = new String[dbTypes.length];
for(int i=0; i<dbTypes.length; i++){
Field f = dbTypes[i].getField("NAME");
names[i] = f.get(null);
}
return names;
}
But it might be slow.
Also I'd suggest to create separate enum DBRegistry that will contain names, identifiers and classes:
public enum DBRegistry {
MYSQL("ab.cde.MySQL", "MySQL", MySQL.class),
POSTGRESQL("ab.cde.PostgreSQL", "PostgreSQL", PostgreSQL.class);
private String name;
private String identifier;
private Class<?> dbClass;
private DBRegistry(String identifier, String name, Class<?> dbClass) {
this.identifier = identifier;
this.name = name;
this.dbClass = dbClass;
}
// Getters...
}
You can iterate on all items in registry using DBRegistry.values
Not tested, but I would suggest something like this. You could register databases by calling DataBase.registerDataBase(new DataBase(...))); which may be invoked from the main file.
public class DataBase {
private final static List<DataBase> INSTANCES = new ArrayList<DataBase>();
private final String identifier;
private final String name;
private final Class<?> dbType;
public DataBase(String identifier, String name, Class<?> dbType) {
this.identifier=identifier.toString();
this.name=name.toString();
this.dbType=dbType;
}
String getIdentifier() {return identifier;}
String getName() {return identifier;}
Class<?> getDbType() {return dbtype;}
public synchronized static void registerDatabase(DataBase database) {
database.getClass();
INSTANCES.add(database);
//may check if already registered and either fail or replace it
}
public synchronized static List<DataBase> getNameList() {
return new ArrayList<DataBase>(INSTANCES);
}
public synchronized static List<String> getNameList() {
List<String> names = new ArrayList<String>(INSTANCES.size());
for (Database db:INSTANCES) names.add(db.getName());
return names;
}
public synchronized static String getIdentifierForName(String name) {
for(DataBase db:INSTANCES){
if(name.equals(db.getName())) return db;
}
return null;
}
public synchronized static DataBase getInstanceOf(String identifier) {
for(DataBase db:INSTANCES){
if(identifier.equals(db.getIdentifier())) return db;
}
return null;
}
}
}
I would advise to keep it simple, never more than necessary to utilize in the actual application. It is easier to extend things than to re-factor code to accomodate for additional complexity. Most of the stuff you mention are merely artefacts of your problem solving, not the actual requirements of your application per se. And it so happens, that a modern object-oriented language has everything you need, and you can implement a good design without reflection and without resorting to static properties and string identifiers.
Remember to rely on the compiler rather than runtime for whatever you know in advance - anything that is known not to change from one application run to another, does not need reflection, because it does not involve runtime variables! I would go for interfaces, classes implementing them, and more importantly the Factory pattern to abstract using these classes:
interface Database
{
void query(String sqlString);
}
class MySQLDatabase implements Database
{
public void query(String sqlString)
{
}
}
class PostgreSQLDatabase implements Database
{
public void query(String sqlString)
{
}
}
class DatabaseFactory
{
Database connectDatabase()
{
/// F.e. return new MySQLDatabase();
}
}
The whole "database abstraction layer" has been done to death already anyway, giving birth to DBA, ODBC and other software stacks that solve your problem. You should let yourself be inspired by these, unless you are sure your particular way of solving this yields advantages that can be proven. If you want to go about this in a professional way, of course. If you want to educate yourself, by all means, use reflection, strings in place of more specific objects, and tight-coupling instead of aggressive modularity.
Just as I was starting to get familiar with interfaces, I came across a stumbling block with abstract classes. In my understanding, they can be used to provide some functionality for subclasses, but forces subclasses to specify undefined functions (if there are any left).
All the examples I came across however only dealt with functionality that could have been static - no reference to instance variables.
I'm trying to hide some common functions like getName() in the abstract class, but be able to define said name in the subclass.
public interface Application {
public String getName();
}
/**
* Specify some default behaviour to keep leaf classes free of common code
*/
public abstract class DefaultApplication implements Application {
public static final String NAME = "DefApp";
#Override
public String getName() {
return NAME;
}
}
public class MyApp extends DefaultApplication {
public static final String NAME = "My App";
}
// Main class
Application myApp = new MyApp();
System.out.println(myApp.getName()); // Prints "DefApp"
I thought that protected String name might work, but this also returns the instance variable in the abstract class. Is the only solution to redefine getName() in each subclass? I wouldn't have minded so much, but this isn't the only case where I'm trying to siphon off methods into the abstract class.
Thanks!
EDIT:
if it's relevant (to suggest other approaches I could consider), Application is a plugin api, and MyApp is an example application provided. DefaultApplication is part of the base project.
You cannot override anything that's static. Static methods do not belong to a particular object, but belong to the class itself instead; when you write return NAME, the compiler reads this as return DefaultApplication.NAME.
In this case, you can either override getName() in each subclass as you already came up with, or you can make the field non-static, and do something like this:
abstract class DefaultApplication implements Application {
private final String name;
protected DefaultApplication(String name) {
this.name = name;
}
protected DefaultApplication() {
this("DefApp");
}
public String getName() {
return name;
}
}
class MyApp extends DefaultApplication {
public MyApp() {
super("My App");
}
}
This will add an extra field to every instance of DefaultApplication but as long as you don't have millions of them, that shouldn't really matter.
The annotations idea interested me, so I figured I'd throw this out here. Here's a really complicated and not exactly recommended way of printing "My App":
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
interface Application {
public String getName();
}
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#interface ApplicationName {
String value();
}
#ApplicationName("DefApp")
abstract class DefaultApplication implements Application {
#Override
public String getName() {
return getClass().getAnnotation(ApplicationName.class).value();
}
}
#ApplicationName("My App")
class MyApp extends DefaultApplication {
}
public class Main {
public static void main(String[] args) {
Application myApp = new MyApp();
System.out.println(myApp.getName());
}
}