Alternative way to create a java enum? - java

I have the following code that I am trying to understand:
public class A {
enum Size {S, M, L };
Size size = Size.M;
}
I understand the first enum line is creating an enum with three values but what is the second line doing? What will the variable size hold and is this another way to construct an enum?

The second line is just giving to the field size (of type Size) of the instance of class A the initial value Size.M.
You may be a little disturbed here by the fact that the enum is created inside the class A, it could have been in another file (but it's perfectly OK to put it inside the class A if it's used only there).
EDIT (not really part of the answer) : here's a (not pretty) exemple of enum declaration so that you can better understand the form of an enum declaration :
public enum QueryError {
no_request("no_request", "No request in client call"),
no_alias_requested("no_alias_requested", "no alias requested"),
session_not_found("session_not_found", "wrong session id"),
synosteelQuery_not_found("sxxx_not_found", "sxxx not found");
public JsonpServerResponse.Error error;
private QueryError(String type, String details) {
this.error = new JsonpServerResponse.Error();
this.error.type = type;
this.error.detail = details;
}
}

The second like is declaring a package private member variable of type Size in your class A and initializing it to point to Size.M.

An enum is a type (just as a class is a type). The second line is creating an instance variable called size, which has a type of Size (since an enum is a type). Then it's initializing the value of that instance variable to an instance of the enum Size (specifically, the Size.M instance).

Related

Casting a String to another type as a parameter of a method in Java reflection

I am trying to pass a value to a method by means of reflection in Java.
Namely, say we have string
String value = (some string representation of a value of type Type);
Say, we have a class with no-args-contructor, a single field int field and a single method, a setter method setTheField:
public class SomeClass{
private SomeType field;
SomeClass(){};
public void setTheField(SomeType parameter){
this.field = parameter
}
}
where SomeType of field may be primitive, wrapper or LocalDate / LocalDateTime.
If I take the setter (say):
Method setter = SomeClass.getClass().getDeclaredMethods()[0];
and then find out its parameters (say):
parametersList = Arrays.stream(setter.getParameters())
.collect(Collectors.toList());
Then if check if the setter requires a single parameter:
if (parametersList.size() != 1) {
throw new IllegalArgumentException("Setter named = " +
setter.getName() +
" is not a single parameter setter!");
}
What I really want to do then, is to pass string to 'setter' on some object SomeClass object = new SomeClass(); as setter.invoke(object, value); and I need somehow to cats String value to SomeType but I can not figure out how to do it uniformly.
Though, it seems a standard situation to appear and I hope someone more enlightened then me in Java can quickly figure out what to do.
Any suggestions are welcome.
Addendum:
I elaborate some more here.
The task I am trying to do is the following. Suppose I have an annotations #Column{String name} targeted to methods (or fields). Suppose I also have some domain class SomeClass with some setters (fields) annotated as #Column. I have to read from CSV top row with column names (headers to link data to the annotation's name), then I have to return a list of objects of my domain class SomeClass. This is the reason I am using reflection and I see no other way around.
Without more context this looks like a design problem. Why go through all the work to grab a setter by reflection and given a String, get a value compatible with the setter argument's type? If there's no other way around this problem, it is not possible to just cast a String to some other type. One possibility is making a factory class.
Assumption: the setter's argument type is some class called MyType.
class ArgumentFactory {
MyType valueFor(String in) {
// based on the string's value, put the conversion logic here
if (in == null || in.isEmpty()) {
return new MyType();
}
// add other cases as necessary ...
}
}
Then you have
ArgumentFactory factory = new ArgumentFactory();
// ...
String value = "qwerty";
setter.invoke(object, argumentFactory.valueFor(value));

Class registration using reflection

I'm learning about Factory Pattern and I am using THIS article as a source. In it, there is this piece of code:
class ProductFactory {
private HashMap m_RegisteredProducts = new HashMap();
public void registerProduct (String productID, Class productClass) {
m_RegisteredProducts.put(productID, productClass);
}
public Product createProduct(String productID) {
Class productClass = (Class)m_RegisteredProducts.get(productID);
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
}
I'm having a hard time figuring out how createProduct() method works. When I'm trying to use this code I get Non-static method `getDeclaredConstructor(java.lang.Class<?>...)' cannot be referenced from a static context error. productClass variable is declared but never used so there is clearly something wrong with the code but I can't figure what exactly. I checked similar questions on SO but don't know how to repurpose them for this case. Reflection is a really confusing subject for me.
My questions:
What is wrong with this code?
Why it is passing new Class[] { String.class } in getDeclaredConstrutor() method and what does it mean?
Why is it passing Object array in newInstance() instead of just single object?
Question 1
There are several things wrong about this code.
It just does not compile because cClass member is missing. Logically, It should be productClass.getDeclaredConstructor instead.
Raw HashMap is used instead of generically typed Map<String, Class<? extends Product>>. Also raw typing for Class and Constructor.
The naming m_RegisteredProducts does not respect Java naming conventions.
Question 2
new Class[] { String.class } arg aims to retrieve the constructor with a single String arg, for example public Product(String id).
It could have been retrieved with just
productClass.getDeclaredConstructor(String.class);
because it is not mandatory to create arrays for varargs.
Question 3
This array arg just looks like a blunder. The constructor instance is retrieved for one with String arg, but it is passing something else to instantiate it. So inevitably there will be an exception thrown.
Conclusion
There are too many wrong or inaccurate things in this example and probably in the article itself. I'd recommend choosing another one.

I don't understand this common java principle [duplicate]

This question already has answers here:
How to instantiate an object in java?
(7 answers)
Closed 5 years ago.
Currently I'm following java course and I am struggling with a part of the code which I see used a lot in methods. So here goes:
Answer answer = new Answer("something");
I have a class named Answer and I think the first Answer is in reference to that. the lower cased answer is the variable. It's after the = sign I'm struggling to comprehend. any help please?
This declares a variable answer of type Answer and initializes it with a new object instance of class Answer by calling the Answer(String) constructor.
Consider Apollo's comment and google it.
This is not only a java principle but a generall programming principle.
You're creating a new Answer Object.
Let's look at this example:
public class Answer{ // The class
private String answer; // internal variable only visible for the class
public Answer(String answer){ // This is a constructor
this.answer = answer; // Here we assign the String we gave this object to an internal variable
}
public void setAnswer(String answer){ // Setter
this.answer = answer;
}
public String getAnswer(){ // Getter
return answer;
}
}
So now you have a class/Object named Answer.
When you now want to use it you need to create a new Object.
This is done over the constructor of a class. ( Constructor = basically a definition of what you need to create the Object )
First you declare what Object you want your variable to be, then you give the variable a name you can use it under.
That looks like this:
Answer variableName
But this will not create a new object.
To create it we need to give the keyword new in combination of a Constructor of the object we want to create.
As we defined a constructor that needs a String to create this object we need to call it like this:
new Answer("the string");
If we combine those two we finally have our usable new variable of a new create Answer
Answer yourVariable = new Answer("the string");
Any declaration in Java follows the following rules:
[variable type] [variable name] = [value];
So in your case:
variable type = object of type Answer
variable name = answer
value = new Answer("something")
What you're doing with new Answer("something") is that you're creating a new object of type Answer using the constructor that accepts a single String
Notice that the value is optional. You can just declare any value and assign a value after that
This is a pretty basic concept in Java.
Once we define a Java class, we can create objects of such class. To do so, we need to call a special method in the class, called constructor, with the reserved keyword new. Additionally, we want to store a reference to the newly created object in a variable, so that we can use it later.
To do so, we first declare a variable of the type of the class:
MyClass myVariable;
And then create an object and assign it to the variable:
myVariable = new MyClass();
In your case, the constructor receives one parameter of type String for initializing the object.

Java Array list stack

This is the top portion of my ArrayListStack class. I am trying to make values become an array list of T of 10. I am getting an error "incompatible types required: ArrayListStack found:java.util.ArrayList". In the line values = new ArrayList(10)". How would i properly set this value thanks
import java.util.ArrayList;
public class ArrayListStack<T> implements StackInterface<T>
{
private ArrayListStack<Integer> values= new ArrayListStack<Integer>();
private int size;
public ArrayListStack()
{
size = 0;
values = new ArrayList<T>(10);
}
I think you are attempting to use an ArrayList to back your ArrayListStack. It makes no sense for an ArrayListStack to contain another ArrayListStack. If this were to compile, each new ArrayListStack would create another ArrayListStack, which would create another ArrayListStack, etc.
Change the type of your values to ArrayList, and use your T generic type parameter:
private ArrayList<T> values;
No need to initialize it here; you are initializing it in the constructor.
There are multiple errors here:
you declare values as an ArrayListStack while it should be an ArrayList
you declare values by specifying the type parameter to Integer while it should stay T
you initialize values outside the constructor to inizialize it again inside the constructor
you try to initialize values to a different type, with a different type parameter
It should be
private ArrayList<T> values;
ArrayStackList() {
value = new ArrayList<T>(10);
}
You are assigning a generic type to an array list of Integer objects. Furthermore you are already initializing the list in your class definition.
public class ArrayListStack<T> implements StackInterface<T>
{
private ArrayList<T> values; // <-- Note change here
private int size;
public ArrayListStack()
{
size = 0;
values = new ArrayList<T>(10);
}
}
You need to have the same type and generic type for values when you construct it and when you declare it. T is your generic type (a generic generic type, if you will). I also removed the superfluous initialization at the field declaration, since you're re-constructing it in the constructor.
If you're trying to make a class that combines the functionality of ArrayList and StackInterface, make the following changes. Otherwise your code doesn't seem to make much sense
import java.util.ArrayList;
public class ArrayListStack<T> extends ArrayList<T> implements StackInterface<T>
{
public ArrayListStack()
{
//You can set this to whatever initial size you like,
//however if you look at the source code of ArrayList
//you'll discover that 10 is the default size of an ArrayList
super(10);
}
//Add whatever methods are required by StackInterface
}
In this situation, you can seamlessly use your class as both a standard ArrayList and a StackInterface

Java Enum types not being recognized by my methods

Currently developing a code smell detector for a uni assignment. I have made an abstract CodeSmell class, with two concrete subclasses - ClassLevelSmell and MethodLevelSmell. The CodeSmell class has a protected field of type SmellType. A sample constructor is as follows:
public ClassLevelSmell(ClassDefinition classDef, SmellType type){
smellyClass = classDef;
this.smell = type;
}
SmellType is an enum I defined, which looks like this:
public enum SmellType {
LONG_CLASS, LONG_METHOD, PRIMITIVE_OBSESSION, LONG_PARAM_LIST}
I then have a SmellDetector object, with numerous methods that compare the statistics of analyzed classes and methods (such as their number of lines, number of primitive declarations etc) and creates a new CodeSmell object if a smell is found. So my code for this looks like this:
private void detectLongClass(ClassDefinition classDef) {
if(classDef.getNumLines() > 250){
smells.add(new ClassLevelSmell(classDef, LONG_CLASS));
}
}
Each SmellDetector object has a field smells, an ArrayList of CodeSmells. However, I'm getting a compiler warning in eclipse when I try to pass the SmellType LONG_CLASS into the constructor for the ClassLevelMethod, telling me "LONG_CLASS cannot be resolved to a variable". Am I making some mistake with the use of Enumerated types? What do?
To reference enum values you either need to use the qualified form with the class name or use static imports. So either make it:
smells.add(new ClassLevelSmell(classDef, SmellType.LONG_CLASS));
or do this:
// at the top of your file:
import static packagename.SmellType.*;
smells.add(new ClassLevelSmell(classDef, LONG_CLASS));
Try this:
smells.add(new ClassLevelSmell(classDef, SmellType.LONG_CLASS));

Categories

Resources