class with selector of static content - java

Lets say I have two similar class:
public class First {
public static final String ONE = "1";
public static final String TWO = "2";
public static final String THREE = "3";
}
public class Second {
public static final String ONE = "one";
public static final String TWO = "two";
public static final String THREE = "three";
}
Now in other class Im using one of them:
public class Third {
//....
#Override
public String toString()
{
System.out.println( First.ONE );
}
}
But what I'm trying to do now, is make kind of selector, lets say constructor of class Third gets boolean value and based on it select which class use, but I dont want to make if (..) statement everywhere, cause its simply too much.
So in abstract I'd like this:
public class Third {
//some global var with reference? to static class
public Third(boolean first)
{
if( first ) {
//set class First as source of static fields
} else {
//set class Second
}
}
//....
#Override
public String toString()
{
System.out.println( globalVariableWithReference.ONE );
}
}
Is it possible without making an istance of these class?

You could use an interface with getter methods, then have the two classes implement that interface (and return their respective values when the getter methods are called). Then you can create a map to map between the boolean value and the two implementation classes (via the interface), and call the object that maps to the boolean. Of course, this requires that you create an object of each class, but you would get the same behavior.
Another option is to create a wrapper class that wraps the if/else logic into its own static methods and return the appropriate value from the two classes based on the boolean value. While you will need to write the if/else logic for this wrapper clasee, you do not need to write it more than once, just call the wrapper class's methods

You can use reflection:
Class x = if (first) First.class : Second.class;
String one = (String) x.getField("ONE").get(null);

Related

How to Transfer values to another class method

I have global variables in Question class and increments these values in event handler. I have another class User which contains a static method Details(). I want to pass these two variables values (after increments) from event handler to the Details() of the User class.:
public class Question {
public int phCounter = 0;
public int chemCounter = 0;
private void CategoryCbActionPerformed(java.awt.event.ActionEvent evt) {
phCounter++;
chemCounter++;
}
}
...
public class User {
static void Details() {
public counter ;
}
}
My question is is there any way, except to send values as arguments to Details(), in which I can inject these incremented values inside Details() method.
First off: Method names in Java are camelCase. Not UpperCase ;)
If you want to access fields of a class in another class there are serveral ways to achieve that. The easiest one are static fields:
public class MyClass {
public static String accessible;
}
public class AnotherClass {
public void someMethod() {
// You can set the value ...
MyClass.accessible = "New value";
}
public void anotherMethod() {
// ... and get the value.
System.out.println(MyClass.accessible);
}
}
But remember: The value of a static field will be always the same unless you change it, even when you create new instances of the class where the static field is used. You should avoid static fields if possible. In most cases you can take the OOP way to achieve the same result.
~ Morph
I can inject these incremented values inside Details() method.
what does this statement mean?
your code below can not be compiled!
public class User{
static void Details()
{
public counter;
}
}
if you want to use reflection to send args to method ,why not just call User.Details(int a,int b)

How to access an object (already cast as its parent) as its actual object without reflection?

How do I access the property of a child class instead of the abstract class, when handling objects by their parent/abstract class? Like in this example:
public class WordCategories {
public static abstract class Noun {
public static final String TYPE = null;
//... and so on, methods
}
public static class Person extends Noun {
public static final String TYPE = "Person";
// ...
}
}
/* ... then we build a collection with members like: */
nouns.add(new WordCategories.Person("Bill Clinton");
/* now later we need to access a mixed list of nouns: */
for(WordCategories.Noun n: nouns) {
if(n.TYPE.equals("Person") ){ // this is always null
}
Obviously I could just specify (WordCategories.Person) n but that assumes that it is a Person. I need the cast to come from the parent class, and it would be most elegant if it did not involve interpreting the TYPE constant or the use of reflection, for that matter.
You don't have to use reflection at all. If you understand what type it is you like, you can use instanceof to get the specific class instance you care about.
for(WordCategories.Noun n: nouns) {
if(n instanceof WordCategories.Person) {
// cast to WordCategories.Person and perform whatever action you like
WordCategoriesPerson actualPerson = (WordCategories.Person) n;
}
}
This trumps the usage of the field to determine the object type, since the class contains enough metadata for you to want to use in this scenario. While many people would also discourage the use of instanceof due to performance (and frankly, if you wanted a list containing WordCategories.Person, just ask for one), its use in this instance would be cleaner than forcing each child class of WordCategories.Noun to create a method to inform us of what type it is.
static fields are always looked up by static type, so it doesn't matter what you assign to n; n.TYPE will always be WordCategories.Noun.TYPE. Heck, n could even be null:
System.out.println(((WordCategories.Noun) null).TYPE); // Doesn't cause an exception.
There is no way to get n.TYPE to behave the way you want with a static TYPE field. You will need to either make it non-static (and make all your objects bigger in the process), or you will need to change the way you access this data.
Instead of trying to access this through a static field, I recommend using an instance method:
public class WordCategories {
public static abstract class Noun {
public static final String TYPE = null;
public abstract String getType();
//... and so on, methods
}
public static class Person extends Noun {
public static final String TYPE = "Person";
public String getType() {
return TYPE;
}
// ...
}
}
...
for(WordCategories.Noun n: nouns) {
if(n.getType().equals("Person") ){
...
}
}
Try the test case:
public static void main(String[] args) {
Base sub1 = new Sub();
System.out.println(sub1.TYPE); // will print 'BASE'
Sub sub2 = new Sub();
System.out.println(sub2.TYPE); // will print 'SUB'
}
static class Base {
static String TYPE = "BASE";
}
static class Sub extends Base {
static String TYPE = "SUB";
}
If you access static field by the instance, it is decided by instance's declare Class, not the instance's real Class.
In your code for(WordCategories.Noun n: nouns) {, n's declare Class is Noun,so whatever n's real Class is,n.TYPE will only be null.
So, either use directly Class to access static fields, or use non-static field or method. Your usage is not wise, you should just take a different way.
Maybe you just need a non-static method:
public String getType() {
return TYPE;
}

How do I make variables in a Main accessible to other classes?

For example I have a MovieDatabase class that contains a list of Movie objects. In my main code, I initialize all the objects in the MovieDatabase. However I wish to call this MovieDatabase in another class to access the library. How would I do this?
Do I add in get methods in my main code and return it? Or is there another way (eg. changing the list of objects to protected/public?)
Thanks!
Code's supposed to be 3 seperate classes, Main, MovieDatabase & Movie.
An instance of movieDatabase is initialized in Main. Upon construction, it calls loadMovieList() and populates the list from a text file. However I wish to call the same instantiation of movieDatabase from another class in order to access the movies, so that I do not have to repeat the loading.
public class Main {
public static void main(String[] args) {
MovieDatabase movieDatabase = new MovieDatabase();
}
public class MovieDatabase {
ArrayList<Movie>movieList = new ArrayList<Movie>();
String fileAddress = "D:/Users/Mine/School/Java/CZ2002_Assignment/src/MovieDatabase/movieDatabase.txt";
public MovieDatabase()
{
numOfMovie=0;
loadMovieList();
}
public int getNumOfMovie() {
return numOfMovie;
}
public void addMovieToList(Movie movie) {
movieList.add(movie);
numOfMovie++;
}
public Movie selMovieByID(int movieID) {
int index=-1;
for (Movie m : movieList) {
index++;
if (m.getMovieID() == movieID)
break;
}
return selMovieByIndex(index);
}
public Movie selMovieByIndex(int index) {
return movieList.get(index);
}
public void loadMovieList()
{
//loads through text file
addMovieToList(new Movie(tempMovie));
System.out.println("Movie Database loaded");
}
public class Movie{
private int movieID;
private String movieName;
private int movieDuration; //in minutes;
private String movieRating; //G; PG; PG13; NC16; M18; R21;
private boolean has3D;
private boolean status;
}
If you have a class that depends on a NameLibrary, you should inject it via the constructor or a set method.
Firstly, its difficult to assess what issues you truly have without any code to show us.
However you mention main method, as in
public static void main(String args[]){};
this main method is designed specifically to run the application, your compiler needs that specific method, it is not designed to be used as an accessor method
e.g.
public int getValue(){
return value;}
this is not the only reason you can't access the main method variable. main doesn't have a return type (due to the use of void) plus the idea of SCOPE (each method has a scope, any method that contains a variable can see that variable, but nothing outside of it can directly see it without a return type) you use scope to limit what can be accessed or what cannot be accessed outside of the methods or classes (thats why class variables usually will have private, in order to limit accessibility)
Create a getter-method which returns the list inside your NameLibrary. if your other class extends from NameLibrary you can call this getter-method with the object reference to your NameLibrary class.
If you want int x to be accessible from other classes, you write:
public class myClass{
public int x = 0;
}
To access it from other classes, you simply write:
myClass.x ... (do something)

Change value from another form java

I have a main form (RandomSend) and another form called (_user)
in the randomsend form I declare a public static variable:
public class RandomSend extends javax.swing.JFrame {
......
public static String userGender; // this variable I want to change from another form (_user)
....
}
and in the RandomSend class I declared _user instance that try to change userGender value
_user setGender = new _user();
setGender.setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE);
setGender.setAlwaysOnTop(true);
setGender.setVisible(true);
In the _user form (class) I trying to change userGender vale:
public class _user extends javax.swing.JFrame {......
....
RandomSend.userGender="male";
....}
when I check the value from within _user , the value of RandomSend.userGender is "male"
but from my main form the value is null...
new new
My attempt According to answer number 1
public class RandomSend extends javax.swing.JFrame {
/**
*
*/
private static String userGender;
.....
.....
// show dialogbox to select gender...
_user setGender = new _user();
setGender.setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE);
setGender.setAlwaysOnTop(true);
setGender.setVisible(true);
....
....
// setter
public static void setUserGender(String gender)
{
if(gender.toLowerCase().equals("female") ||gender.toLowerCase().equals("male"))
userGender = gender;
else userGender= "Unknown!!";
}
//getter
public static String getUserGender()
{
return userGender;
}
and in the other class (frame) :
public class _user extends javax.swing.JFrame {
....
....
RandomSend.setUserGender("male");
..
..
..
}
but the Randomsend.userGender doesn't change!
You make changes to an objects member values via the use of getter and setter functions that you define on that object. To use your example you'd end up with something like:
public class RandomSend extend javax.swing.JFrame {
// This should be preferred for values that can mutate (non-final) to prevent
// modification without the owning class being alerted the value is changing
private static String userGender;
public static void setUserGender(String value) {
userGender = value;
}
public static String getUserGender() {
return userGender;
}
}
Using this example you would change the value by calling RandomSend.setUserGender("male") and you would read this value by calling RandomSend.getUserGender().
Some Additional Notes
I just wanted to point out some additional things that I noticed about your sample. Using static values in the manner that you are is not necessarily the best idea. You're locking the use of the class down in the wrong way. You should maintain an instance of a User class or some other kind of class that manages information specific to a user, such as gender. By managing an instance instead of static values on a class you're making it easier for you to handle other users within the application if that need ever rose up. If you are sure you never need to support more than the current user, then you can still use instances but implement it with a singleton pattern.
That would look something like:
public class SingletonExample {
private static SingletonExample instance = null;
// Declared private to prevent new SingletonExample
// outside of this class
private SingletonExample {}
public static SingletonExample getInstance() {
if (instance == null) {
instance = new SingletonExample();
}
return instance;
}
}
You would use this class by fetching an instance like SingletonExample.getInstance() and then operate on that instance. Using this methods guarantees that in all points in your project you're accessing the same instance of the same object making "global" in a sense.
Another note I would like to make is try and use final values or better yet, an enum instead of strings for things like gender which you will most likely use as values. I say this because in order to properly compare genders you have to do:
if (RandomSend.userGender.equals("male")) {
// ...
}
If you instead created a Gender class with constants like:
public Gender {
public static final int MALE = 1;
public static final int FEMALE = 2;
}
And comparisons (provided value changes in the proper classes)
if (RandomSend.userGender == Gender.MALE) {
// ...
}
And no more wasted string literals being passed around. This is such a good idea that Java has an entire construct unique to providing this solution called enums. You would define a Gender enum like so:
public enum Gender {
MALE,
FEMALE;
}
And then you declare you userGender as a Gender value and your comparisons are the same as if you built the enum yourself from a class with constant values. These changes can, in the long run, make your projects more manageable and easier to maintain.

Determine which subclass to choose by accessing static variables from the Class object

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.

Categories